aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.classpath32
-rw-r--r--.gitignore2
-rw-r--r--.project31
-rw-r--r--.settings/org.eclipse.core.resources.prefs2
-rw-r--r--.settings/org.eclipse.core.runtime.prefs2
-rw-r--r--.settings/org.eclipse.jdt.core.prefs291
-rw-r--r--.settings/org.eclipse.jdt.ui.prefs58
-rw-r--r--.settings/org.eclipse.wst.validation.prefs10
-rw-r--r--README.md100
-rw-r--r--WebContent/VAADIN/jquery-1.7.2.js9404
-rw-r--r--WebContent/VAADIN/jquery.atmosphere.js2731
-rw-r--r--WebContent/VAADIN/themes/base/base.scss2
-rw-r--r--WebContent/VAADIN/themes/base/calendar/calendar.scss378
-rw-r--r--WebContent/VAADIN/themes/base/calendar/img/arrows.pngbin0 -> 248 bytes
-rw-r--r--WebContent/VAADIN/themes/base/common/common.scss15
-rw-r--r--WebContent/VAADIN/themes/base/datefield/datefield.scss13
-rw-r--r--WebContent/VAADIN/themes/base/debug/debug.scss217
-rw-r--r--WebContent/VAADIN/themes/base/debug/fonts/font.dev.svg39
-rw-r--r--WebContent/VAADIN/themes/base/debug/fonts/font.eotbin0 -> 6124 bytes
-rw-r--r--WebContent/VAADIN/themes/base/debug/fonts/font.svg39
-rw-r--r--WebContent/VAADIN/themes/base/debug/fonts/font.ttfbin0 -> 5944 bytes
-rw-r--r--WebContent/VAADIN/themes/base/debug/fonts/font.woffbin0 -> 3336 bytes
-rw-r--r--WebContent/VAADIN/themes/base/window/window.scss27
-rw-r--r--WebContent/VAADIN/themes/chameleon/components/window/window.scss34
-rw-r--r--WebContent/VAADIN/themes/chameleon/img/maximize.pngbin0 -> 1207 bytes
-rw-r--r--WebContent/VAADIN/themes/chameleon/img/restore.pngbin0 -> 1200 bytes
-rw-r--r--WebContent/VAADIN/themes/liferay/window/maximize_sprites.pngbin0 -> 1291 bytes
-rw-r--r--WebContent/VAADIN/themes/liferay/window/restore_sprites.pngbin0 -> 1441 bytes
-rw-r--r--WebContent/VAADIN/themes/liferay/window/window.scss28
-rw-r--r--WebContent/VAADIN/themes/reindeer/notification/notification.scss4
-rw-r--r--WebContent/VAADIN/themes/reindeer/panel/panel.scss36
-rw-r--r--WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.scss12
-rw-r--r--WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.scss4
-rw-r--r--WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.scss7
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/close-active.pngbin0 -> 359 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/close-hover.pngbin0 -> 369 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/close.pngbin0 -> 318 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/maximize-active.pngbin0 -> 245 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/maximize-hover.pngbin0 -> 245 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/maximize.pngbin0 -> 185 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/restore-active.pngbin0 -> 295 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/restore-hover.pngbin0 -> 296 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/black/restore.pngbin0 -> 249 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/close-hover.png (renamed from WebContent/VAADIN/themes/reindeer/window/img/close-light-hover.png)bin600 -> 600 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/close-pressed.png (renamed from WebContent/VAADIN/themes/reindeer/window/img/close-light-pressed.png)bin631 -> 631 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/close.png (renamed from WebContent/VAADIN/themes/reindeer/window/img/close-light.png)bin549 -> 549 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/content-bg.png (renamed from WebContent/VAADIN/themes/reindeer/window/img/content-bg-light.png)bin208 -> 208 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/maximize-active.pngbin0 -> 268 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/maximize-hover.pngbin0 -> 271 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/maximize.pngbin0 -> 271 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/resize.png (renamed from WebContent/VAADIN/themes/reindeer/window/img/resize-light.png)bin222 -> 222 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/restore-active.pngbin0 -> 360 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/restore-hover.pngbin0 -> 366 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/light/restore.pngbin0 -> 366 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/maximize.pngbin0 -> 270 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/img/restore.pngbin0 -> 328 bytes
-rw-r--r--WebContent/VAADIN/themes/reindeer/window/window.scss272
-rw-r--r--WebContent/VAADIN/themes/runo/tabsheet/tabsheet.scss3
-rw-r--r--WebContent/VAADIN/themes/runo/window/img/maximize.pngbin0 -> 388 bytes
-rw-r--r--WebContent/VAADIN/themes/runo/window/img/restore.pngbin0 -> 569 bytes
-rw-r--r--WebContent/VAADIN/themes/runo/window/window.scss41
-rw-r--r--WebContent/VAADIN/themes/tests-calendar/styles.css96
-rw-r--r--WebContent/VAADIN/vaadinBootstrap.js21
-rw-r--r--WebContent/VAADIN/vaadinPush.js.tpl8
-rw-r--r--WebContent/WEB-INF/web.xml27
-rw-r--r--WebContent/WEB-INF/web.xml.2.4131
-rw-r--r--WebContent/license.html21
-rw-r--r--WebContent/licenses/common-development-and-distribution-license-v1-0.txt384
-rw-r--r--WebContent/release-notes.html367
-rw-r--r--all/build.xml2
-rw-r--r--all/ivy.xml2
-rw-r--r--build.xml7
-rwxr-xr-xbuild/ide.xml79
-rwxr-xr-xbuild/ivy-ide.xml23
-rw-r--r--buildhelpers/build.xml4
-rw-r--r--buildhelpers/ivy.xml4
-rw-r--r--client-compiled/build.xml5
-rw-r--r--client-compiler/build.xml4
-rw-r--r--client-compiler/ivy.xml103
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java16
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java34
-rw-r--r--client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java19
-rw-r--r--client/build.xml6
-rw-r--r--client/ivy.xml8
-rw-r--r--client/src/com/vaadin/Vaadin.gwt.xml16
-rw-r--r--client/src/com/vaadin/client/ApplicationConfiguration.java90
-rw-r--r--client/src/com/vaadin/client/ApplicationConnection.java515
-rw-r--r--client/src/com/vaadin/client/BrowserInfo.java10
-rw-r--r--client/src/com/vaadin/client/ComponentConnector.java19
-rw-r--r--client/src/com/vaadin/client/ComponentLocator.java13
-rw-r--r--client/src/com/vaadin/client/ConnectorHierarchyChangeEvent.java10
-rw-r--r--client/src/com/vaadin/client/Console.java44
-rw-r--r--client/src/com/vaadin/client/HasComponentsConnector.java1
-rw-r--r--client/src/com/vaadin/client/NullConsole.java74
-rw-r--r--client/src/com/vaadin/client/Profiler.java27
-rw-r--r--client/src/com/vaadin/client/SimpleTree.java36
-rw-r--r--client/src/com/vaadin/client/Util.java29
-rw-r--r--client/src/com/vaadin/client/VCaption.java32
-rw-r--r--client/src/com/vaadin/client/VConsole.java77
-rw-r--r--client/src/com/vaadin/client/VDebugConsole.java1041
-rw-r--r--client/src/com/vaadin/client/VErrorMessage.java3
-rw-r--r--client/src/com/vaadin/client/VLoadingIndicator.java292
-rw-r--r--client/src/com/vaadin/client/VTooltip.java268
-rw-r--r--client/src/com/vaadin/client/VUIDLBrowser.java6
-rw-r--r--client/src/com/vaadin/client/ValueMap.java4
-rw-r--r--client/src/com/vaadin/client/communication/AtmospherePushConnection.java453
-rw-r--r--client/src/com/vaadin/client/communication/PushConnection.java91
-rw-r--r--client/src/com/vaadin/client/debug/internal/DebugButton.java109
-rw-r--r--client/src/com/vaadin/client/debug/internal/ErrorNotificationHandler.java86
-rw-r--r--client/src/com/vaadin/client/debug/internal/HierarchySection.java676
-rw-r--r--client/src/com/vaadin/client/debug/internal/Highlight.java210
-rw-r--r--client/src/com/vaadin/client/debug/internal/Icon.java62
-rw-r--r--client/src/com/vaadin/client/debug/internal/LogSection.java355
-rw-r--r--client/src/com/vaadin/client/debug/internal/NetworkSection.java97
-rw-r--r--client/src/com/vaadin/client/debug/internal/Section.java76
-rw-r--r--client/src/com/vaadin/client/debug/internal/VDebugWindow.java1062
-rw-r--r--client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java2
-rw-r--r--client/src/com/vaadin/client/metadata/Property.java25
-rw-r--r--client/src/com/vaadin/client/metadata/TypeDataStore.java19
-rw-r--r--client/src/com/vaadin/client/ui/AbstractClickEventHandler.java5
-rw-r--r--client/src/com/vaadin/client/ui/AbstractComponentConnector.java42
-rw-r--r--client/src/com/vaadin/client/ui/AbstractConnector.java1
-rw-r--r--client/src/com/vaadin/client/ui/AbstractHasComponentsConnector.java2
-rw-r--r--client/src/com/vaadin/client/ui/VAbsoluteLayout.java104
-rw-r--r--client/src/com/vaadin/client/ui/VButton.java12
-rw-r--r--client/src/com/vaadin/client/ui/VCalendar.java1446
-rw-r--r--client/src/com/vaadin/client/ui/VCalendarPanel.java501
-rw-r--r--client/src/com/vaadin/client/ui/VCheckBox.java24
-rw-r--r--client/src/com/vaadin/client/ui/VColorPickerArea.java1
-rw-r--r--client/src/com/vaadin/client/ui/VContextMenu.java38
-rw-r--r--client/src/com/vaadin/client/ui/VFilterSelect.java35
-rw-r--r--client/src/com/vaadin/client/ui/VFormLayout.java22
-rw-r--r--client/src/com/vaadin/client/ui/VLabel.java3
-rw-r--r--client/src/com/vaadin/client/ui/VNativeButton.java6
-rw-r--r--client/src/com/vaadin/client/ui/VOptionGroup.java8
-rw-r--r--client/src/com/vaadin/client/ui/VOptionGroupBase.java2
-rw-r--r--client/src/com/vaadin/client/ui/VPopupCalendar.java189
-rw-r--r--client/src/com/vaadin/client/ui/VPopupView.java29
-rw-r--r--client/src/com/vaadin/client/ui/VTextualDate.java35
-rw-r--r--client/src/com/vaadin/client/ui/VTree.java61
-rw-r--r--client/src/com/vaadin/client/ui/VWindow.java98
-rw-r--r--client/src/com/vaadin/client/ui/absolutelayout/AbsoluteLayoutConnector.java5
-rw-r--r--client/src/com/vaadin/client/ui/aria/AriaHelper.java188
-rw-r--r--client/src/com/vaadin/client/ui/aria/HandlesAriaCaption.java39
-rw-r--r--client/src/com/vaadin/client/ui/aria/HandlesAriaInvalid.java33
-rw-r--r--client/src/com/vaadin/client/ui/aria/HandlesAriaRequired.java32
-rw-r--r--client/src/com/vaadin/client/ui/button/ButtonConnector.java7
-rw-r--r--client/src/com/vaadin/client/ui/calendar/CalendarConnector.java662
-rw-r--r--client/src/com/vaadin/client/ui/calendar/VCalendarAction.java138
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java55
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/CalendarEvent.java313
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateCell.java810
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateCellContainer.java117
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java639
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateCellGroup.java59
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DateUtil.java70
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/DayToolbar.java181
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/FocusableComplexPanel.java122
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/FocusableGrid.java134
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/FocusableHTML.java124
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/HasTooltipKey.java33
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java142
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/MonthGrid.java216
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java701
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayToolbar.java97
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/SimpleWeekToolbar.java109
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/WeekGrid.java678
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/WeekGridMinuteTimeRange.java62
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/WeekLabel.java51
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java185
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEventsDateCell.java67
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java65
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java167
-rw-r--r--client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java182
-rw-r--r--client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java5
-rw-r--r--client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java2
-rw-r--r--client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java4
-rw-r--r--client/src/com/vaadin/client/ui/form/FormConnector.java5
-rw-r--r--client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java9
-rw-r--r--client/src/com/vaadin/client/ui/menubar/MenuBarConnector.java10
-rw-r--r--client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java5
-rw-r--r--client/src/com/vaadin/client/ui/orderedlayout/Slot.java6
-rw-r--r--client/src/com/vaadin/client/ui/table/TableConnector.java10
-rw-r--r--client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java10
-rw-r--r--client/src/com/vaadin/client/ui/tree/TreeConnector.java52
-rw-r--r--client/src/com/vaadin/client/ui/ui/UIConnector.java178
-rw-r--r--client/src/com/vaadin/client/ui/window/WindowConnector.java288
-rw-r--r--common.xml41
-rw-r--r--eclipse/Development Mode (vaadin).launch38
-rw-r--r--eclipse/Development Server (vaadin).launch12
-rw-r--r--gwt-files.xml76
-rw-r--r--ivy.xml22
-rw-r--r--ivysettings.xml4
-rw-r--r--push/build.xml74
-rw-r--r--push/ivy.xml37
-rw-r--r--push/src/org/atmosphere/cpr/AtmosphereFramework.java1779
-rwxr-xr-xscripts/automerge7.sh131
-rw-r--r--server/build.xml6
-rw-r--r--server/ivy.xml40
-rw-r--r--server/src/com/vaadin/annotations/Push.java49
-rw-r--r--server/src/com/vaadin/data/Container.java9
-rw-r--r--server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java37
-rw-r--r--server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java26
-rw-r--r--server/src/com/vaadin/data/fieldgroup/FieldGroup.java94
-rw-r--r--server/src/com/vaadin/data/util/AbstractBeanContainer.java20
-rw-r--r--server/src/com/vaadin/data/util/AbstractInMemoryContainer.java19
-rw-r--r--server/src/com/vaadin/data/util/AbstractProperty.java37
-rw-r--r--server/src/com/vaadin/data/util/IndexedContainer.java57
-rw-r--r--server/src/com/vaadin/data/util/LegacyPropertyHelper.java102
-rw-r--r--server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java37
-rw-r--r--server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java22
-rw-r--r--server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java200
-rw-r--r--server/src/com/vaadin/server/AbstractClientConnector.java24
-rw-r--r--server/src/com/vaadin/server/AbstractCommunicationManager.java2881
-rw-r--r--server/src/com/vaadin/server/BootstrapHandler.java72
-rw-r--r--server/src/com/vaadin/server/BrowserWindowOpener.java3
-rw-r--r--server/src/com/vaadin/server/ClientConnector.java10
-rw-r--r--server/src/com/vaadin/server/CommunicationManager.java93
-rw-r--r--server/src/com/vaadin/server/ComponentSizeValidator.java4
-rw-r--r--server/src/com/vaadin/server/ConnectorResource.java9
-rw-r--r--server/src/com/vaadin/server/ConnectorResourceHandler.java49
-rw-r--r--server/src/com/vaadin/server/Constants.java58
-rw-r--r--server/src/com/vaadin/server/DefaultDeploymentConfiguration.java63
-rw-r--r--server/src/com/vaadin/server/DeploymentConfiguration.java37
-rw-r--r--server/src/com/vaadin/server/DownloadStream.java5
-rw-r--r--server/src/com/vaadin/server/DragAndDropService.java10
-rw-r--r--server/src/com/vaadin/server/FileDownloader.java23
-rw-r--r--server/src/com/vaadin/server/GAEVaadinServlet.java40
-rw-r--r--server/src/com/vaadin/server/GlobalResourceHandler.java53
-rw-r--r--server/src/com/vaadin/server/JsonCodec.java4
-rw-r--r--server/src/com/vaadin/server/JsonPaintTarget.java12
-rw-r--r--server/src/com/vaadin/server/LegacyCommunicationManager.java498
-rw-r--r--server/src/com/vaadin/server/LegacyPaint.java2
-rw-r--r--server/src/com/vaadin/server/Page.java178
-rw-r--r--server/src/com/vaadin/server/PortletCommunicationManager.java147
-rw-r--r--server/src/com/vaadin/server/RequestHandler.java22
-rw-r--r--server/src/com/vaadin/server/RequestTimer.java55
-rw-r--r--server/src/com/vaadin/server/ServerRpcManager.java2
-rw-r--r--server/src/com/vaadin/server/ServletPortletHelper.java28
-rw-r--r--server/src/com/vaadin/server/SessionExpiredHandler.java48
-rw-r--r--server/src/com/vaadin/server/SynchronizedRequestHandler.java65
-rw-r--r--server/src/com/vaadin/server/UIProvider.java25
-rw-r--r--server/src/com/vaadin/server/UnsupportedBrowserHandler.java8
-rw-r--r--server/src/com/vaadin/server/VaadinPortlet.java350
-rw-r--r--server/src/com/vaadin/server/VaadinPortletService.java76
-rw-r--r--server/src/com/vaadin/server/VaadinService.java771
-rw-r--r--server/src/com/vaadin/server/VaadinServlet.java384
-rw-r--r--server/src/com/vaadin/server/VaadinServletService.java128
-rw-r--r--server/src/com/vaadin/server/VaadinSession.java280
-rw-r--r--server/src/com/vaadin/server/WebBrowser.java13
-rw-r--r--server/src/com/vaadin/server/communication/AbstractStreamingEvent.java (renamed from server/src/com/vaadin/server/AbstractStreamingEvent.java)2
-rw-r--r--server/src/com/vaadin/server/communication/AtmospherePushConnection.java247
-rw-r--r--server/src/com/vaadin/server/communication/ClientRpcWriter.java141
-rw-r--r--server/src/com/vaadin/server/communication/ConnectorHierarchyWriter.java81
-rw-r--r--server/src/com/vaadin/server/communication/ConnectorTypeWriter.java73
-rw-r--r--server/src/com/vaadin/server/communication/FileUploadHandler.java645
-rw-r--r--server/src/com/vaadin/server/communication/HeartbeatHandler.java90
-rw-r--r--server/src/com/vaadin/server/communication/LegacyUidlWriter.java118
-rw-r--r--server/src/com/vaadin/server/communication/LocaleWriter.java204
-rw-r--r--server/src/com/vaadin/server/communication/MetadataWriter.java148
-rw-r--r--server/src/com/vaadin/server/communication/PortletBootstrapHandler.java113
-rw-r--r--server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java82
-rw-r--r--server/src/com/vaadin/server/communication/PortletListenerNotifier.java89
-rw-r--r--server/src/com/vaadin/server/communication/PortletUIInitHandler.java63
-rw-r--r--server/src/com/vaadin/server/communication/PublishedFileHandler.java151
-rw-r--r--server/src/com/vaadin/server/communication/PushConnection.java48
-rw-r--r--server/src/com/vaadin/server/communication/PushHandler.java380
-rw-r--r--server/src/com/vaadin/server/communication/PushRequestHandler.java134
-rw-r--r--server/src/com/vaadin/server/communication/ResourceWriter.java113
-rw-r--r--server/src/com/vaadin/server/communication/ServerRpcHandler.java469
-rw-r--r--server/src/com/vaadin/server/communication/ServletBootstrapHandler.java48
-rw-r--r--server/src/com/vaadin/server/communication/ServletUIInitHandler.java (renamed from client/src/com/vaadin/client/SynchronousXHR.java)25
-rw-r--r--server/src/com/vaadin/server/communication/SessionRequestHandler.java70
-rw-r--r--server/src/com/vaadin/server/communication/SharedStateWriter.java75
-rw-r--r--server/src/com/vaadin/server/communication/StreamingEndEventImpl.java (renamed from server/src/com/vaadin/server/StreamingEndEventImpl.java)2
-rw-r--r--server/src/com/vaadin/server/communication/StreamingErrorEventImpl.java (renamed from server/src/com/vaadin/server/StreamingErrorEventImpl.java)2
-rw-r--r--server/src/com/vaadin/server/communication/StreamingProgressEventImpl.java (renamed from server/src/com/vaadin/server/StreamingProgressEventImpl.java)2
-rw-r--r--server/src/com/vaadin/server/communication/StreamingStartEventImpl.java (renamed from server/src/com/vaadin/server/StreamingStartEventImpl.java)2
-rw-r--r--server/src/com/vaadin/server/communication/UIInitHandler.java304
-rw-r--r--server/src/com/vaadin/server/communication/UidlRequestHandler.java306
-rw-r--r--server/src/com/vaadin/server/communication/UidlWriter.java317
-rw-r--r--server/src/com/vaadin/server/themeutils/SASSAddonImportFileCreator.java200
-rw-r--r--server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java (renamed from client-compiler/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java)92
-rw-r--r--server/src/com/vaadin/server/widgetsetutils/WidgetSetBuilder.java (renamed from client-compiler/src/com/vaadin/server/widgetsetutils/WidgetSetBuilder.java)0
-rw-r--r--server/src/com/vaadin/ui/AbstractColorPicker.java1
-rw-r--r--server/src/com/vaadin/ui/AbstractField.java94
-rw-r--r--server/src/com/vaadin/ui/AbstractMedia.java20
-rw-r--r--server/src/com/vaadin/ui/AbstractOrderedLayout.java29
-rw-r--r--server/src/com/vaadin/ui/Button.java30
-rw-r--r--server/src/com/vaadin/ui/Calendar.java1845
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java30
-rw-r--r--server/src/com/vaadin/ui/DateField.java177
-rw-r--r--server/src/com/vaadin/ui/GridLayout.java24
-rw-r--r--server/src/com/vaadin/ui/Label.java53
-rw-r--r--server/src/com/vaadin/ui/Layout.java17
-rw-r--r--server/src/com/vaadin/ui/LoadingIndicatorConfiguration.java160
-rw-r--r--server/src/com/vaadin/ui/LoginForm.java30
-rw-r--r--server/src/com/vaadin/ui/PopupDateField.java20
-rw-r--r--server/src/com/vaadin/ui/TooltipConfiguration.java240
-rw-r--r--server/src/com/vaadin/ui/Tree.java104
-rw-r--r--server/src/com/vaadin/ui/UI.java309
-rw-r--r--server/src/com/vaadin/ui/UIDetachedException.java42
-rw-r--r--server/src/com/vaadin/ui/Window.java146
-rw-r--r--server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java51
-rw-r--r--server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java603
-rw-r--r--server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java86
-rw-r--r--server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java80
-rw-r--r--server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java577
-rw-r--r--server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java265
-rw-r--r--server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java179
-rw-r--r--server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java42
-rw-r--r--server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java146
-rw-r--r--server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java112
-rw-r--r--server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java91
-rw-r--r--server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java79
-rw-r--r--server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java70
-rw-r--r--server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java74
-rw-r--r--server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java70
-rw-r--r--server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java77
-rw-r--r--server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java82
-rw-r--r--server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java2
-rw-r--r--server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java2
-rw-r--r--server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java8
-rw-r--r--server/src/com/vaadin/util/CurrentInstance.java106
-rw-r--r--server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java69
-rw-r--r--server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java82
-rw-r--r--server/tests/src/com/vaadin/data/util/AbstractContainerTest.java20
-rw-r--r--server/tests/src/com/vaadin/data/util/ReflectToolsGetSuperField.java11
-rwxr-xr-xserver/tests/src/com/vaadin/data/util/sqlcontainer/SQLTestsConstants.java11
-rw-r--r--server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java73
-rw-r--r--server/tests/src/com/vaadin/server/TestAbstractApplicationServletStaticFilesLocation.java6
-rw-r--r--server/tests/src/com/vaadin/server/VaadinSessionTest.java150
-rw-r--r--server/tests/src/com/vaadin/tests/data/converter/ConverterFactory.java9
-rw-r--r--server/tests/src/com/vaadin/tests/data/validator/TestStringLengthValidator.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java18
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java4
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestSimpleMultiPartInputStream.java2
-rw-r--r--server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java22
-rw-r--r--server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java4
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java9
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java5
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java4
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java210
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/calendar/ContainerDataSource.java362
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java1
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/fieldgroup/CaseInsensitiveBinding.java85
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/gridlayout/DefaultAlignment.java46
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/label/LabelConverters.java3
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/orderedlayout/DefaultAlignment.java68
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/tree/TreeTest.java8
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java3
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java3
-rw-r--r--server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java3
-rw-r--r--server/tests/src/com/vaadin/tests/server/componentcontainer/AddRemoveComponentTest.java2
-rw-r--r--server/tests/src/com/vaadin/tests/util/AlwaysLockedVaadinSession.java23
-rw-r--r--server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java111
-rw-r--r--server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java63
-rw-r--r--server/tests/src/com/vaadin/ui/LabelDataSource.java3
-rw-r--r--server/tests/src/com/vaadin/util/ReflectToolsGetFieldValueByType.java6
-rw-r--r--server/tests/src/com/vaadin/util/ReflectToolsGetPrimitiveFieldValue.java4
-rw-r--r--shared/build.xml4
-rw-r--r--shared/ivy.xml4
-rw-r--r--shared/src/com/vaadin/shared/ApplicationConstants.java18
-rw-r--r--shared/src/com/vaadin/shared/JsonConstants.java2
-rw-r--r--shared/src/com/vaadin/shared/communication/MethodInvocation.java27
-rw-r--r--shared/src/com/vaadin/shared/communication/PushMode.java66
-rw-r--r--shared/src/com/vaadin/shared/ui/button/ButtonState.java1
-rw-r--r--shared/src/com/vaadin/shared/ui/calendar/CalendarClientRpc.java28
-rw-r--r--shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java36
-rw-r--r--shared/src/com/vaadin/shared/ui/calendar/CalendarServerRpc.java49
-rw-r--r--shared/src/com/vaadin/shared/ui/calendar/CalendarState.java69
-rw-r--r--shared/src/com/vaadin/shared/ui/calendar/DateConstants.java33
-rw-r--r--shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java4
-rw-r--r--shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java4
-rw-r--r--shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java14
-rw-r--r--shared/src/com/vaadin/shared/ui/tree/TreeConstants.java2
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/PageClientRpc.java2
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/PageState.java33
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIClientRpc.java34
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java7
-rw-r--r--shared/src/com/vaadin/shared/ui/ui/UIState.java35
-rw-r--r--shared/src/com/vaadin/shared/ui/window/WindowMode.java39
-rw-r--r--shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java5
-rw-r--r--shared/src/com/vaadin/shared/ui/window/WindowState.java2
-rw-r--r--shared/src/com/vaadin/shared/util/SharedUtil.java45
-rw-r--r--theme-compiler/build.xml6
-rw-r--r--theme-compiler/ivy.xml14
-rw-r--r--theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml2
-rw-r--r--theme-compiler/src/com/vaadin/sass/SassCompiler.java5
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluator.java139
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/expression/BinaryExpression.java46
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/expression/BinaryOperator.java70
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/expression/Parentheses.java21
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/expression/exception/ArithmeticException.java26
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/expression/exception/IncompatibleUnitsException.java29
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandler.java6
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandlerImpl.java20
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/parser/LexicalUnitImpl.java85
-rwxr-xr-x[-rw-r--r--]theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java14757
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj62
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/parser/ParserConstants.java646
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/parser/ParserTokenManager.java11020
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/parser/SCSSLexicalUnit.java4
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/resolver/ClassloaderResolver.java6
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/resolver/VaadinResolver.java80
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/tree/ContentNode.java33
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/tree/MixinDefNode.java34
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/tree/MixinNode.java19
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/tree/Node.java17
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/tree/RuleNode.java17
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/tree/VariableNode.java17
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/util/DeepCopy.java10
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java9
-rw-r--r--theme-compiler/src/com/vaadin/sass/internal/visitor/MixinNodeHandler.java17
-rw-r--r--theme-compiler/tests/resources/automatic/css/basic_arithmetics.css31
-rw-r--r--theme-compiler/tests/resources/automatic/css/mixin-content-directive-with-vars.css5
-rw-r--r--theme-compiler/tests/resources/automatic/css/mixin-content-directive.css20
-rw-r--r--theme-compiler/tests/resources/automatic/scss/basic_arithmetics.scss44
-rw-r--r--theme-compiler/tests/resources/automatic/scss/mixin-content-directive-with-vars.scss9
-rw-r--r--theme-compiler/tests/resources/automatic/scss/mixin-content-directive.scss40
-rw-r--r--theme-compiler/tests/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluatorTest.java125
-rw-r--r--theme-compiler/tests/src/com/vaadin/sass/resolvers/VaadinResolverTest.java83
-rw-r--r--themes/build.xml4
-rw-r--r--uitest/build.xml10
-rw-r--r--uitest/integration-testscripts/common/integration_push_test.tpl42
-rw-r--r--uitest/integration_tests.xml37
-rw-r--r--uitest/ivy.xml19
-rw-r--r--uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java9
-rw-r--r--uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java7
-rw-r--r--uitest/src/com/vaadin/tests/applicationcontext/CloseSession.java16
-rw-r--r--uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java160
-rw-r--r--uitest/src/com/vaadin/tests/applicationcontext/RpcForClosedUI.html44
-rw-r--r--uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java24
-rw-r--r--uitest/src/com/vaadin/tests/components/button/ButtonWithShortcutNotRendered.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.html77
-rw-r--r--uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.java51
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java184
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarActions.html51
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarActionsUI.java110
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarBasicNavigation.html236
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarEventSizingNoOverlap.html110
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarMidnightEventsTest.html116
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvent.html170
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvents.html410
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarNotifications.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest1000x600px.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100percentXundefined.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100x100percent.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest300pxXundefined.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX100percent.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX300px.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedXUndefined.html41
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarTest.java1242
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarTestEvent.java48
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarVisibleHours24H.html46
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/CalendarWeeklyViewNewEvents.html657
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/HiddenFwdBackButtons.java61
-rw-r--r--uitest/src/com/vaadin/tests/components/calendar/NotificationTestUI.java104
-rw-r--r--uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRevertValueChange.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboBoxDuplicateCaption.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.java5
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java270
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html186
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html91
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html121
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html100
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html191
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html146
-rw-r--r--uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html136
-rwxr-xr-xuitest/src/com/vaadin/tests/components/orderedlayout/VerticalRelativeSizeWithoutExpand.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/page/PageReload.html46
-rw-r--r--uitest/src/com/vaadin/tests/components/page/PageReload.java34
-rw-r--r--uitest/src/com/vaadin/tests/components/popupview/ClickingWhilePopupOpen.html2
-rw-r--r--uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaEmptyString.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaPreventsTextFieldAccess.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/select/OptionGroupBaseSelects.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html69
-rw-r--r--uitest/src/com/vaadin/tests/components/table/EmptyRowsWhenScrolling.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/table/LargeSelectionCausesNPE.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndExpandRatios.java9
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableInSubWindowMemoryLeak.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java9
-rw-r--r--uitest/src/com/vaadin/tests/components/table/ViewPortCalculation.java2
-rwxr-xr-xuitest/src/com/vaadin/tests/components/tabsheet/ExtraScrollbarsInTabSheet.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/tabsheet/HiddenTabSheetBrowserResize.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java5
-rw-r--r--uitest/src/com/vaadin/tests/components/textfield/TextFieldMaxLengthRemovedFromDOM.java1
-rw-r--r--uitest/src/com/vaadin/tests/components/tree/SimpleTree.html270
-rw-r--r--uitest/src/com/vaadin/tests/components/tree/SimpleTree.java122
-rw-r--r--uitest/src/com/vaadin/tests/components/tree/TreeItemClickAndValueChange.html5
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableCacheOnPartialUpdates.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbar.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/treetable/TreeTableInternalError.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/LoadingIndicatorConfigurationTest.java96
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html145
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.java107
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UIInitException.html4
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UIPolling.html53
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UIPolling.java90
-rw-r--r--uitest/src/com/vaadin/tests/components/ui/UISerialization.java56
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java3
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html10
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html10
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html10
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html10
-rw-r--r--uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html10
-rw-r--r--uitest/src/com/vaadin/tests/components/upload/TestFileUploadSize.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/window/CenteredWindowWithUndefinedSize.java4
-rw-r--r--uitest/src/com/vaadin/tests/components/window/CloseSubWindow.html7
-rw-r--r--uitest/src/com/vaadin/tests/components/window/CloseSubWindow.java2
-rw-r--r--uitest/src/com/vaadin/tests/components/window/LegacyWindowOpenTest.java6
-rw-r--r--uitest/src/com/vaadin/tests/components/window/PageOpenTest.java6
-rw-r--r--uitest/src/com/vaadin/tests/components/window/SubWindowOrder.html6
-rw-r--r--uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html239
-rw-r--r--uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.java165
-rw-r--r--uitest/src/com/vaadin/tests/components/window/WindowWithInvalidCloseListener.html2
-rw-r--r--uitest/src/com/vaadin/tests/containers/sqlcontainer/TableQueryWithNonUniqueFirstPrimaryKey.java1
-rw-r--r--uitest/src/com/vaadin/tests/debug/DebugWindowPresent.html18
-rw-r--r--uitest/src/com/vaadin/tests/debug/HierarchyAfterAnalyzeLayouts.html15
-rw-r--r--uitest/src/com/vaadin/tests/fieldgroup/DateForm.html42
-rw-r--r--uitest/src/com/vaadin/tests/fieldgroup/DateForm.java152
-rw-r--r--uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java375
-rw-r--r--uitest/src/com/vaadin/tests/layouts/VerticalLayoutSlotExpansionAndAlignment.java1
-rw-r--r--uitest/src/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java46
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java63
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java57
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginMainView.java42
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginUI.java64
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginView.java137
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v71beta/CSSInjectWithColorpicker.java234
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7a1/AutoGeneratingForm.java2
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7b6/OpeningUIInPopup.java7
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7b9/CountView.java1
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7b9/LoginView.java1
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7b9/MainView.java1
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7b9/MainViewEarlierExample.java1
-rw-r--r--uitest/src/com/vaadin/tests/minitutorials/v7b9/SettingsView.java5
-rw-r--r--uitest/src/com/vaadin/tests/push/BasicPush.html88
-rw-r--r--uitest/src/com/vaadin/tests/push/BasicPush.java105
-rw-r--r--uitest/src/com/vaadin/tests/push/PushFromInit.html32
-rw-r--r--uitest/src/com/vaadin/tests/push/PushFromInit.java36
-rw-r--r--uitest/src/com/vaadin/tests/push/PushReattachedComponent.html47
-rw-r--r--uitest/src/com/vaadin/tests/push/RoundTripTest.java77
-rw-r--r--uitest/src/com/vaadin/tests/push/StreamingPush.html88
-rw-r--r--uitest/src/com/vaadin/tests/push/TogglePush.html91
-rw-r--r--uitest/src/com/vaadin/tests/push/TogglePush.java85
-rw-r--r--uitest/src/com/vaadin/tests/push/TogglePushInInit.html69
-rw-r--r--uitest/src/com/vaadin/tests/requesthandlers/AppResource404.html7
-rw-r--r--uitest/src/com/vaadin/tests/requesthandlers/AppResource404.java4
-rw-r--r--uitest/src/com/vaadin/tests/themes/CSSInjectTest.html57
-rw-r--r--uitest/src/com/vaadin/tests/themes/CSSInjectTest.java87
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml4
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterConnector.java106
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterRpc.java25
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java30
-rw-r--r--uitest/src/com/vaadin/tests/widgetset/server/RoundTripTester.java60
-rw-r--r--uitest/test.xml2
560 files changed, 69392 insertions, 21267 deletions
diff --git a/.classpath b/.classpath
new file mode 100644
index 0000000000..381f0d280d
--- /dev/null
+++ b/.classpath
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="server/tests/src"/>
+ <classpathentry kind="src" path="client/tests/src"/>
+ <classpathentry kind="src" path="theme-compiler/tests/src"/>
+ <classpathentry kind="src" path="theme-compiler/src"/>
+ <classpathentry kind="src" path="theme-compiler/tests/resources"/>
+ <classpathentry kind="src" path="client/src"/>
+ <classpathentry kind="src" path="server/src"/>
+ <classpathentry kind="src" path="client-compiler/src"/>
+ <classpathentry kind="src" path="uitest/src"/>
+ <classpathentry kind="src" path="buildhelpers/src"/>
+ <classpathentry kind="src" path="shared/src"/>
+ <classpathentry kind="src" path="push/src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
+ <attributes>
+ <attribute name="owner.project.facets" value="java"/>
+ </attributes>
+ </classpathentry>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=client%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=server%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=shared%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=client-compiler%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=theme-compiler%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=uitest%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry exported="true" kind="con" path="org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;ivyXmlPath=push%2Fivy.xml&amp;confs=ide&amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;loadSettingsOnDemand=false&amp;propertyFiles="/>
+ <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
+ <classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.module.container"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/gwt-dev"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/gwt-user"/>
+ <classpathentry kind="output" path="build/classes"/>
+</classpath>
diff --git a/.gitignore b/.gitignore
index d2236fafb0..d5899b3d58 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,8 @@
/WebContent/VAADIN/widgetsets
/WebContent/VAADIN/gwt-unitCache*
+WebContent/VAADIN/vaadinPush.js
+
# /WebContent/WEB-INF/
/WebContent/WEB-INF/classes
diff --git a/.project b/.project
new file mode 100644
index 0000000000..a0a79fbcec
--- /dev/null
+++ b/.project
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>vaadin</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.common.project.facet.core.builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.wst.validation.validationbuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+ <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+ <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.apache.ivyde.eclipse.ivynature</nature>
+ </natures>
+</projectDescription>
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..99f26c0203
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/.settings/org.eclipse.core.runtime.prefs b/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000000..5a0ad22d2a
--- /dev/null
+++ b/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..ecafda3a05
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,291 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=0
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
+org.eclipse.jdt.core.formatter.comment.format_block_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
+org.eclipse.jdt.core.formatter.comment.format_line_comments=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
+org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
+org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
+org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=8
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.join_lines_in_comments=true
+org.eclipse.jdt.core.formatter.join_wrapped_lines=true
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=space
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_on_off_tags=true
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
+org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
+org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
+org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
diff --git a/.settings/org.eclipse.jdt.ui.prefs b/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000..31240a63bd
--- /dev/null
+++ b/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,58 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_Vaadin Java Conventions 20110923
+formatter_settings_version=12
+org.eclipse.jdt.ui.javadoc=true
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8" standalone\="no"?><templates><template autoinsert\="true" context\="gettercomment_context" deleted\="false" description\="Comment for getter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.gettercomment" name\="gettercomment">/**\n * @return the ${bare_field_name}\n */</template><template autoinsert\="true" context\="settercomment_context" deleted\="false" description\="Comment for setter method" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.settercomment" name\="settercomment">/**\n * @param ${param} the ${bare_field_name} to set\n */</template><template autoinsert\="true" context\="constructorcomment_context" deleted\="false" description\="Comment for created constructors" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorcomment" name\="constructorcomment">/**\n * ${tags}\n */</template><template autoinsert\="false" context\="filecomment_context" deleted\="false" description\="Comment for created Java files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.filecomment" name\="filecomment">/**\n * \n */</template><template autoinsert\="false" context\="typecomment_context" deleted\="false" description\="Comment for created types" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.typecomment" name\="typecomment">/**\n * \n * @since \n * @author Vaadin Ltd\n * ${tags}\n */</template><template autoinsert\="true" context\="fieldcomment_context" deleted\="false" description\="Comment for fields" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.fieldcomment" name\="fieldcomment">/**\n * \n */</template><template autoinsert\="false" context\="methodcomment_context" deleted\="false" description\="Comment for non-overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodcomment" name\="methodcomment">/**\n * @since\n * ${tags}\n */</template><template autoinsert\="true" context\="overridecomment_context" deleted\="false" description\="Comment for overriding methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.overridecomment" name\="overridecomment">/* (non-Javadoc)\n * ${see_to_overridden}\n */</template><template autoinsert\="true" context\="delegatecomment_context" deleted\="false" description\="Comment for delegate methods" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.delegatecomment" name\="delegatecomment">/**\n * ${tags}\n * ${see_to_target}\n */</template><template autoinsert\="false" context\="newtype_context" deleted\="false" description\="Newly created files" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.newtype" name\="newtype">/*\n * Copyright 2000-2013 Vaadin Ltd.\n * \n * Licensed under the Apache License, Version 2.0 (the "License"); you may not\n * use this file except in compliance with the License. You may obtain a copy of\n * the License at\n * \n * http\://www.apache.org/licenses/LICENSE-2.0\n * \n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations under\n * the License.\n */\n\n${filecomment}\n${package_declaration}\n\n${typecomment}\n${type_declaration}</template><template autoinsert\="true" context\="classbody_context" deleted\="false" description\="Code in new class type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.classbody" name\="classbody">\n</template><template autoinsert\="true" context\="interfacebody_context" deleted\="false" description\="Code in new interface type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.interfacebody" name\="interfacebody">\n</template><template autoinsert\="true" context\="enumbody_context" deleted\="false" description\="Code in new enum type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.enumbody" name\="enumbody">\n</template><template autoinsert\="true" context\="annotationbody_context" deleted\="false" description\="Code in new annotation type bodies" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.annotationbody" name\="annotationbody">\n</template><template autoinsert\="true" context\="catchblock_context" deleted\="false" description\="Code in new catch blocks" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.catchblock" name\="catchblock">// ${todo} Auto-generated catch block\n${exception_var}.printStackTrace();</template><template autoinsert\="true" context\="methodbody_context" deleted\="false" description\="Code in created method stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.methodbody" name\="methodbody">// ${todo} Auto-generated method stub\n${body_statement}</template><template autoinsert\="true" context\="constructorbody_context" deleted\="false" description\="Code in created constructor stubs" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.constructorbody" name\="constructorbody">${body_statement}\n// ${todo} Auto-generated constructor stub</template><template autoinsert\="true" context\="getterbody_context" deleted\="false" description\="Code in created getters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.getterbody" name\="getterbody">return ${field};</template><template autoinsert\="true" context\="setterbody_context" deleted\="false" description\="Code in created setters" enabled\="true" id\="org.eclipse.jdt.ui.text.codetemplates.setterbody" name\="setterbody">${field} \= ${param};</template></templates>
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=true
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_trailing_whitespaces=true
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=true
+sp_cleanup.remove_unnecessary_nls_tags=false
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=true
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=true
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
diff --git a/.settings/org.eclipse.wst.validation.prefs b/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 0000000000..9e3833bbc9
--- /dev/null
+++ b/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,10 @@
+DELEGATES_PREFERENCE=delegateValidatorList
+USER_BUILD_PREFERENCE=enabledBuildValidatorList
+USER_MANUAL_PREFERENCE=enabledManualValidatorList
+USER_PREFERENCE=overrideGlobalPreferencestruedisableAllValidationfalseversion1.2.401.v201209052200
+eclipse.preferences.version=1
+override=true
+suspend=false
+vals/org.eclipse.wst.html.core.HTMLValidator/global=TF01
+vals/org.eclipse.wst.jsdt.web.core.JsBatchValidator/global=TF02
+vf.version=3
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..5b56333cdb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,100 @@
+Cloning the project repositories
+======
+
+Vaadin 7 consists of three separate repositories
+* https://github.com/vaadin/vaadin.git
+* https://github.com/vaadin/gwt.git
+* https://github.com/vaadin/gwt-tools.git
+
+Start by cloning these repositories into the same folder:
+<pre><code>git clone https://github.com/vaadin/vaadin.git
+git clone https://github.com/vaadin/gwt.git
+git clone https://github.com/vaadin/gwt-tools.git</code></pre>
+
+The *vaadin* and *gwt* repositories contain project code. The *gwt-tools* project only contain dependency jars used by the other projects.
+
+Do not rename the repositories as the rest of this document relies on using the standard naming.
+
+Setting up Eclipse to Develop Vaadin 7
+=========
+Assuming you have cloned the repositories as described in “Cloning the project repositories” above, you can import the *vaadin* and *gwt* projects into Eclipse as follows:
+
+Start Eclipse
+-------------
+Start Eclipse and use the root checkout folder (the one containing the *vaadin*, *gwt* and *gwt-tools* folders) as the workspace folder
+
+Define Required Variables for the GWT Eclipse Projects
+--------
+To be able to find all files, the GWT project requires you to define a couple of variables:
+
+1. Open *Window* -> *Preferences* (Windows) or *Eclipse* -> *Preferences* (Mac)
+1. Go to *General* -> *Workspace* -> *Linked Resources*
+1. Add a new Path Variable **GWT_ROOT** referring to the gwt folder containing the gwt project
+![GWT_ROOT](http://f.cl.ly/items/430q0H0z3t362Z1A1n3L/LinkedResources.png "Defining GWT_ROOT")
+1. Go to *Java* -> *Build Path* -> *Classpath Variables*
+1. Add two new variables
+ 1. GWT_TOOLS referring to the gwt-tools folder containing the dependency jars
+ 1. JDK_HOME referring to your jdk installation directory
+ ![GWT_TOOLS](http://f.cl.ly/items/1k2Z1n2v0p0y3l0X0D1G/ClasspathVars.png "Defining GWT_TOOLS")
+1. Go to Java -> Compiler
+ 1. Check that the compliance level has been set to 1.6 (or higher)
+
+Import the Projects into the Workspace
+------------
+1. Do *File* -> *Import* -> *General* -> *Existing Projects into Workspace*
+![ImportProject](http://f.cl.ly/items/0G361519182v1z2T1o1O/Import.png "Import project")
+1. Select the workspace folder as root directory
+1. Click “deselect all” and select
+ 1. gwt-dev
+ 2. gwt-user
+1. Click “finish” to complete the import of GWT
+1. Then repeat by doing *File* -> *Import* -> *General* -> *Existing Projects into Workspace*
+1. Select the workspace folder as root directory
+1. Click “deselect all” and select
+ 1. vaadin
+1. Click “finish” to complete the import of Vaadin Framework
+
+![FinishImportProject](http://cl.ly/image/2W3S0P2c2p1t/Import2.png "Finishing Project Import")
+
+You should now have three projects in your workspace. If the vaadin project does not compile without errors, choose *Ivy* -> *Resolve* from the vaadin project popup menu. Now all projects should compile without errors (there might be warnings).
+
+Note that the first compilation takes a while to finish as Ivy downloads dependencies used in the projects.
+
+Compiling the Default Widget Set and Themes
+--------
+Compile the default widget set by executing the default target in build/ide.xml in the vaadin project.
+In Eclipse this is done by opening build/ide.xml, right clicking on it and choosing *Run As* -> *Ant Build*.
+![CompileWidgetSet](http://cl.ly/image/1R43162b282e/build.png "Compiling the Widget Set")
+
+Running a UI test
+------
+The *vaadin* project includes an embedded Jetty which is used for running the UI tests.
+It is a standard Java application: *com.vaadin.launcher.DevelopmentServerLauncher*.
+Launch it in debug mode in Eclipse by right clicking on it and selecting *Debug As* -> *Java Application*.
+
+This launches a Jetty on port 8888 which allows you to run any UI class in the project by opening http://localhost:8888/run/&lt;UI class name&gt;?restartApplication in your browser, e.g. [http://localhost:8888/run/com.vaadin.tests.components.label.LabelModes?restartApplication](http://localhost:8888/run/com.vaadin.tests.components.label.LabelModes?restartApplication) (Add ?restartApplication to ensure).
+
+Running JUnit tests
+=====
+The JUnit tests for the projects can be run using
+<pre><code>ant test</code></pre>
+
+Running this in the *gwt* directory will run the GWT JUnit tests.
+Running it in the *vaadin* directory will run the Vaadin JUnit tests.
+
+Running the Vaadin TestBench tests currently requires access to a correctly configured TestBench 2 cluster, only available inside Vaadin.
+
+Building a package
+=====
+The distribution files can be built in a few steps. First build the *gwt* project by running
+<pre><code>ant</code></pre>
+in the *gwt* directory. The elemental package needs to be built separately:
+<pre><code>ant elemental</code></pre>
+Building the elemental package is not possible on Windows as it requires gcc.
+
+Move to the *vaadin* project directory and unpack the previously built gwt jars
+<pre><code>ant -f gwt-files.xml unpack.gwt</code></pre>
+Then build the *vaadin* project by running
+<pre><code>ant</code></pre>
+in the *vaadin* directory.
+
diff --git a/WebContent/VAADIN/jquery-1.7.2.js b/WebContent/VAADIN/jquery-1.7.2.js
new file mode 100644
index 0000000000..3774ff9861
--- /dev/null
+++ b/WebContent/VAADIN/jquery-1.7.2.js
@@ -0,0 +1,9404 @@
+/*!
+ * jQuery JavaScript Library v1.7.2
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Wed Mar 21 12:46:34 2012 -0700
+ */
+(function( window, undefined ) {
+
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document,
+ navigator = window.navigator,
+ location = window.location;
+var jQuery = (function() {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // A simple way to check for HTML strings or ID strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+ // Check if a string has a non-whitespace character in it
+ rnotwhite = /\S/,
+
+ // Used for trimming whitespace
+ trimLeft = /^\s+/,
+ trimRight = /\s+$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+ // Useragent RegExp
+ rwebkit = /(webkit)[ \/]([\w.]+)/,
+ ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+ rmsie = /(msie) ([\w.]+)/,
+ rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+ // Matches dashed string for camelizing
+ rdashAlpha = /-([a-z]|[0-9])/ig,
+ rmsPrefix = /^-ms-/,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return ( letter + "" ).toUpperCase();
+ },
+
+ // Keep a UserAgent string for use with jQuery.browser
+ userAgent = navigator.userAgent,
+
+ // For matching the engine and version of the browser
+ browserMatch,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // The ready event handler
+ DOMContentLoaded,
+
+ // Save a reference to some core methods
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty,
+ push = Array.prototype.push,
+ slice = Array.prototype.slice,
+ trim = String.prototype.trim,
+ indexOf = Array.prototype.indexOf,
+
+ // [[Class]] -> type pairs
+ class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), or $(undefined)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // The body element only exists once, optimize finding it
+ if ( selector === "body" && !context && document.body ) {
+ this.context = document;
+ this[0] = document.body;
+ this.selector = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ // Are we dealing with HTML string or an ID?
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = quickExpr.exec( selector );
+ }
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+ doc = ( context ? context.ownerDocument || context : document );
+
+ // If a single string is passed in and it's a single tag
+ // just do a createElement and skip the rest
+ ret = rsingleTag.exec( selector );
+
+ if ( ret ) {
+ if ( jQuery.isPlainObject( context ) ) {
+ selector = [ document.createElement( ret[1] ) ];
+ jQuery.fn.attr.call( selector, context, true );
+
+ } else {
+ selector = [ doc.createElement( ret[1] ) ];
+ }
+
+ } else {
+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+ selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $("#id")
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.7.2",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return slice.call( this, 0 );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+ // Build a new jQuery matched element set
+ var ret = this.constructor();
+
+ if ( jQuery.isArray( elems ) ) {
+ push.apply( ret, elems );
+
+ } else {
+ jQuery.merge( ret, elems );
+ }
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Attach the listeners
+ jQuery.bindReady();
+
+ // Add the callback
+ readyList.add( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ i = +i;
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ),
+ "slice", slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+ // Either a released hold or an DOMready/load event and not yet ready
+ if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.fireWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger( "ready" ).off( "ready" );
+ }
+ }
+ },
+
+ bindReady: function() {
+ if ( readyList ) {
+ return;
+ }
+
+ readyList = jQuery.Callbacks( "once memory" );
+
+ // Catch cases where $(document).ready() is called after the
+ // browser event has already occurred.
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Mozilla, Opera and webkit nightlies currently support this event
+ if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else if ( document.attachEvent ) {
+ // ensure firing before onload,
+ // maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var toplevel = false;
+
+ try {
+ toplevel = window.frameElement == null;
+ } catch(e) {}
+
+ if ( document.documentElement.doScroll && toplevel ) {
+ doScrollCheck();
+ }
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ parseJSON: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+
+ }
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+ var xml, tmp;
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && rnotwhite.test( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0,
+ length = object.length,
+ isObj = length === undefined || jQuery.isFunction( object );
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.apply( object[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( object[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return object;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: trim ?
+ function( text ) {
+ return text == null ?
+ "" :
+ trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( array, results ) {
+ var ret = results || [];
+
+ if ( array != null ) {
+ // The window, strings (and functions) also have 'length'
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ var type = jQuery.type( array );
+
+ if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+ push.call( ret, array );
+ } else {
+ jQuery.merge( ret, array );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array, i ) {
+ var len;
+
+ if ( array ) {
+ if ( indexOf ) {
+ return indexOf.call( array, elem, i );
+ }
+
+ len = array.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in array && array[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var i = first.length,
+ j = 0;
+
+ if ( typeof second.length === "number" ) {
+ for ( var l = second.length; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [], retVal;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value, key, ret = [],
+ i = 0,
+ length = elems.length,
+ // jquery objects are treated as arrays
+ isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( key in elems ) {
+ value = callback( elems[ key ], key, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ if ( typeof context === "string" ) {
+ var tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ var args = slice.call( arguments, 2 ),
+ proxy = function() {
+ return fn.apply( context, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Mutifunctional method to get and set values to a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
+ var exec,
+ bulk = key == null,
+ i = 0,
+ length = elems.length;
+
+ // Sets many values
+ if ( key && typeof key === "object" ) {
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+ }
+ chainable = 1;
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = pass === undefined && jQuery.isFunction( value );
+
+ if ( bulk ) {
+ // Bulk operations only iterate when executing function values
+ if ( exec ) {
+ exec = fn;
+ fn = function( elem, key, value ) {
+ return exec.call( jQuery( elem ), value );
+ };
+
+ // Otherwise they run against the entire set
+ } else {
+ fn.call( elems, value );
+ fn = null;
+ }
+ }
+
+ if ( fn ) {
+ for (; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+ }
+
+ chainable = 1;
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ },
+
+ // Use of jQuery.browser is frowned upon.
+ // More details: http://docs.jquery.com/Utilities/jQuery.browser
+ uaMatch: function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = rwebkit.exec( ua ) ||
+ ropera.exec( ua ) ||
+ rmsie.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+ [];
+
+ return { browser: match[1] || "", version: match[2] || "0" };
+ },
+
+ sub: function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ return jQuerySub;
+ },
+
+ browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+ jQuery.browser[ browserMatch.browser ] = true;
+ jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+ jQuery.browser.safari = true;
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+ trimLeft = /^[\s\xA0]+/;
+ trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+ DOMContentLoaded = function() {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ };
+
+} else if ( document.attachEvent ) {
+ DOMContentLoaded = function() {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( document.readyState === "complete" ) {
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+ if ( jQuery.isReady ) {
+ return;
+ }
+
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch(e) {
+ setTimeout( doScrollCheck, 1 );
+ return;
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+}
+
+return jQuery;
+
+})();
+
+
+// String to Object flags format cache
+var flagsCache = {};
+
+// Convert String-formatted flags into Object-formatted ones and store in cache
+function createFlags( flags ) {
+ var object = flagsCache[ flags ] = {},
+ i, length;
+ flags = flags.split( /\s+/ );
+ for ( i = 0, length = flags.length; i < length; i++ ) {
+ object[ flags[i] ] = true;
+ }
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * flags: an optional list of space-separated flags that will change how
+ * the callback list behaves
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible flags:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( flags ) {
+
+ // Convert flags from String-formatted to Object-formatted
+ // (we check in cache first)
+ flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
+
+ var // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = [],
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Add one or several callbacks to the list
+ add = function( args ) {
+ var i,
+ length,
+ elem,
+ type,
+ actual;
+ for ( i = 0, length = args.length; i < length; i++ ) {
+ elem = args[ i ];
+ type = jQuery.type( elem );
+ if ( type === "array" ) {
+ // Inspect recursively
+ add( elem );
+ } else if ( type === "function" ) {
+ // Add if not in unique mode and callback is not in
+ if ( !flags.unique || !self.has( elem ) ) {
+ list.push( elem );
+ }
+ }
+ }
+ },
+ // Fire callbacks
+ fire = function( context, args ) {
+ args = args || [];
+ memory = !flags.memory || [ context, args ];
+ fired = true;
+ firing = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
+ memory = true; // Mark as halted
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( !flags.once ) {
+ if ( stack && stack.length ) {
+ memory = stack.shift();
+ self.fireWith( memory[ 0 ], memory[ 1 ] );
+ }
+ } else if ( memory === true ) {
+ self.disable();
+ } else {
+ list = [];
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ var length = list.length;
+ add( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away, unless previous
+ // firing was halted (stopOnFalse)
+ } else if ( memory && memory !== true ) {
+ firingStart = length;
+ fire( memory[ 0 ], memory[ 1 ] );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ var args = arguments,
+ argIndex = 0,
+ argLength = args.length;
+ for ( ; argIndex < argLength ; argIndex++ ) {
+ for ( var i = 0; i < list.length; i++ ) {
+ if ( args[ argIndex ] === list[ i ] ) {
+ // Handle firingIndex and firingLength
+ if ( firing ) {
+ if ( i <= firingLength ) {
+ firingLength--;
+ if ( i <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ // Remove the element
+ list.splice( i--, 1 );
+ // If we have some unicity property then
+ // we only need to do this once
+ if ( flags.unique ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ if ( list ) {
+ var i = 0,
+ length = list.length;
+ for ( ; i < length; i++ ) {
+ if ( fn === list[ i ] ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory || memory === true ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( stack ) {
+ if ( firing ) {
+ if ( !flags.once ) {
+ stack.push( [ context, args ] );
+ }
+ } else if ( !( flags.once && memory ) ) {
+ fire( context, args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+
+
+var // Static reference to slice
+ sliceDeferred = [].slice;
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var doneList = jQuery.Callbacks( "once memory" ),
+ failList = jQuery.Callbacks( "once memory" ),
+ progressList = jQuery.Callbacks( "memory" ),
+ state = "pending",
+ lists = {
+ resolve: doneList,
+ reject: failList,
+ notify: progressList
+ },
+ promise = {
+ done: doneList.add,
+ fail: failList.add,
+ progress: progressList.add,
+
+ state: function() {
+ return state;
+ },
+
+ // Deprecated
+ isResolved: doneList.fired,
+ isRejected: failList.fired,
+
+ then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
+ deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
+ return this;
+ },
+ always: function() {
+ deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
+ return this;
+ },
+ pipe: function( fnDone, fnFail, fnProgress ) {
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( {
+ done: [ fnDone, "resolve" ],
+ fail: [ fnFail, "reject" ],
+ progress: [ fnProgress, "notify" ]
+ }, function( handler, data ) {
+ var fn = data[ 0 ],
+ action = data[ 1 ],
+ returned;
+ if ( jQuery.isFunction( fn ) ) {
+ deferred[ handler ](function() {
+ returned = fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+ }
+ });
+ } else {
+ deferred[ handler ]( newDefer[ action ] );
+ }
+ });
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ if ( obj == null ) {
+ obj = promise;
+ } else {
+ for ( var key in promise ) {
+ obj[ key ] = promise[ key ];
+ }
+ }
+ return obj;
+ }
+ },
+ deferred = promise.promise({}),
+ key;
+
+ for ( key in lists ) {
+ deferred[ key ] = lists[ key ].fire;
+ deferred[ key + "With" ] = lists[ key ].fireWith;
+ }
+
+ // Handle state
+ deferred.done( function() {
+ state = "resolved";
+ }, failList.disable, progressList.lock ).fail( function() {
+ state = "rejected";
+ }, doneList.disable, progressList.lock );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( firstParam ) {
+ var args = sliceDeferred.call( arguments, 0 ),
+ i = 0,
+ length = args.length,
+ pValues = new Array( length ),
+ count = length,
+ pCount = length,
+ deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+ firstParam :
+ jQuery.Deferred(),
+ promise = deferred.promise();
+ function resolveFunc( i ) {
+ return function( value ) {
+ args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ if ( !( --count ) ) {
+ deferred.resolveWith( deferred, args );
+ }
+ };
+ }
+ function progressFunc( i ) {
+ return function( value ) {
+ pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ deferred.notifyWith( promise, pValues );
+ };
+ }
+ if ( length > 1 ) {
+ for ( ; i < length; i++ ) {
+ if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
+ args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
+ } else {
+ --count;
+ }
+ }
+ if ( !count ) {
+ deferred.resolveWith( deferred, args );
+ }
+ } else if ( deferred !== firstParam ) {
+ deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+ }
+ return promise;
+ }
+});
+
+
+
+
+jQuery.support = (function() {
+
+ var support,
+ all,
+ a,
+ select,
+ opt,
+ input,
+ fragment,
+ tds,
+ events,
+ eventName,
+ i,
+ isSupported,
+ div = document.createElement( "div" ),
+ documentElement = document.documentElement;
+
+ // Preliminary tests
+ div.setAttribute("className", "t");
+ div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+ all = div.getElementsByTagName( "*" );
+ a = div.getElementsByTagName( "a" )[ 0 ];
+
+ // Can't get basic test support
+ if ( !all || !all.length || !a ) {
+ return {};
+ }
+
+ // First batch of supports tests
+ select = document.createElement( "select" );
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName( "input" )[ 0 ];
+
+ support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: ( a.getAttribute("href") === "/a" ),
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.55/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: ( input.value === "on" ),
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // Tests for enctype support on a form(#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
+ // Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
+ focusinBubbles: false,
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ pixelMargin: true
+ };
+
+ // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
+ jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+ div.attachEvent( "onclick", function() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ support.noCloneEvent = false;
+ });
+ div.cloneNode( true ).fireEvent( "onclick" );
+ }
+
+ // Check if a radio maintains its value
+ // after being appended to the DOM
+ input = document.createElement("input");
+ input.value = "t";
+ input.setAttribute("type", "radio");
+ support.radioValue = input.value === "t";
+
+ input.setAttribute("checked", "checked");
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( div.lastChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ fragment.removeChild( input );
+ fragment.appendChild( div );
+
+ // Technique from Juriy Zaytsev
+ // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( div.attachEvent ) {
+ for ( i in {
+ submit: 1,
+ change: 1,
+ focusin: 1
+ }) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, "return;" );
+ isSupported = ( typeof div[ eventName ] === "function" );
+ }
+ support[ i + "Bubbles" ] = isSupported;
+ }
+ }
+
+ fragment.removeChild( div );
+
+ // Null elements to avoid leaks in IE
+ fragment = select = opt = div = input = null;
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, outer, inner, table, td, offsetSupport,
+ marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
+ paddingMarginBorderVisibility, paddingMarginBorder,
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ conMarginTop = 1;
+ paddingMarginBorder = "padding:0;margin:0;border:";
+ positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
+ paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
+ style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
+ html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
+ "<table " + style + "' cellpadding='0' cellspacing='0'>" +
+ "<tr><td></td></tr></table>";
+
+ container = document.createElement("div");
+ container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
+ body.insertBefore( container, body.firstChild );
+
+ // Construct the test element
+ div = document.createElement("div");
+ container.appendChild( div );
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName( "td" );
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE <= 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ if ( window.getComputedStyle ) {
+ div.innerHTML = "";
+ marginDiv = document.createElement( "div" );
+ marginDiv.style.width = "0";
+ marginDiv.style.marginRight = "0";
+ div.style.width = "2px";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+ }
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.innerHTML = "";
+ div.style.width = div.style.padding = "1px";
+ div.style.border = 0;
+ div.style.overflow = "hidden";
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "block";
+ div.style.overflow = "visible";
+ div.innerHTML = "<div style='width:5px;'></div>";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+ }
+
+ div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
+ div.innerHTML = html;
+
+ outer = div.firstChild;
+ inner = outer.firstChild;
+ td = outer.nextSibling.firstChild.firstChild;
+
+ offsetSupport = {
+ doesNotAddBorder: ( inner.offsetTop !== 5 ),
+ doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
+ };
+
+ inner.style.position = "fixed";
+ inner.style.top = "20px";
+
+ // safari subtracts parent border width here which is 5px
+ offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
+ inner.style.position = inner.style.top = "";
+
+ outer.style.overflow = "hidden";
+ outer.style.position = "relative";
+
+ offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
+ offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+
+ if ( window.getComputedStyle ) {
+ div.style.marginTop = "1%";
+ support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
+ }
+
+ if ( typeof container.style.zoom !== "undefined" ) {
+ container.style.zoom = 1;
+ }
+
+ body.removeChild( container );
+ marginDiv = div = container = null;
+
+ jQuery.extend( support, offsetSupport );
+ });
+
+ return support;
+})();
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+ cache: {},
+
+ // Please use with caution
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var privateCache, thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
+ isEvents = name === "events";
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = ++jQuery.uuid;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ privateCache = thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Users should not attempt to inspect the internal events object using jQuery.data,
+ // it is undocumented and subject to change. But does anyone listen? No.
+ if ( isEvents && !thisCache[ name ] ) {
+ return privateCache.events;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i, l,
+
+ // Reference to internal data cache key
+ internalKey = jQuery.expando,
+
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+
+ // See jQuery.data for more information
+ id = isNode ? elem[ internalKey ] : internalKey;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split( " " );
+ }
+ }
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject(cache[ id ]) ) {
+ return;
+ }
+ }
+
+ // Browsers that fail expando deletion also refuse to delete expandos on
+ // the window, but it will allow it on all other JS objects; other browsers
+ // don't care
+ // Ensure that `cache` is not a window object #10080
+ if ( jQuery.support.deleteExpando || !cache.setInterval ) {
+ delete cache[ id ];
+ } else {
+ cache[ id ] = null;
+ }
+
+ // We destroyed the cache and need to eliminate the expando on the node to avoid
+ // false lookups in the cache for entries that no longer exist
+ if ( isNode ) {
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( jQuery.support.deleteExpando ) {
+ delete elem[ internalKey ];
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( internalKey );
+ } else {
+ elem[ internalKey ] = null;
+ }
+ }
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ if ( elem.nodeName ) {
+ var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ if ( match ) {
+ return !(match === true || elem.getAttribute("classid") !== match);
+ }
+ }
+
+ return true;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var parts, part, attr, name, l,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attr = elem.attributes;
+ for ( l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.substring(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ parts = key.split( ".", 2 );
+ parts[1] = parts[1] ? "." + parts[1] : "";
+ part = parts[1] + "!";
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && elem ) {
+ data = jQuery.data( elem, key );
+ data = dataAttr( elem, key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ }
+
+ parts[1] = value;
+ this.each(function() {
+ var self = jQuery( this );
+
+ self.triggerHandler( "setData" + part, parts );
+ jQuery.data( this, key, value );
+ self.triggerHandler( "changeData" + part, parts );
+ });
+ }, null, value, arguments.length > 1, null, false );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ jQuery.isNumeric( data ) ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ for ( var name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+function handleQueueMarkDefer( elem, type, src ) {
+ var deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ defer = jQuery._data( elem, deferDataKey );
+ if ( defer &&
+ ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
+ ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
+ // Give room for hard-coded callbacks to fire first
+ // and eventually mark/queue something else on the element
+ setTimeout( function() {
+ if ( !jQuery._data( elem, queueDataKey ) &&
+ !jQuery._data( elem, markDataKey ) ) {
+ jQuery.removeData( elem, deferDataKey, true );
+ defer.fire();
+ }
+ }, 0 );
+ }
+}
+
+jQuery.extend({
+
+ _mark: function( elem, type ) {
+ if ( elem ) {
+ type = ( type || "fx" ) + "mark";
+ jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
+ }
+ },
+
+ _unmark: function( force, elem, type ) {
+ if ( force !== true ) {
+ type = elem;
+ elem = force;
+ force = false;
+ }
+ if ( elem ) {
+ type = type || "fx";
+ var key = type + "mark",
+ count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
+ if ( count ) {
+ jQuery._data( elem, key, count );
+ } else {
+ jQuery.removeData( elem, key, true );
+ handleQueueMarkDefer( elem, type, "mark" );
+ }
+ }
+ },
+
+ queue: function( elem, type, data ) {
+ var q;
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ q = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !q || jQuery.isArray(data) ) {
+ q = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ q.push( data );
+ }
+ }
+ return q || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ fn = queue.shift(),
+ hooks = {};
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ }
+
+ if ( fn ) {
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ jQuery._data( elem, type + ".run", hooks );
+ fn.call( elem, function() {
+ jQuery.dequeue( elem, type );
+ }, hooks );
+ }
+
+ if ( !queue.length ) {
+ jQuery.removeData( elem, type + "queue " + type + ".run", true );
+ handleQueueMarkDefer( elem, type, "queue" );
+ }
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, object ) {
+ if ( typeof type !== "string" ) {
+ object = type;
+ type = undefined;
+ }
+ type = type || "fx";
+ var defer = jQuery.Deferred(),
+ elements = this,
+ i = elements.length,
+ count = 1,
+ deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ tmp;
+ function resolve() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ }
+ while( i-- ) {
+ if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+ ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
+ jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
+ jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
+ count++;
+ tmp.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( object );
+ }
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+ rspace = /\s+/,
+ rreturn = /\r/g,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea)?$/i,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ nodeHook, boolHook, fixSpecified;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classNames, i, l, elem,
+ setClass, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ classNames = value.split( rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className && classNames.length === 1 ) {
+ elem.className = value;
+
+ } else {
+ setClass = " " + elem.className + " ";
+
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
+ setClass += classNames[ c ] + " ";
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classNames, i, l, elem, className, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( (value && typeof value === "string") || value === undefined ) {
+ classNames = ( value || "" ).split( rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 && elem.className ) {
+ if ( value ) {
+ className = (" " + elem.className + " ").replace( rclass, " " );
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ className = className.replace(" " + classNames[ c ] + " ", " ");
+ }
+ elem.className = jQuery.trim( className );
+
+ } else {
+ elem.className = "";
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.split( rspace );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space seperated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var self = jQuery(this), val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, i, max, option,
+ index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type === "select-one";
+
+ // Nothing was selected
+ if ( index < 0 ) {
+ return null;
+ }
+
+ // Loop through all the selected options
+ i = one ? index : 0;
+ max = one ? index + 1 : options.length;
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // Don't return options that are disabled or in a disabled optgroup
+ if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+ (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+ if ( one && !values.length && options.length ) {
+ return jQuery( options[ index ] ).val();
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attrFn: {
+ val: true,
+ css: true,
+ html: true,
+ text: true,
+ data: true,
+ width: true,
+ height: true,
+ offset: true
+ },
+
+ attr: function( elem, name, value, pass ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( pass && name in jQuery.attrFn ) {
+ return jQuery( elem )[ name ]( value );
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+
+ } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, "" + value );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ ret = elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret === null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var propName, attrNames, name, l, isBool,
+ i = 0;
+
+ if ( value && elem.nodeType === 1 ) {
+ attrNames = value.toLowerCase().split( rspace );
+ l = attrNames.length;
+
+ for ( ; i < l; i++ ) {
+ name = attrNames[ i ];
+
+ if ( name ) {
+ propName = jQuery.propFix[ name ] || name;
+ isBool = rboolean.test( name );
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ // Do not do this for boolean attributes (see #10870)
+ if ( !isBool ) {
+ jQuery.attr( elem, name, "" );
+ }
+ elem.removeAttribute( getSetAttribute ? name : propName );
+
+ // Set corresponding property to false for boolean attributes
+ if ( isBool && propName in elem ) {
+ elem[ propName ] = false;
+ }
+ }
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to it's default in case type is set after value
+ // This is for element creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ },
+ // Use the value property for back compat
+ // Use the nodeHook for button elements in IE6/7 (#1954)
+ value: {
+ get: function( elem, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.get( elem, name );
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.set( elem, value, name );
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
+jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ fixSpecified = {
+ name: true,
+ id: true,
+ coords: true
+ };
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret;
+ ret = elem.getAttributeNode( name );
+ return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
+ ret.nodeValue :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ ret = document.createAttribute( name );
+ elem.setAttributeNode( ret );
+ }
+ return ( ret.nodeValue = value + "" );
+ }
+ };
+
+ // Apply the nodeHook to tabindex
+ jQuery.attrHooks.tabindex.set = nodeHook.set;
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ if ( value === "" ) {
+ value = "false";
+ }
+ nodeHook.set( elem, value, name );
+ }
+ };
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret === null ? undefined : ret;
+ }
+ });
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Normalize to lowercase since IE uppercases css property names
+ return elem.style.cssText.toLowerCase() || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = "" + value );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+
+
+
+
+var rformElems = /^(?:textarea|input|select)$/i,
+ rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
+ rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
+ quickParse = function( selector ) {
+ var quick = rquickIs.exec( selector );
+ if ( quick ) {
+ // 0 1 2 3
+ // [ _, tag, id, class ]
+ quick[1] = ( quick[1] || "" ).toLowerCase();
+ quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
+ }
+ return quick;
+ },
+ quickIs = function( elem, m ) {
+ var attrs = elem.attributes || {};
+ return (
+ (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
+ (!m[2] || (attrs.id || {}).value === m[2]) &&
+ (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
+ );
+ },
+ hoverHack = function( events ) {
+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, quick, handlers, special;
+
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ events = elemData.events;
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+ eventHandle = elemData.handle;
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = jQuery.trim( hoverHack(types) ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
+
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ quick: selector && quickParse( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ t, tns, type, origType, namespaces, origCount,
+ j, events, special, handle, eventType, handleObj;
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tns[1];
+ namespaces = tns[2];
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector? special.delegateType : special.bindType ) || type;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+
+ // Remove matching events
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ eventType.splice( j--, 1 );
+
+ if ( handleObj.selector ) {
+ eventType.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( eventType.length === 0 && origCount !== eventType.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, [ "events", "handle" ], true );
+ }
+ },
+
+ // Events that are safe to short-circuit if no handlers are attached.
+ // Native DOM events should not be added, they may have inline handlers.
+ customEvent: {
+ "getData": true,
+ "setData": true,
+ "changeData": true
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
+ // Event object or event type
+ var type = event.type || event,
+ namespaces = [],
+ cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "!" ) >= 0 ) {
+ // Exclusive events trigger only for the exact event (no namespaces)
+ type = type.slice(0, -1);
+ exclusive = true;
+ }
+
+ if ( type.indexOf( "." ) >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+
+ if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+ // No jQuery handlers for this event type, and it can't have inline handlers
+ return;
+ }
+
+ // Caller can pass in an Event, Object, or just an event type string
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[ jQuery.expando ] ? event :
+ // Object literal
+ new jQuery.Event( type, event ) :
+ // Just the event type (string)
+ new jQuery.Event( type );
+
+ event.type = type;
+ event.isTrigger = true;
+ event.exclusive = exclusive;
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+ // Handle a global trigger
+ if ( !elem ) {
+
+ // TODO: Stop taunting the data cache; remove global events and always attach to document
+ cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+ }
+ }
+ return;
+ }
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data != null ? jQuery.makeArray( data ) : [];
+ data.unshift( event );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ eventPath = [[ elem, special.bindType || type ]];
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+ old = null;
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push([ cur, bubbleType ]);
+ old = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( old && old === elem.ownerDocument ) {
+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+ }
+ }
+
+ // Fire handlers on the event path
+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+ cur = eventPath[i][0];
+ event.type = eventPath[i][1];
+
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+ // Note that this is a bare JS function and not a jQuery handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event || window.event );
+
+ var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = [].slice.call( arguments, 0 ),
+ run_all = !event.exclusive && !event.namespace,
+ special = jQuery.event.special[ event.type ] || {},
+ handlerQueue = [],
+ i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers that should run if there are delegated events
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !(event.button && event.type === "click") ) {
+
+ // Pregenerate a single jQuery object for reuse with .is()
+ jqcur = jQuery(this);
+ jqcur.context = this.ownerDocument || this;
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+ // Don't process events on disabled elements (#6911, #8165)
+ if ( cur.disabled !== true ) {
+ selMatch = {};
+ matches = [];
+ jqcur[0] = cur;
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = (
+ handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
+ );
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( handlers.length > delegateCount ) {
+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+ }
+
+ // Run delegates first; they may want to stop propagation beneath us
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ event.currentTarget = matched.elem;
+
+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = matched.matches[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop,
+ originalEvent = event,
+ fixHook = jQuery.event.fixHooks[ event.type ] || {},
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = jQuery.Event( originalEvent );
+
+ for ( i = copy.length; i; ) {
+ prop = copy[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Target should not be a text node (#504, Safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+ if ( event.metaKey === undefined ) {
+ event.metaKey = event.ctrlKey;
+ }
+
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ ready: {
+ // Make sure the ready event is setup
+ setup: jQuery.bindReady
+ },
+
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+
+ focus: {
+ delegateType: "focusin"
+ },
+ blur: {
+ delegateType: "focusout"
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
+ }
+ },
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ if ( elem.detachEvent ) {
+ elem.detachEvent( "on" + type, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // otherwise set the returnValue property of the original event to false (IE)
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector,
+ ret;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !form._submit_attached ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ form._submit_attached = true;
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ jQuery.event.simulate( "change", this, event, true );
+ }
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ elem._change_attached = true;
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) { // && selector != null
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ var handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( var type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ return jQuery.event.trigger( type, data, this[0], true );
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+ }
+});
+
+
+
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ expando = "sizcache" + (Math.random() + '').replace('.', ''),
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rReturn = /\r\n/g,
+ rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+
+ var origContext = context;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var m, set, checkSet, extra, ret, cur, pop, i,
+ prune = true,
+ contextXML = Sizzle.isXML( context ),
+ parts = [],
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ do {
+ chunker.exec( "" );
+ m = chunker.exec( soFar );
+
+ if ( m ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+ } while ( m );
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context, seed );
+
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set, seed );
+ }
+ }
+
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+ ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set )[0] :
+ ret.set[0];
+ }
+
+ if ( context ) {
+ ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+ set = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set ) :
+ ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray( set );
+
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ cur = parts.pop();
+ pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+
+ } else if ( context && context.nodeType === 1 ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+
+ } else {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[ i - 1 ] ) {
+ results.splice( i--, 1 );
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+ return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+ return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+ var set, i, len, match, type, left;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ left = match[1];
+ match.splice( 1, 1 );
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace( rBackslash, "" );
+ set = Expr.find[ type ]( match, context, isXML );
+
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( "*" ) :
+ [];
+ }
+
+ return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+ var match, anyFound,
+ type, found, item, filter, left,
+ i, pass,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ filter = Expr.filter[ type ];
+ left = match[1];
+
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ pass = not ^ found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+
+ } else {
+ curLoop[i] = false;
+ }
+
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Utility function for retreiving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+var getText = Sizzle.getText = function( elem ) {
+ var i, node,
+ nodeType = elem.nodeType,
+ ret = "";
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent || innerText for elements
+ if ( typeof elem.textContent === 'string' ) {
+ return elem.textContent;
+ } else if ( typeof elem.innerText === 'string' ) {
+ // Replace IE's carriage returns
+ return elem.innerText.replace( rReturn, '' );
+ } else {
+ // Traverse it's children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( i = 0; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ if ( node.nodeType !== 8 ) {
+ ret += getText( node );
+ }
+ }
+ }
+ return ret;
+};
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+
+ leftMatch: {},
+
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+
+ attrHandle: {
+ href: function( elem ) {
+ return elem.getAttribute( "href" );
+ },
+ type: function( elem ) {
+ return elem.getAttribute( "type" );
+ }
+ },
+
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !rNonWord.test( part ),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+
+ ">": function( checkSet, part ) {
+ var elem,
+ isPartStr = typeof part === "string",
+ i = 0,
+ l = checkSet.length;
+
+ if ( isPartStr && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+
+ } else {
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+
+ "": function(checkSet, part, isXML){
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+ },
+
+ "~": function( checkSet, part, isXML ) {
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+ }
+ },
+
+ find: {
+ ID: function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ },
+
+ NAME: function( match, context ) {
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [],
+ results = context.getElementsByName( match[1] );
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+
+ TAG: function( match, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( match[1] );
+ }
+ }
+ },
+ preFilter: {
+ CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+ match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ ID: function( match ) {
+ return match[1].replace( rBackslash, "" );
+ },
+
+ TAG: function( match, curLoop ) {
+ return match[1].replace( rBackslash, "" ).toLowerCase();
+ },
+
+ CHILD: function( match ) {
+ if ( match[1] === "nth" ) {
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[2] = match[2].replace(/^\+|\s*/g, '');
+
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+ else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+
+ ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+ var name = match[1] = match[1].replace( rBackslash, "" );
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ // Handle if an un-quoted value was used
+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+
+ PSEUDO: function( match, curLoop, inplace, result, not ) {
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+
+ return false;
+ }
+
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+
+ POS: function( match ) {
+ match.unshift( true );
+
+ return match;
+ }
+ },
+
+ filters: {
+ enabled: function( elem ) {
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+
+ disabled: function( elem ) {
+ return elem.disabled === true;
+ },
+
+ checked: function( elem ) {
+ return elem.checked === true;
+ },
+
+ selected: function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ parent: function( elem ) {
+ return !!elem.firstChild;
+ },
+
+ empty: function( elem ) {
+ return !elem.firstChild;
+ },
+
+ has: function( elem, i, match ) {
+ return !!Sizzle( match[3], elem ).length;
+ },
+
+ header: function( elem ) {
+ return (/h\d/i).test( elem.nodeName );
+ },
+
+ text: function( elem ) {
+ var attr = elem.getAttribute( "type" ), type = elem.type;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+ },
+
+ radio: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+ },
+
+ checkbox: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+ },
+
+ file: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+ },
+
+ password: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+ },
+
+ submit: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "submit" === elem.type;
+ },
+
+ image: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+ },
+
+ reset: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "reset" === elem.type;
+ },
+
+ button: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && "button" === elem.type || name === "button";
+ },
+
+ input: function( elem ) {
+ return (/input|select|textarea|button/i).test( elem.nodeName );
+ },
+
+ focus: function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ }
+ },
+ setFilters: {
+ first: function( elem, i ) {
+ return i === 0;
+ },
+
+ last: function( elem, i, match, array ) {
+ return i === array.length - 1;
+ },
+
+ even: function( elem, i ) {
+ return i % 2 === 0;
+ },
+
+ odd: function( elem, i ) {
+ return i % 2 === 1;
+ },
+
+ lt: function( elem, i, match ) {
+ return i < match[3] - 0;
+ },
+
+ gt: function( elem, i, match ) {
+ return i > match[3] - 0;
+ },
+
+ nth: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ },
+
+ eq: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function( elem, match, i, array ) {
+ var name = match[1],
+ filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ } else {
+ Sizzle.error( name );
+ }
+ },
+
+ CHILD: function( elem, match ) {
+ var first, last,
+ doneName, parent, cache,
+ count, diff,
+ type = match[1],
+ node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ first = match[2];
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ doneName = match[0];
+ parent = elem.parentNode;
+
+ if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
+ count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent[ expando ] = doneName;
+ }
+
+ diff = elem.nodeIndex - last;
+
+ if ( first === 0 ) {
+ return diff === 0;
+
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+
+ ID: function( elem, match ) {
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+
+ TAG: function( elem, match ) {
+ return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
+ },
+
+ CLASS: function( elem, match ) {
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+
+ ATTR: function( elem, match ) {
+ var name = match[1],
+ result = Sizzle.attr ?
+ Sizzle.attr( elem, name ) :
+ Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ !type && Sizzle.attr ?
+ result != null :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+
+ POS: function( elem, match, i, array ) {
+ var name = match[2],
+ filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+// Expose origPOS
+// "global" as in regardless of relation to brackets/parens
+Expr.match.globalPOS = origPOS;
+
+var makeArray = function( array, results ) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+ makeArray = function( array, results ) {
+ var i = 0,
+ ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+
+ } else {
+ for ( ; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+ };
+
+} else {
+ sortOrder = function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+ };
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date()).getTime(),
+ root = document.documentElement;
+
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+
+ return m ?
+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+
+ Expr.filter.ID = function( elem, match ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+
+ // release memory in IE
+ root = form = null;
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function( match, context ) {
+ var results = context.getElementsByTagName( match[1] );
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "<a href='#'></a>";
+
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+
+ Expr.attrHandle.href = function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ };
+ }
+
+ // release memory in IE
+ div = null;
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle,
+ div = document.createElement("div"),
+ id = "__sizzle__";
+
+ div.innerHTML = "<p class='TEST'></p>";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function( query, context, extra, seed ) {
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && !Sizzle.isXML(context) ) {
+ // See if we find a selector to speed up
+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+ // Speed-up: Sizzle("TAG")
+ if ( match[1] ) {
+ return makeArray( context.getElementsByTagName( query ), extra );
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+ return makeArray( context.getElementsByClassName( match[2] ), extra );
+ }
+ }
+
+ if ( context.nodeType === 9 ) {
+ // Speed-up: Sizzle("body")
+ // The body element only exists once, optimize finding it
+ if ( query === "body" && context.body ) {
+ return makeArray( [ context.body ], extra );
+
+ // Speed-up: Sizzle("#ID")
+ } else if ( match && match[3] ) {
+ var elem = context.getElementById( match[3] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id === match[3] ) {
+ return makeArray( [ elem ], extra );
+ }
+
+ } else {
+ return makeArray( [], extra );
+ }
+ }
+
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || id,
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if ( !old ) {
+ context.setAttribute( "id", nid );
+ } else {
+ nid = nid.replace( /'/g, "\\$&" );
+ }
+ if ( relativeHierarchySelector && hasParent ) {
+ context = context.parentNode;
+ }
+
+ try {
+ if ( !relativeHierarchySelector || hasParent ) {
+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+ }
+
+ } catch(pseudoError) {
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ // release memory in IE
+ div = null;
+ })();
+}
+
+(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+ if ( matches ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9 fails this)
+ var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+ pseudoWorks = false;
+
+ try {
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( document.documentElement, "[test!='']:sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ Sizzle.matchesSelector = function( node, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+ if ( !Sizzle.isXML( node ) ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+ var ret = matches.call( node, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || !disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9, so check for that
+ node.document && node.document.nodeType !== 11 ) {
+ return ret;
+ }
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ // Opera can't find a second classname (in 9.6)
+ // Also, make sure that getElementsByClassName actually exists
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function( match, context, isXML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ // release memory in IE
+ div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem[ expando ] = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem[ expando ] = doneName;
+ elem.sizset = i;
+ }
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+if ( document.documentElement.contains ) {
+ Sizzle.contains = function( a, b ) {
+ return a !== b && (a.contains ? a.contains(b) : true);
+ };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+ Sizzle.contains = function( a, b ) {
+ return !!(a.compareDocumentPosition(b) & 16);
+ };
+
+} else {
+ Sizzle.contains = function() {
+ return false;
+ };
+}
+
+Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context, seed ) {
+ var match,
+ tmpSet = [],
+ later = "",
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet, seed );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+Sizzle.selectors.attrMap = {};
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+ // Note: This RegExp should be improved, or likely pulled from Sizzle
+ rmultiselector = /,/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ slice = Array.prototype.slice,
+ POS = jQuery.expr.match.globalPOS,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var self = this,
+ i, l;
+
+ if ( typeof selector !== "string" ) {
+ return jQuery( selector ).filter(function() {
+ for ( i = 0, l = self.length; i < l; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ });
+ }
+
+ var ret = this.pushStack( "", "find", selector ),
+ length, n, r;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( n = length; n < ret.length; n++ ) {
+ for ( r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var targets = jQuery( target );
+ return this.filter(function() {
+ for ( var i = 0, l = targets.length; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ POS.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var ret = [], i, l, cur = this[0];
+
+ // Array (deprecated as of jQuery 1.7)
+ if ( jQuery.isArray( selectors ) ) {
+ var level = 1;
+
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( i = 0; i < selectors.length; i++ ) {
+
+ if ( jQuery( cur ).is( selectors[ i ] ) ) {
+ ret.push({ selector: selectors[ i ], elem: cur, level: level });
+ }
+ }
+
+ cur = cur.parentNode;
+ level++;
+ }
+
+ return ret;
+ }
+
+ // String
+ var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+
+ } else {
+ cur = cur.parentNode;
+ if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return jQuery.nth( elem, 2, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return jQuery.nth( elem, 2, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.makeArray( elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, slice.call( arguments ).join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function( cur, result, dir, elem ) {
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] ) {
+ if ( cur.nodeType === 1 && ++num === result ) {
+ break;
+ }
+ }
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+ // Can't pass null or undefined to indexOf in Firefox 4
+ // Set to 0 to skip string check
+ qualifier = qualifier || 0;
+
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( elem === qualifier ) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+ });
+}
+
+
+
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style)/i,
+ rnocache = /<(?:script|object|embed|option|style)/i,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /\/(java|ecma)script/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ area: [ 1, "<map>", "</map>" ],
+ _default: [ 0, "", "" ]
+ },
+ safeFragment = createSafeFragment( document );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ } else if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ set.push.apply( set, this.toArray() );
+ return this.pushStack( set, "before", arguments );
+ }
+ },
+
+ after: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ } else if ( arguments.length ) {
+ var set = this.pushStack( this, "after", arguments );
+ set.push.apply( set, jQuery.clean(arguments) );
+ return set;
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ null;
+ }
+
+
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function( value ) {
+ if ( this[0] && this[0].parentNode ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery( value ).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ jQuery( this ).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ } else {
+ return this.length ?
+ this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+ this;
+ }
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+ var results, first, fragment, parent,
+ value = args[0],
+ scripts = [];
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback, true );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call(this, i, table ? self.html() : undefined);
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ parent = value && value.parentNode;
+
+ // If we're in a fragment, just use that instead of building a new one
+ if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+ results = { fragment: parent };
+
+ } else {
+ results = jQuery.buildFragment( args, this, scripts );
+ }
+
+ fragment = results.fragment;
+
+ if ( fragment.childNodes.length === 1 ) {
+ first = fragment = fragment.firstChild;
+ } else {
+ first = fragment.firstChild;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+ callback.call(
+ table ?
+ root(this[i], first) :
+ this[i],
+ // Make sure that we do not leak memory by inadvertently discarding
+ // the original fragment (which might have attached data) instead of
+ // using it; in addition, use the original fragment object for the last
+ // item instead of first because it can end up being emptied incorrectly
+ // in certain situations (Bug #8070).
+ // Fragments from the fragment cache must always be cloned and never used
+ // in place.
+ results.cacheable || ( l > 1 && i < lastIndex ) ?
+ jQuery.clone( fragment, true, true ) :
+ fragment
+ );
+ }
+ }
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, function( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ type: "GET",
+ global: false,
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ });
+ }
+ }
+
+ return this;
+ }
+});
+
+function root( elem, cur ) {
+ return jQuery.nodeName(elem, "table") ?
+ (elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+ elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function cloneFixAttributes( src, dest ) {
+ var nodeName;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // clearAttributes removes the attributes, which we don't want,
+ // but also removes the attachEvent events, which we *do* want
+ if ( dest.clearAttributes ) {
+ dest.clearAttributes();
+ }
+
+ // mergeAttributes, in contrast, only merges back on the
+ // original attributes, not the events
+ if ( dest.mergeAttributes ) {
+ dest.mergeAttributes( src );
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 fail to clone children inside object elements that use
+ // the proprietary classid attribute value (rather than the type
+ // attribute) to identify the type of content to display
+ if ( nodeName === "object" ) {
+ dest.outerHTML = src.outerHTML;
+
+ } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+ if ( src.checked ) {
+ dest.defaultChecked = dest.checked = src.checked;
+ }
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+
+ // IE blanks contents when cloning scripts
+ } else if ( nodeName === "script" && dest.text !== src.text ) {
+ dest.text = src.text;
+ }
+
+ // Event data gets referenced instead of copied if the expando
+ // gets copied too
+ dest.removeAttribute( jQuery.expando );
+
+ // Clear flags for bubbling special change/submit events, they must
+ // be reattached when the newly cloned events are first activated
+ dest.removeAttribute( "_submit_attached" );
+ dest.removeAttribute( "_change_attached" );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+ var fragment, cacheable, cacheresults, doc,
+ first = args[ 0 ];
+
+ // nodes may contain either an explicit document object,
+ // a jQuery collection or context object.
+ // If nodes[0] contains a valid object to assign to doc
+ if ( nodes && nodes[0] ) {
+ doc = nodes[0].ownerDocument || nodes[0];
+ }
+
+ // Ensure that an attr object doesn't incorrectly stand in as a document object
+ // Chrome and Firefox seem to allow this to occur and will throw exception
+ // Fixes #8950
+ if ( !doc.createDocumentFragment ) {
+ doc = document;
+ }
+
+ // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+ if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
+ first.charAt(0) === "<" && !rnocache.test( first ) &&
+ (jQuery.support.checkClone || !rchecked.test( first )) &&
+ (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+ cacheable = true;
+
+ cacheresults = jQuery.fragments[ first ];
+ if ( cacheresults && cacheresults !== 1 ) {
+ fragment = cacheresults;
+ }
+ }
+
+ if ( !fragment ) {
+ fragment = doc.createDocumentFragment();
+ jQuery.clean( args, doc, fragment, scripts );
+ }
+
+ if ( cacheable ) {
+ jQuery.fragments[ first ] = cacheresults ? fragment : 1;
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = [],
+ insert = jQuery( selector ),
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+
+ } else {
+ for ( var i = 0, l = insert.length; i < l; i++ ) {
+ var elems = ( i > 0 ? this.clone(true) : this ).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+function getAll( elem ) {
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ return elem.getElementsByTagName( "*" );
+
+ } else if ( typeof elem.querySelectorAll !== "undefined" ) {
+ return elem.querySelectorAll( "*" );
+
+ } else {
+ return [];
+ }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( elem.type === "checkbox" || elem.type === "radio" ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "input" ) {
+ fixDefaultChecked( elem );
+ // Skip scripts, get other children
+ } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
+ jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+ }
+}
+
+// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
+function shimCloneNode( elem ) {
+ var div = document.createElement( "div" );
+ safeFragment.appendChild( div );
+
+ div.innerHTML = elem.outerHTML;
+ return div.firstChild;
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var srcElements,
+ destElements,
+ i,
+ // IE<=8 does not properly clone detached, unknown element nodes
+ clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
+ elem.cloneNode( true ) :
+ shimCloneNode( elem );
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+ // IE copies events bound via attachEvent when using cloneNode.
+ // Calling detachEvent on the clone will also remove the events
+ // from the original. In order to get around this, we use some
+ // proprietary methods to clear the events. Thanks to MooTools
+ // guys for this hotness.
+
+ cloneFixAttributes( elem, clone );
+
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ // Weird iteration because IE will replace the length property
+ // with an element if you are cloning the body and one of the
+ // elements on the page has a name or id of "length"
+ for ( i = 0; srcElements[i]; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ cloneCopyEvent( elem, clone );
+
+ if ( deepDataAndEvents ) {
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneCopyEvent( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ srcElements = destElements = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ clean: function( elems, context, fragment, scripts ) {
+ var checkScriptType, script, j,
+ ret = [];
+
+ context = context || document;
+
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if ( typeof context.createElement === "undefined" ) {
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+ }
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" ) {
+ if ( !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+ } else {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
+ wrap = wrapMap[ tag ] || wrapMap._default,
+ depth = wrap[0],
+ div = context.createElement("div"),
+ safeChildNodes = safeFragment.childNodes,
+ remove;
+
+ // Append wrapper element to unknown element safe doc fragment
+ if ( context === document ) {
+ // Use the fragment we've already created for this document
+ safeFragment.appendChild( div );
+ } else {
+ // Use a fragment created with the owner document
+ createSafeFragment( context ).appendChild( div );
+ }
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var hasBody = rtbody.test(elem),
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+
+ // Clear elements from DocumentFragment (safeFragment or otherwise)
+ // to avoid hoarding elements. Fixes #11356
+ if ( div ) {
+ div.parentNode.removeChild( div );
+
+ // Guard against -1 index exceptions in FF3.6
+ if ( safeChildNodes.length > 0 ) {
+ remove = safeChildNodes[ safeChildNodes.length - 1 ];
+
+ if ( remove && remove.parentNode ) {
+ remove.parentNode.removeChild( remove );
+ }
+ }
+ }
+ }
+ }
+
+ // Resets defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ var len;
+ if ( !jQuery.support.appendChecked ) {
+ if ( elem[0] && typeof (len = elem.length) === "number" ) {
+ for ( j = 0; j < len; j++ ) {
+ findInputs( elem[j] );
+ }
+ } else {
+ findInputs( elem );
+ }
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ ret = jQuery.merge( ret, elem );
+ }
+ }
+
+ if ( fragment ) {
+ checkScriptType = function( elem ) {
+ return !elem.type || rscriptType.test( elem.type );
+ };
+ for ( i = 0; ret[i]; i++ ) {
+ script = ret[i];
+ if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
+ scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
+
+ } else {
+ if ( script.nodeType === 1 ) {
+ var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
+
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ }
+ fragment.appendChild( script );
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems ) {
+ var data, id,
+ cache = jQuery.cache,
+ special = jQuery.event.special,
+ deleteExpando = jQuery.support.deleteExpando;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ continue;
+ }
+
+ id = elem[ jQuery.expando ];
+
+ if ( id ) {
+ data = cache[ id ];
+
+ if ( data && data.events ) {
+ for ( var type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+
+ // Null the DOM reference to avoid IE6/7/8 leak (#7054)
+ if ( data.handle ) {
+ data.handle.elem = null;
+ }
+ }
+
+ if ( deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ delete cache[ id ];
+ }
+ }
+ }
+});
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity=([^)]*)/,
+ // fixed for IE9, see #8346
+ rupper = /([A-Z]|^ms)/g,
+ rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
+ rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
+ rrelNum = /^([\-+])=([\-+.\de]+)/,
+ rmargin = /^margin/,
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+
+ // order is important!
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+
+ curCSS,
+
+ getComputedStyle,
+ currentStyle;
+
+jQuery.fn.css = function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+};
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+
+ } else {
+ return elem.style.opacity;
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, origName = jQuery.camelCase( name ),
+ style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+ name = jQuery.cssProps[ origName ] || origName;
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra ) {
+ var ret, hooks;
+
+ // Make sure that we're working with the right name
+ name = jQuery.camelCase( name );
+ hooks = jQuery.cssHooks[ name ];
+ name = jQuery.cssProps[ name ] || name;
+
+ // cssFloat needs a special treatment
+ if ( name === "cssFloat" ) {
+ name = "float";
+ }
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+ return ret;
+
+ // Otherwise, if a way to get the computed value exists, use that
+ } else if ( curCSS ) {
+ return curCSS( elem, name );
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {},
+ ret, name;
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// DEPRECATED in 1.3, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ getComputedStyle = function( elem, name ) {
+ var ret, defaultView, computedStyle, width,
+ style = elem.style;
+
+ name = name.replace( rupper, "-$1" ).toLowerCase();
+
+ if ( (defaultView = elem.ownerDocument.defaultView) &&
+ (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+
+ ret = computedStyle.getPropertyValue( name );
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
+ // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
+ width = style.width;
+ style.width = ret;
+ ret = computedStyle.width;
+ style.width = width;
+ }
+
+ return ret;
+ };
+}
+
+if ( document.documentElement.currentStyle ) {
+ currentStyle = function( elem, name ) {
+ var left, rsLeft, uncomputed,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && (uncomputed = style[ name ]) ) {
+ ret = uncomputed;
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( rnumnonpx.test( ret ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ i = name === "width" ? 1 : 0,
+ len = 4;
+
+ if ( val > 0 ) {
+ if ( extra !== "border" ) {
+ for ( ; i < len; i += 2 ) {
+ if ( !extra ) {
+ val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
+ } else {
+ val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+ }
+
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+
+ // Add padding, border, margin
+ if ( extra ) {
+ for ( ; i < len; i += 2 ) {
+ val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ if ( extra !== "padding" ) {
+ val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ if ( elem.offsetWidth !== 0 ) {
+ return getWidthOrHeight( elem, name, extra );
+ } else {
+ return jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ });
+ }
+ }
+ },
+
+ set: function( elem, value ) {
+ return rnum.test( value ) ?
+ value + "px" :
+ value;
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there there is no filter style applied in a css rule, we are done
+ if ( currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery(function() {
+ // This hook cannot be added until DOM ready because the support test
+ // for it is not run until after DOM ready
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" }, function() {
+ if ( computed ) {
+ return curCSS( elem, "margin-right" );
+ } else {
+ return elem.style.marginRight;
+ }
+ });
+ }
+ };
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ var width = elem.offsetWidth,
+ height = elem.offsetHeight;
+
+ return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i,
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ],
+ expanded = {};
+
+ for ( i = 0; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+});
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rhash = /#.*$/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rquery = /\?/,
+ rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ rselectTextarea = /^(?:select|textarea)/i,
+ rspacesAjax = /\s+/,
+ rts = /([?&])_=[^&]*/,
+ rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Document location
+ ajaxLocation,
+
+ // Document location segments
+ ajaxLocParts,
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ if ( jQuery.isFunction( func ) ) {
+ var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+ i = 0,
+ length = dataTypes.length,
+ dataType,
+ list,
+ placeBefore;
+
+ // For each dataType in the dataTypeExpression
+ for ( ; i < length; i++ ) {
+ dataType = dataTypes[ i ];
+ // We control if we're asked to add before
+ // any existing element
+ placeBefore = /^\+/.test( dataType );
+ if ( placeBefore ) {
+ dataType = dataType.substr( 1 ) || "*";
+ }
+ list = structure[ dataType ] = structure[ dataType ] || [];
+ // then we add to the structure accordingly
+ list[ placeBefore ? "unshift" : "push" ]( func );
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+ dataType /* internal */, inspected /* internal */ ) {
+
+ dataType = dataType || options.dataTypes[ 0 ];
+ inspected = inspected || {};
+
+ inspected[ dataType ] = true;
+
+ var list = structure[ dataType ],
+ i = 0,
+ length = list ? list.length : 0,
+ executeOnly = ( structure === prefilters ),
+ selection;
+
+ for ( ; i < length && ( executeOnly || !selection ); i++ ) {
+ selection = list[ i ]( options, originalOptions, jqXHR );
+ // If we got redirected to another dataType
+ // we try there if executing only and not done already
+ if ( typeof selection === "string" ) {
+ if ( !executeOnly || inspected[ selection ] ) {
+ selection = undefined;
+ } else {
+ options.dataTypes.unshift( selection );
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, selection, inspected );
+ }
+ }
+ }
+ // If we're only executing or nothing was selected
+ // we try the catchall dataType if not done already
+ if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, "*", inspected );
+ }
+ // unnecessary when only executing (prefilters)
+ // but it'll be ignored by the caller in that case
+ return selection;
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+}
+
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+
+ // Don't do a request if no elements are being requested
+ } else if ( !this.length ) {
+ return this;
+ }
+
+ var off = url.indexOf( " " );
+ if ( off >= 0 ) {
+ var selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params ) {
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( typeof params === "object" ) {
+ params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+ type = "POST";
+ }
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ // Complete callback (responseText is used internally)
+ complete: function( jqXHR, status, responseText ) {
+ // Store the response as specified by the jqXHR object
+ responseText = jqXHR.responseText;
+ // If successful, inject the HTML into all the matched elements
+ if ( jqXHR.isResolved() ) {
+ // #4825: Get the actual response in case
+ // a dataFilter is present in ajaxSettings
+ jqXHR.done(function( r ) {
+ responseText = r;
+ });
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(responseText.replace(rscript, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ responseText );
+ }
+
+ if ( callback ) {
+ self.each( callback, [ responseText, status, jqXHR ] );
+ }
+ }
+ });
+
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+
+ serializeArray: function() {
+ return this.map(function(){
+ return this.elements ? jQuery.makeArray( this.elements ) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
+ rinput.test( this.type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val, i ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+ jQuery.fn[ o ] = function( f ){
+ return this.on( o, f );
+ };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ type: method,
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ };
+});
+
+jQuery.extend({
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ if ( settings ) {
+ // Building a settings object
+ ajaxExtend( target, jQuery.ajaxSettings );
+ } else {
+ // Extending ajaxSettings
+ settings = target;
+ target = jQuery.ajaxSettings;
+ }
+ ajaxExtend( target, settings );
+ return target;
+ },
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ type: "GET",
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ processData: true,
+ async: true,
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ text: "text/plain",
+ json: "application/json, text/javascript",
+ "*": allTypes
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText"
+ },
+
+ // List of data converters
+ // 1) key format is "source_type destination_type" (a single space in-between)
+ // 2) the catchall symbol "*" can be used for source_type
+ converters: {
+
+ // Convert anything to text
+ "* text": window.String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ context: true,
+ url: true
+ }
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events
+ // It's the callbackContext if one was provided in the options
+ // and if it's a DOM node or a jQuery collection
+ globalEventContext = callbackContext !== s &&
+ ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+ jQuery( callbackContext ) : jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // ifModified key
+ ifModifiedKey,
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // transport
+ transport,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // The jqXHR state
+ state = 0,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Fake xhr
+ jqXHR = {
+
+ readyState: 0,
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( !state ) {
+ var lname = name.toLowerCase();
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match === undefined ? null : match;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ statusText = statusText || "abort";
+ if ( transport ) {
+ transport.abort( statusText );
+ }
+ done( 0, statusText );
+ return this;
+ }
+ };
+
+ // Callback for when everything is done
+ // It is defined here because jslint complains if it is declared
+ // at the end of the function (which would be more logical and readable)
+ function done( status, nativeStatusText, responses, headers ) {
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ var isSuccess,
+ success,
+ error,
+ statusText = nativeStatusText,
+ response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+ lastModified,
+ etag;
+
+ // If successful, handle type chaining
+ if ( status >= 200 && status < 300 || status === 304 ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+
+ if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+ jQuery.lastModified[ ifModifiedKey ] = lastModified;
+ }
+ if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+ jQuery.etag[ ifModifiedKey ] = etag;
+ }
+ }
+
+ // If not modified
+ if ( status === 304 ) {
+
+ statusText = "notmodified";
+ isSuccess = true;
+
+ // If we have data
+ } else {
+
+ try {
+ success = ajaxConvert( s, response );
+ statusText = "success";
+ isSuccess = true;
+ } catch(e) {
+ // We have a parsererror
+ statusText = "parsererror";
+ error = e;
+ }
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( !statusText || status ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = "" + ( nativeStatusText || statusText );
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+ jqXHR.complete = completeDeferred.add;
+
+ // Status-dependent callbacks
+ jqXHR.statusCode = function( map ) {
+ if ( map ) {
+ var tmp;
+ if ( state < 2 ) {
+ for ( tmp in map ) {
+ statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+ }
+ } else {
+ tmp = map[ jqXHR.status ];
+ jqXHR.then( tmp, tmp );
+ }
+ }
+ return this;
+ };
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+ // Determine if a cross-domain request is in order
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return false;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Get ifModifiedKey before adding the anti-cache parameter
+ ifModifiedKey = s.url;
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+
+ var ts = jQuery.now(),
+ // try replacing _= if it is there
+ ret = s.url.replace( rts, "$1_=" + ts );
+
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ ifModifiedKey = ifModifiedKey || s.url;
+ if ( jQuery.lastModified[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+ }
+ if ( jQuery.etag[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+ }
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already
+ jqXHR.abort();
+ return false;
+
+ }
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout( function(){
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch (e) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a, traditional ) {
+ var s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : value;
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( var prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+ }
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( var name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var contents = s.contents,
+ dataTypes = s.dataTypes,
+ responseFields = s.responseFields,
+ ct,
+ type,
+ finalDataType,
+ firstDataType;
+
+ // Fill responseXXX fields
+ for ( type in responseFields ) {
+ if ( type in responses ) {
+ jqXHR[ responseFields[type] ] = responses[ type ];
+ }
+ }
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+ // Apply the dataFilter if provided
+ if ( s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ var dataTypes = s.dataTypes,
+ converters = {},
+ i,
+ key,
+ length = dataTypes.length,
+ tmp,
+ // Current and previous dataTypes
+ current = dataTypes[ 0 ],
+ prev,
+ // Conversion expression
+ conversion,
+ // Conversion function
+ conv,
+ // Conversion functions (transitive conversion)
+ conv1,
+ conv2;
+
+ // For each dataType in the chain
+ for ( i = 1; i < length; i++ ) {
+
+ // Create converters map
+ // with lowercased keys
+ if ( i === 1 ) {
+ for ( key in s.converters ) {
+ if ( typeof key === "string" ) {
+ converters[ key.toLowerCase() ] = s.converters[ key ];
+ }
+ }
+ }
+
+ // Get the dataTypes
+ prev = current;
+ current = dataTypes[ i ];
+
+ // If current is auto dataType, update it to prev
+ if ( current === "*" ) {
+ current = prev;
+ // If no auto and dataTypes are actually different
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Get the converter
+ conversion = prev + " " + current;
+ conv = converters[ conversion ] || converters[ "* " + current ];
+
+ // If there is no direct converter, search transitively
+ if ( !conv ) {
+ conv2 = undefined;
+ for ( conv1 in converters ) {
+ tmp = conv1.split( " " );
+ if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+ conv2 = converters[ tmp[1] + " " + current ];
+ if ( conv2 ) {
+ conv1 = converters[ conv1 ];
+ if ( conv1 === true ) {
+ conv = conv2;
+ } else if ( conv2 === true ) {
+ conv = conv1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ // If we found no converter, dispatch an error
+ if ( !( conv || conv2 ) ) {
+ jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+ }
+ // If found converter is not an equivalence
+ if ( conv !== true ) {
+ // Convert with 1 or 2 converters accordingly
+ response = conv ? conv( response ) : conv2( conv1(response) );
+ }
+ }
+ }
+ return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+ jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ return jQuery.expando + "_" + ( jsc++ );
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
+
+ if ( s.dataTypes[ 0 ] === "jsonp" ||
+ s.jsonp !== false && ( jsre.test( s.url ) ||
+ inspectData && jsre.test( s.data ) ) ) {
+
+ var responseContainer,
+ jsonpCallback = s.jsonpCallback =
+ jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+ previous = window[ jsonpCallback ],
+ url = s.url,
+ data = s.data,
+ replace = "$1" + jsonpCallback + "$2";
+
+ if ( s.jsonp !== false ) {
+ url = url.replace( jsre, replace );
+ if ( s.url === url ) {
+ if ( inspectData ) {
+ data = data.replace( jsre, replace );
+ }
+ if ( s.data === data ) {
+ // Add callback manually
+ url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+ }
+ }
+ }
+
+ s.url = url;
+ s.data = data;
+
+ // Install callback
+ window[ jsonpCallback ] = function( response ) {
+ responseContainer = [ response ];
+ };
+
+ // Clean-up function
+ jqXHR.always(function() {
+ // Set callback back to previous value
+ window[ jsonpCallback ] = previous;
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( previous ) ) {
+ window[ jsonpCallback ]( responseContainer[ 0 ] );
+ }
+ });
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( jsonpCallback + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /javascript|ecmascript/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement( "script" );
+
+ script.async = "async";
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( head && script.parentNode ) {
+ head.removeChild( script );
+ }
+
+ // Dereference the script
+ script = undefined;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709 and #4378).
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( 0, 1 );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject ? function() {
+ // Abort all pending requests
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( 0, 1 );
+ }
+ } : false,
+ xhrId = 0,
+ xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+ jQuery.extend( jQuery.support, {
+ ajax: !!xhr,
+ cors: !!xhr && ( "withCredentials" in xhr )
+ });
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var xhr = s.xhr(),
+ handle,
+ i;
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( _ ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+
+ var status,
+ statusText,
+ responseHeaders,
+ responses,
+ xml;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occured
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ status = xhr.status;
+ responseHeaders = xhr.getAllResponseHeaders();
+ responses = {};
+ xml = xhr.responseXML;
+
+ // Construct response list
+ if ( xml && xml.documentElement /* #4958 */ ) {
+ responses.xml = xml;
+ }
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ try {
+ responses.text = xhr.responseText;
+ } catch( _ ) {
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ // if we're in sync mode or it's in cache
+ // and has been retrieved directly (IE6 & IE7)
+ // we need to manually fire the callback
+ if ( !s.async || xhr.readyState === 4 ) {
+ callback();
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback(0,1);
+ }
+ }
+ };
+ }
+ });
+}
+
+
+
+
+var elemdisplay = {},
+ iframe, iframeDoc,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+ timerId,
+ fxAttrs = [
+ // height animations
+ [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+ // width animations
+ [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+ // opacity animations
+ [ "opacity" ]
+ ],
+ fxNow;
+
+jQuery.fn.extend({
+ show: function( speed, easing, callback ) {
+ var elem, display;
+
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("show", 3), speed, easing, callback );
+
+ } else {
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+ display = elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( (display === "" && jQuery.css(elem, "display") === "none") ||
+ !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ if ( display === "" || display === "none" ) {
+ elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
+ }
+ }
+ }
+
+ return this;
+ }
+ },
+
+ hide: function( speed, easing, callback ) {
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("hide", 3), speed, easing, callback);
+
+ } else {
+ var elem, display,
+ i = 0,
+ j = this.length;
+
+ for ( ; i < j; i++ ) {
+ elem = this[i];
+ if ( elem.style ) {
+ display = jQuery.css( elem, "display" );
+
+ if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
+ jQuery._data( elem, "olddisplay", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ if ( this[i].style ) {
+ this[i].style.display = "none";
+ }
+ }
+
+ return this;
+ }
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2, callback ) {
+ var bool = typeof fn === "boolean";
+
+ if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+ this._toggle.apply( this, arguments );
+
+ } else if ( fn == null || bool ) {
+ this.each(function() {
+ var state = bool ? fn : jQuery(this).is(":hidden");
+ jQuery(this)[ state ? "show" : "hide" ]();
+ });
+
+ } else {
+ this.animate(genFx("toggle", 3), fn, fn2, callback);
+ }
+
+ return this;
+ },
+
+ fadeTo: function( speed, to, easing, callback ) {
+ return this.filter(":hidden").css("opacity", 0).show().end()
+ .animate({opacity: to}, speed, easing, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed( speed, easing, callback );
+
+ if ( jQuery.isEmptyObject( prop ) ) {
+ return this.each( optall.complete, [ false ] );
+ }
+
+ // Do not change referenced properties as per-property easing will be lost
+ prop = jQuery.extend( {}, prop );
+
+ function doAnimation() {
+ // XXX 'this' does not always have a nodeName when running the
+ // test suite
+
+ if ( optall.queue === false ) {
+ jQuery._mark( this );
+ }
+
+ var opt = jQuery.extend( {}, optall ),
+ isElement = this.nodeType === 1,
+ hidden = isElement && jQuery(this).is(":hidden"),
+ name, val, p, e, hooks, replace,
+ parts, start, end, unit,
+ method;
+
+ // will store per property easing and be used to determine when an animation is complete
+ opt.animatedProperties = {};
+
+ // first pass over propertys to expand / normalize
+ for ( p in prop ) {
+ name = jQuery.camelCase( p );
+ if ( p !== name ) {
+ prop[ name ] = prop[ p ];
+ delete prop[ p ];
+ }
+
+ if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
+ replace = hooks.expand( prop[ name ] );
+ delete prop[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'p' from above because we have the correct "name"
+ for ( p in replace ) {
+ if ( ! ( p in prop ) ) {
+ prop[ p ] = replace[ p ];
+ }
+ }
+ }
+ }
+
+ for ( name in prop ) {
+ val = prop[ name ];
+ // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+ if ( jQuery.isArray( val ) ) {
+ opt.animatedProperties[ name ] = val[ 1 ];
+ val = prop[ name ] = val[ 0 ];
+ } else {
+ opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+ }
+
+ if ( val === "hide" && hidden || val === "show" && !hidden ) {
+ return opt.complete.call( this );
+ }
+
+ if ( isElement && ( name === "height" || name === "width" ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( this, "display" ) === "inline" &&
+ jQuery.css( this, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
+ this.style.display = "inline-block";
+
+ } else {
+ this.style.zoom = 1;
+ }
+ }
+ }
+ }
+
+ if ( opt.overflow != null ) {
+ this.style.overflow = "hidden";
+ }
+
+ for ( p in prop ) {
+ e = new jQuery.fx( this, opt, p );
+ val = prop[ p ];
+
+ if ( rfxtypes.test( val ) ) {
+
+ // Tracks whether to show or hide based on private
+ // data attached to the element
+ method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
+ if ( method ) {
+ jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+ e[ method ]();
+ } else {
+ e[ val ]();
+ }
+
+ } else {
+ parts = rfxnum.exec( val );
+ start = e.cur();
+
+ if ( parts ) {
+ end = parseFloat( parts[2] );
+ unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+ // We need to compute starting value
+ if ( unit !== "px" ) {
+ jQuery.style( this, p, (end || 1) + unit);
+ start = ( (end || 1) / e.cur() ) * start;
+ jQuery.style( this, p, start + unit);
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] ) {
+ end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+ }
+
+ e.custom( start, end, unit );
+
+ } else {
+ e.custom( start, val, "" );
+ }
+ }
+ }
+
+ // For JS strict compliance
+ return true;
+ }
+
+ return optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+
+ stop: function( type, clearQueue, gotoEnd ) {
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var index,
+ hadTimers = false,
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ // clear marker counters if we know they won't be
+ if ( !gotoEnd ) {
+ jQuery._unmark( true, this );
+ }
+
+ function stopQueue( elem, data, index ) {
+ var hooks = data[ index ];
+ jQuery.removeData( elem, index, true );
+ hooks.stop( gotoEnd );
+ }
+
+ if ( type == null ) {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
+ stopQueue( this, data, index );
+ }
+ }
+ } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
+ stopQueue( this, data, index );
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ if ( gotoEnd ) {
+
+ // force the next step to be the last
+ timers[ index ]( true );
+ } else {
+ timers[ index ].saveState();
+ }
+ hadTimers = true;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( !( gotoEnd && hadTimers ) ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ }
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout( clearFxNow, 0 );
+ return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+ fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+ var obj = {};
+
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
+ obj[ this ] = type;
+ });
+
+ return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx( "show", 1 ),
+ slideUp: genFx( "hide", 1 ),
+ slideToggle: genFx( "toggle", 1 ),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.extend({
+ speed: function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function( noUnmark ) {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ } else if ( noUnmark !== false ) {
+ jQuery._unmark( this );
+ }
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
+ }
+ },
+
+ timers: [],
+
+ fx: function( elem, options, prop ) {
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ options.orig = options.orig || {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+ // Simple function for setting a style value
+ update: function() {
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
+ },
+
+ // Get the current size
+ cur: function() {
+ if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
+ return this.elem[ this.prop ];
+ }
+
+ var parsed,
+ r = jQuery.css( this.elem, this.prop );
+ // Empty strings, null, undefined and "auto" are converted to 0,
+ // complex values such as "rotate(1rad)" are returned as is,
+ // simple values such as "10px" are parsed to Float.
+ return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+ },
+
+ // Start an animation from one number to another
+ custom: function( from, to, unit ) {
+ var self = this,
+ fx = jQuery.fx;
+
+ this.startTime = fxNow || createFxNow();
+ this.end = to;
+ this.now = this.start = from;
+ this.pos = this.state = 0;
+ this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+
+ function t( gotoEnd ) {
+ return self.step( gotoEnd );
+ }
+
+ t.queue = this.options.queue;
+ t.elem = this.elem;
+ t.saveState = function() {
+ if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+ if ( self.options.hide ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ } else if ( self.options.show ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.end );
+ }
+ }
+ };
+
+ if ( t() && jQuery.timers.push(t) && !timerId ) {
+ timerId = setInterval( fx.tick, fx.interval );
+ }
+ },
+
+ // Simple 'show' function
+ show: function() {
+ var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
+
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ // Make sure that we start at a small width/height to avoid any flash of content
+ if ( dataShow !== undefined ) {
+ // This show is picking up where a previous hide or show left off
+ this.custom( this.cur(), dataShow );
+ } else {
+ this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+ }
+
+ // Start by showing the element
+ jQuery( this.elem ).show();
+ },
+
+ // Simple 'hide' function
+ hide: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom( this.cur(), 0 );
+ },
+
+ // Each step of an animation
+ step: function( gotoEnd ) {
+ var p, n, complete,
+ t = fxNow || createFxNow(),
+ done = true,
+ elem = this.elem,
+ options = this.options;
+
+ if ( gotoEnd || t >= options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ options.animatedProperties[ this.prop ] = true;
+
+ for ( p in options.animatedProperties ) {
+ if ( options.animatedProperties[ p ] !== true ) {
+ done = false;
+ }
+ }
+
+ if ( done ) {
+ // Reset the overflow
+ if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+ jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+ elem.style[ "overflow" + value ] = options.overflow[ index ];
+ });
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( options.hide ) {
+ jQuery( elem ).hide();
+ }
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( options.hide || options.show ) {
+ for ( p in options.animatedProperties ) {
+ jQuery.style( elem, p, options.orig[ p ] );
+ jQuery.removeData( elem, "fxshow" + p, true );
+ // Toggle data is no longer needed
+ jQuery.removeData( elem, "toggle" + p, true );
+ }
+ }
+
+ // Execute the complete function
+ // in the event that the complete function throws an exception
+ // we must ensure it won't be called twice. #5684
+
+ complete = options.complete;
+ if ( complete ) {
+
+ options.complete = false;
+ complete.call( elem );
+ }
+ }
+
+ return false;
+
+ } else {
+ // classical easing cannot be used with an Infinity duration
+ if ( options.duration == Infinity ) {
+ this.now = t;
+ } else {
+ n = t - this.startTime;
+ this.state = n / options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+ this.now = this.start + ( (this.end - this.start) * this.pos );
+ }
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+};
+
+jQuery.extend( jQuery.fx, {
+ tick: function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ },
+
+ interval: 13,
+
+ stop: function() {
+ clearInterval( timerId );
+ timerId = null;
+ },
+
+ speeds: {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+ },
+
+ step: {
+ opacity: function( fx ) {
+ jQuery.style( fx.elem, "opacity", fx.now );
+ },
+
+ _default: function( fx ) {
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ } else {
+ fx.elem[ fx.prop ] = fx.now;
+ }
+ }
+ }
+});
+
+// Ensure props that can't be negative don't go there on undershoot easing
+jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
+ // exclude marginTop, marginLeft, marginBottom and marginRight from this list
+ if ( prop.indexOf( "margin" ) ) {
+ jQuery.fx.step[ prop ] = function( fx ) {
+ jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+ };
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+ if ( !elemdisplay[ nodeName ] ) {
+
+ var body = document.body,
+ elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+ display = elem.css( "display" );
+ elem.remove();
+
+ // If the simple way fails,
+ // get element's real default display by attaching it to a temp iframe
+ if ( display === "none" || display === "" ) {
+ // No iframe to use yet, so create it
+ if ( !iframe ) {
+ iframe = document.createElement( "iframe" );
+ iframe.frameBorder = iframe.width = iframe.height = 0;
+ }
+
+ body.appendChild( iframe );
+
+ // Create a cacheable copy of the iframe document on first call.
+ // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+ // document to it; WebKit & Firefox won't allow reusing the iframe document.
+ if ( !iframeDoc || !iframe.createElement ) {
+ iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+ iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
+ iframeDoc.close();
+ }
+
+ elem = iframeDoc.createElement( nodeName );
+
+ iframeDoc.body.appendChild( elem );
+
+ display = jQuery.css( elem, "display" );
+ body.removeChild( iframe );
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return elemdisplay[ nodeName ];
+}
+
+
+
+
+var getOffset,
+ rtable = /^t(?:able|d|h)$/i,
+ rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+ getOffset = function( elem, doc, docElem, box ) {
+ try {
+ box = elem.getBoundingClientRect();
+ } catch(e) {}
+
+ // Make sure we're not dealing with a disconnected DOM node
+ if ( !box || !jQuery.contains( docElem, elem ) ) {
+ return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+ }
+
+ var body = doc.body,
+ win = getWindow( doc ),
+ clientTop = docElem.clientTop || body.clientTop || 0,
+ clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
+ scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+ top = box.top + scrollTop - clientTop,
+ left = box.left + scrollLeft - clientLeft;
+
+ return { top: top, left: left };
+ };
+
+} else {
+ getOffset = function( elem, doc, docElem ) {
+ var computedStyle,
+ offsetParent = elem.offsetParent,
+ prevOffsetParent = elem,
+ body = doc.body,
+ defaultView = doc.defaultView,
+ prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+ top = elem.offsetTop,
+ left = elem.offsetLeft;
+
+ while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+ break;
+ }
+
+ computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+ top -= elem.scrollTop;
+ left -= elem.scrollLeft;
+
+ if ( elem === offsetParent ) {
+ top += elem.offsetTop;
+ left += elem.offsetLeft;
+
+ if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevOffsetParent = offsetParent;
+ offsetParent = elem.offsetParent;
+ }
+
+ if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevComputedStyle = computedStyle;
+ }
+
+ if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+ top += body.offsetTop;
+ left += body.offsetLeft;
+ }
+
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+ top += Math.max( docElem.scrollTop, body.scrollTop );
+ left += Math.max( docElem.scrollLeft, body.scrollLeft );
+ }
+
+ return { top: top, left: left };
+ };
+}
+
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var elem = this[0],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return null;
+ }
+
+ if ( elem === doc.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ return getOffset( elem, doc, doc.documentElement );
+};
+
+jQuery.offset = {
+
+ bodyOffset: function( body ) {
+ var top = body.offsetTop,
+ left = body.offsetLeft;
+
+ if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
+ top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+ left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+ }
+
+ return { top: top, left: left };
+ },
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[0] ) {
+ return null;
+ }
+
+ var elem = this[0],
+
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+ offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+ // Add offsetParent borders
+ parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+ parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+ // Subtract the two offsets
+ return {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.body;
+ while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ jQuery.support.boxModel && win.document.documentElement[ method ] ||
+ win.document.body[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+
+
+
+// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ var clientProp = "client" + name,
+ scrollProp = "scroll" + name,
+ offsetProp = "offset" + name;
+
+ // innerHeight and innerWidth
+ jQuery.fn[ "inner" + name ] = function() {
+ var elem = this[0];
+ return elem ?
+ elem.style ?
+ parseFloat( jQuery.css( elem, type, "padding" ) ) :
+ this[ type ]() :
+ null;
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn[ "outer" + name ] = function( margin ) {
+ var elem = this[0];
+ return elem ?
+ elem.style ?
+ parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+ this[ type ]() :
+ null;
+ };
+
+ jQuery.fn[ type ] = function( value ) {
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc, docElemProp, orig, ret;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+ doc = elem.document;
+ docElemProp = doc.documentElement[ clientProp ];
+ return jQuery.support.boxModel && docElemProp ||
+ doc.body && doc.body[ clientProp ] || docElemProp;
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ doc = elem.documentElement;
+
+ // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
+ // so we can't use max, as it'll choose the incorrect offset[Width/Height]
+ // instead we use the correct client[Width/Height]
+ // support:IE6
+ if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
+ return doc[ clientProp ];
+ }
+
+ return Math.max(
+ elem.body[ scrollProp ], doc[ scrollProp ],
+ elem.body[ offsetProp ], doc[ offsetProp ]
+ );
+ }
+
+ // Get width or height on the element
+ if ( value === undefined ) {
+ orig = jQuery.css( elem, type );
+ ret = parseFloat( orig );
+ return jQuery.isNumeric( ret ) ? ret : orig;
+ }
+
+ // Set the width or height on the element
+ jQuery( elem ).css( type, value );
+ }, type, value, arguments.length, null );
+ };
+});
+
+
+
+
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+ define( "jquery", [], function () { return jQuery; } );
+}
+
+
+
+})( window );
diff --git a/WebContent/VAADIN/jquery.atmosphere.js b/WebContent/VAADIN/jquery.atmosphere.js
new file mode 100644
index 0000000000..e9def6ae95
--- /dev/null
+++ b/WebContent/VAADIN/jquery.atmosphere.js
@@ -0,0 +1,2731 @@
+/**
+ * Copyright 2012 Jeanfrancois Arcand
+ *
+ * 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.
+ */
+/*
+ * IE streaming/XDR supports is copied/highly inspired by http://code.google.com/p/jquery-stream/
+ *
+ * Copyright 2011, Donghwan Kim
+ * Licensed under the Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * LocalStorage supports is copied/highly inspired by https://github.com/flowersinthesand/jquery-socket
+ * Copyright 2011, Donghwan Kim
+ * Licensed under the Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * */
+/**
+ * Official documentation of this library: https://github.com/Atmosphere/atmosphere/wiki/jQuery.atmosphere.js-API
+ */
+jQuery.atmosphere = function() {
+ jQuery(window).bind("unload.atmosphere", function() {
+ jQuery.atmosphere.unsubscribe();
+ });
+
+ // Prevent ESC to kill the connection from Firefox.
+ jQuery(window).keypress(function(e){
+ if(e.keyCode == 27){
+ e.preventDefault();
+ }
+ });
+
+ var parseHeaders = function(headerString) {
+ var match, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, headers = {};
+ while (match = rheaders.exec(headerString)) {
+ headers[match[1]] = match[2];
+ }
+ return headers;
+ };
+
+ return {
+ version : "1.0.12",
+ requests : [],
+ callbacks : [],
+
+ onError : function(response) {
+ },
+ onClose : function(response) {
+ },
+ onOpen : function(response) {
+ },
+ onMessage : function(response) {
+ },
+ onReconnect : function(request, response) {
+ },
+ onMessagePublished : function(response) {
+ },
+ onTransportFailure : function (reason, request) {
+ },
+ onLocalMessage : function (response) {
+ },
+
+ AtmosphereRequest : function(options) {
+
+ /**
+ * {Object} Request parameters.
+ * @private
+ */
+ var _request = {
+ timeout: 300000,
+ method: 'GET',
+ headers: {},
+ contentType : '',
+ callback: null,
+ url : '',
+ data : '',
+ suspend : true,
+ maxRequest : -1,
+ reconnect : true,
+ maxStreamingLength : 10000000,
+ lastIndex : 0,
+ logLevel : 'info',
+ requestCount : 0,
+ fallbackMethod: 'GET',
+ fallbackTransport : 'streaming',
+ transport : 'long-polling',
+ webSocketImpl: null,
+ webSocketUrl: null,
+ webSocketPathDelimiter: "@@",
+ enableXDR : false,
+ rewriteURL : false,
+ attachHeadersAsQueryString : true,
+ executeCallbackBeforeReconnect : false,
+ readyState : 0,
+ lastTimestamp : 0,
+ withCredentials : false,
+ trackMessageLength : false ,
+ messageDelimiter : '|',
+ connectTimeout : -1,
+ reconnectInterval : 0,
+ dropAtmosphereHeaders : true,
+ uuid : 0,
+ shared : false,
+ readResponsesHeaders : true,
+ maxReconnectOnClose: 5,
+ enableProtocol: false,
+ onError : function(response) {
+ },
+ onClose : function(response) {
+ },
+ onOpen : function(response) {
+ },
+ onMessage : function(response) {
+ },
+ onReconnect : function(request, response) {
+ },
+ onMessagePublished : function(response) {
+ },
+ onTransportFailure : function (reason, request) {
+ },
+ onLocalMessage : function (request) {
+ }
+ };
+
+ /**
+ * {Object} Request's last response.
+ * @private
+ */
+ var _response = {
+ status: 200,
+ responseBody : '',
+ headers : [],
+ state : "messageReceived",
+ transport : "polling",
+ error: null,
+ request : null,
+ partialMessage : "",
+ id : 0
+ };
+
+ /**
+ * {websocket} Opened web socket.
+ *
+ * @private
+ */
+ var _websocket = null;
+
+ /**
+ * {SSE} Opened SSE.
+ *
+ * @private
+ */
+ var _sse = null;
+
+ /**
+ * {XMLHttpRequest, ActiveXObject} Opened ajax request (in case of
+ * http-streaming or long-polling)
+ *
+ * @private
+ */
+ var _activeRequest = null;
+
+ /**
+ * {Object} Object use for streaming with IE.
+ *
+ * @private
+ */
+ var _ieStream = null;
+
+ /**
+ * {Object} Object use for jsonp transport.
+ *
+ * @private
+ */
+ var _jqxhr = null;
+
+ /**
+ * {boolean} If request has been subscribed or not.
+ *
+ * @private
+ */
+ var _subscribed = true;
+
+ /**
+ * {number} Number of test reconnection.
+ *
+ * @private
+ */
+ var _requestCount = 0;
+
+ /**
+ * {boolean} If request is currently aborded.
+ *
+ * @private
+ */
+ var _abordingConnection = false;
+
+ /**
+ * A local "channel' of communication.
+ * @private
+ */
+ var _localSocketF = null;
+
+ /**
+ * The storage used.
+ * @private
+ */
+ var _storageService;
+
+ /**
+ * Local communication
+ * @private
+ */
+ var _localStorageService = null;
+
+ /**
+ * A Unique ID
+ * @private
+ */
+ var guid = jQuery.now();
+
+ /** Trace time */
+ var _traceTimer;
+
+ // Automatic call to subscribe
+ _subscribe(options);
+
+ /**
+ * Initialize atmosphere request object.
+ *
+ * @private
+ */
+ function _init() {
+ _subscribed = true;
+ _abordingConnection = false;
+ _requestCount = 0;
+
+ _websocket = null;
+ _sse = null;
+ _activeRequest = null;
+ _ieStream = null;
+ }
+
+ /**
+ * Re-initialize atmosphere object.
+ * @private
+ */
+ function _reinit() {
+ _clearState();
+ _init();
+ }
+
+ /**
+ * Subscribe request using request transport. <br>
+ * If request is currently opened, this one will be closed.
+ *
+ * @param {Object}
+ * Request parameters.
+ * @private
+ */
+ function _subscribe(options) {
+ _reinit();
+
+ _request = jQuery.extend(_request, options);
+ // Allow at least 1 request
+ _request.mrequest = _request.reconnect;
+ if (!_request.reconnect) {
+ _request.reconnect = true;
+ }
+ }
+
+ /**
+ * Check if web socket is supported (check for custom implementation
+ * provided by request object or browser implementation).
+ *
+ * @returns {boolean} True if web socket is supported, false
+ * otherwise.
+ * @private
+ */
+ function _supportWebsocket() {
+ return _request.webSocketImpl != null || window.WebSocket || window.MozWebSocket;
+ }
+
+ /**
+ * Check if server side events (SSE) is supported (check for custom implementation
+ * provided by request object or browser implementation).
+ *
+ * @returns {boolean} True if web socket is supported, false
+ * otherwise.
+ * @private
+ */
+ function _supportSSE() {
+ return window.EventSource;
+ }
+
+ /**
+ * Open request using request transport. <br>
+ * If request transport is 'websocket' but websocket can't be
+ * opened, request will automatically reconnect using fallback
+ * transport.
+ *
+ * @private
+ */
+ function _execute() {
+ // Shared across multiple tabs/windows.
+ if (_request.shared) {
+ _localStorageService = _local(_request);
+ if (_localStorageService != null) {
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Storage service available. All communication will be local");
+ }
+
+ if (_localStorageService.open(_request)) {
+ // Local connection.
+ return;
+ }
+ }
+
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("No Storage service available.");
+ }
+ // Wasn't local or an error occurred
+ _localStorageService = null;
+ }
+
+ // Protocol
+ _request.firstMessage= true;
+ _request.ctime = jQuery.now();
+
+ if (_request.transport != 'websocket' && _request.transport != 'sse') {
+ // Gives a chance to the connection to be established before calling the callback
+ setTimeout(function() {
+ _open('opening', _request.transport, _request);
+ }, 500);
+ _executeRequest();
+
+ } else if (_request.transport == 'websocket') {
+ if (!_supportWebsocket()) {
+ _reconnectWithFallbackTransport("Websocket is not supported, using request.fallbackTransport (" + _request.fallbackTransport + ")");
+ } else {
+ _executeWebSocket(false);
+ }
+ } else if (_request.transport == 'sse') {
+ if (!_supportSSE()) {
+ _reconnectWithFallbackTransport("Server Side Events(SSE) is not supported, using request.fallbackTransport (" + _request.fallbackTransport + ")");
+ } else {
+ _executeSSE(false);
+ }
+ }
+ }
+
+ function _local(request) {
+ var trace, connector, orphan, name = "atmosphere-" + request.url, connectors = {
+ storage: function() {
+ if (!jQuery.atmosphere.supportStorage()) {
+ return;
+ }
+
+ var storage = window.localStorage,
+ get = function(key) {
+ return jQuery.parseJSON(storage.getItem(name + "-" + key));
+ },
+ set = function(key, value) {
+ storage.setItem(name + "-" + key, jQuery.stringifyJSON(value));
+ };
+
+ return {
+ init: function() {
+ set("children", get("children").concat([guid]));
+ jQuery(window).on("storage.socket", function(event) {
+ event = event.originalEvent;
+ if (event.key === name && event.newValue) {
+ listener(event.newValue);
+ }
+ });
+ return get("opened");
+ },
+ signal: function(type, data) {
+ storage.setItem(name, jQuery.stringifyJSON({target: "p", type: type, data: data}));
+ },
+ close: function() {
+ var index, children = get("children");
+
+ jQuery(window).off("storage.socket");
+ if (children) {
+ index = jQuery.inArray(request.id, children);
+ if (index > -1) {
+ children.splice(index, 1);
+ set("children", children);
+ }
+ }
+ }
+ };
+ },
+ windowref: function() {
+ var win = window.open("", name.replace(/\W/g, ""));
+
+ if (!win || win.closed || !win.callbacks) {
+ return;
+ }
+
+ return {
+ init: function() {
+ win.callbacks.push(listener);
+ win.children.push(guid);
+ return win.opened;
+ },
+ signal: function(type, data) {
+ if (!win.closed && win.fire) {
+ win.fire(jQuery.stringifyJSON({target: "p", type: type, data: data}));
+ }
+ },
+ close : function() {
+ function remove(array, e) {
+ var index = jQuery.inArray(e, array);
+ if (index > -1) {
+ array.splice(index, 1);
+ }
+ }
+
+ // Removes traces only if the parent is alive
+ if (!orphan) {
+ remove(win.callbacks, listener);
+ remove(win.children, guid);
+ }
+ }
+
+ };
+ }
+ };
+
+ // Receives open, close and message command from the parent
+ function listener(string) {
+ var command = jQuery.parseJSON(string), data = command.data;
+
+ if (command.target === "c") {
+ switch (command.type) {
+ case "open":
+ _open("opening", 'local', _request)
+ break;
+ case "close":
+ if (!orphan) {
+ orphan = true;
+ if (data.reason === "aborted") {
+ _close();
+ } else {
+ // Gives the heir some time to reconnect
+ if (data.heir === guid) {
+ _execute();
+ } else {
+ setTimeout(function() {
+ _execute();
+ }, 100);
+ }
+ }
+ }
+ break;
+ case "message":
+ _prepareCallback(data, "messageReceived", 200, request.transport);
+ break;
+ case "localMessage":
+ _localMessage(data);
+ break;
+ }
+ }
+ }
+
+ function findTrace() {
+ var matcher = new RegExp("(?:^|; )(" + encodeURIComponent(name) + ")=([^;]*)").exec(document.cookie);
+ if (matcher) {
+ return jQuery.parseJSON(decodeURIComponent(matcher[2]));
+ }
+ }
+
+ // Finds and validates the parent socket's trace from the cookie
+ trace = findTrace();
+ if (!trace || jQuery.now() - trace.ts > 1000) {
+ return;
+ }
+
+ // Chooses a connector
+ connector = connectors.storage() || connectors.windowref();
+ if (!connector) {
+ return;
+ }
+
+ return {
+ open: function() {
+ var parentOpened;
+
+ // Checks the shared one is alive
+ _traceTimer = setInterval(function() {
+ var oldTrace = trace;
+ trace = findTrace();
+ if (!trace || oldTrace.ts === trace.ts) {
+ // Simulates a close signal
+ listener(jQuery.stringifyJSON({target: "c", type: "close", data: {reason: "error", heir: oldTrace.heir}}));
+ }
+ }, 1000);
+
+ parentOpened = connector.init();
+ if (parentOpened) {
+ // Firing the open event without delay robs the user of the opportunity to bind connecting event handlers
+ setTimeout(function() {
+ _open("opening", 'local', request)
+ }, 50);
+ }
+ return parentOpened;
+ },
+ send: function(event) {
+ connector.signal("send", event);
+ },
+ localSend: function(event) {
+ connector.signal("localSend", jQuery.stringifyJSON({id: guid , event: event}));
+ },
+ close: function() {
+ // Do not signal the parent if this method is executed by the unload event handler
+ if (!_abordingConnection) {
+ clearInterval(_traceTimer);
+ connector.signal("close");
+ connector.close();
+ }
+ }
+ };
+ };
+
+ function share() {
+ var storageService, name = "atmosphere-" + _request.url, servers = {
+ // Powered by the storage event and the localStorage
+ // http://www.w3.org/TR/webstorage/#event-storage
+ storage: function() {
+ if (!jQuery.atmosphere.supportStorage()) {
+ return;
+ }
+
+ var storage = window.localStorage;
+
+ return {
+ init: function() {
+ // Handles the storage event
+ jQuery(window).on("storage.socket", function(event) {
+ event = event.originalEvent;
+ // When a deletion, newValue initialized to null
+ if (event.key === name && event.newValue) {
+ listener(event.newValue);
+ }
+ });
+ },
+ signal: function(type, data) {
+ storage.setItem(name, jQuery.stringifyJSON({target: "c", type: type, data: data}));
+ },
+ get: function(key) {
+ return jQuery.parseJSON(storage.getItem(name + "-" + key));
+ },
+ set: function(key, value) {
+ storage.setItem(name + "-" + key, jQuery.stringifyJSON(value));
+ },
+ close : function() {
+ jQuery(window).off("storage.socket");
+ storage.removeItem(name);
+ storage.removeItem(name + "-opened");
+ storage.removeItem(name + "-children");
+ }
+
+ };
+ },
+ // Powered by the window.open method
+ // https://developer.mozilla.org/en/DOM/window.open
+ windowref: function() {
+ // Internet Explorer raises an invalid argument error
+ // when calling the window.open method with the name containing non-word characters
+ var neim = name.replace(/\W/g, ""), win = (jQuery('iframe[name="' + neim + '"]')[0]
+ || jQuery('<iframe name="' + neim + '" />').hide().appendTo("body")[0]).contentWindow;
+
+ return {
+ init: function() {
+ // Callbacks from different windows
+ win.callbacks = [listener];
+ // In IE 8 and less, only string argument can be safely passed to the function in other window
+ win.fire = function(string) {
+ var i;
+
+ for (i = 0; i < win.callbacks.length; i++) {
+ win.callbacks[i](string);
+ }
+ };
+ },
+ signal: function(type, data) {
+ if (!win.closed && win.fire) {
+ win.fire(jQuery.stringifyJSON({target: "c", type: type, data: data}));
+ }
+ },
+ get: function(key) {
+ return !win.closed ? win[key] : null;
+ },
+ set: function(key, value) {
+ if (!win.closed) {
+ win[key] = value;
+ }
+ },
+ close : function() {}
+ };
+ }
+ };
+
+
+ // Receives send and close command from the children
+ function listener(string) {
+ var command = jQuery.parseJSON(string), data = command.data;
+
+ if (command.target === "p") {
+ switch (command.type) {
+ case "send":
+ _push(data);
+ break;
+ case "localSend":
+ _localMessage(data);
+ break;
+ case "close":
+ _close();
+ break;
+ }
+ }
+ }
+
+ _localSocketF = function propagateMessageEvent(context) {
+ storageService.signal("message", context);
+ }
+
+ function leaveTrace() {
+ document.cookie = encodeURIComponent(name) + "=" +
+ // Opera's JSON implementation ignores a number whose a last digit of 0 strangely
+ // but has no problem with a number whose a last digit of 9 + 1
+ encodeURIComponent(jQuery.stringifyJSON({ts: jQuery.now() + 1, heir: (storageService.get("children") || [])[0]}));
+ }
+
+ // Chooses a storageService
+ storageService = servers.storage() || servers.windowref();
+ storageService.init();
+
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Installed StorageService " + storageService);
+ }
+
+ // List of children sockets
+ storageService.set("children", []);
+
+ if (storageService.get("opened") != null && !storageService.get("opened")) {
+ // Flag indicating the parent socket is opened
+ storageService.set("opened", false);
+ }
+ // Leaves traces
+ leaveTrace();
+ _traceTimer = setInterval(leaveTrace, 1000);
+
+ _storageService = storageService;
+ }
+
+ /**
+ * @private
+ */
+ function _open(state, transport, request) {
+ if (_request.shared && transport != 'local') {
+ share();
+ }
+
+ if (_storageService != null) {
+ _storageService.set("opened", true);
+ }
+
+ request.close = function() {
+ _close();
+ };
+
+ _response.request = request;
+ var prevState = _response.state;
+ _response.state = state;
+ _response.status = 200;
+ var prevTransport = _response.transport;
+ _response.transport = transport;
+
+ var _body = _response.responseBody;
+ _invokeCallback();
+ _response.responseBody = _body;
+
+ _response.state = prevState;
+ _response.transport = prevTransport;
+ }
+
+ /**
+ * Execute request using jsonp transport.
+ *
+ * @param request
+ * {Object} request Request parameters, if
+ * undefined _request object will be used.
+ * @private
+ */
+ function _jsonp(request) {
+ // When CORS is enabled, make sure we force the proper transport.
+ request.transport="jsonp";
+
+ var rq = _request;
+ if ((request != null) && (typeof(request) != 'undefined')) {
+ rq = request;
+ }
+
+ var url = rq.url;
+ var data = rq.data;
+ if (rq.attachHeadersAsQueryString) {
+ url = _attachHeaders(rq);
+ if (data != '') {
+ url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(data);
+ }
+ data = '';
+ }
+
+ _jqxhr = jQuery.ajax({
+ url : url,
+ type : rq.method,
+ dataType: "jsonp",
+ error : function(jqXHR, textStatus, errorThrown) {
+ if (jqXHR.status < 300) {
+ _reconnect(_jqxhr, rq);
+ } else {
+ _prepareCallback(textStatus, "error", jqXHR.status, rq.transport);
+ }
+ },
+ jsonp : "jsonpTransport",
+ success: function(json) {
+
+ if (rq.reconnect && (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) {
+ _readHeaders(_jqxhr, rq);
+
+ if (!rq.executeCallbackBeforeReconnect) {
+ _reconnect(_jqxhr, rq);
+ }
+
+ var msg = json.message;
+ if (msg != null && typeof msg != 'string') {
+ try {
+ msg = jQuery.stringifyJSON(msg);
+ } catch (err) {
+ // The message was partial
+ }
+ }
+
+ if (_handleProtocol(rq, msg)) {
+ _prepareCallback(msg, "messageReceived", 200, rq.transport);
+ }
+
+ if (rq.executeCallbackBeforeReconnect) {
+ _reconnect(_jqxhr, rq);
+ }
+ } else {
+ jQuery.atmosphere.log(_request.logLevel, ["JSONP reconnect maximum try reached " + _request.requestCount]);
+ _onError();
+ }
+ },
+ data : rq.data,
+ beforeSend : function(jqXHR) {
+ _doRequest(jqXHR, rq, false);
+ }
+ });
+ }
+
+ /**
+ * Execute request using ajax transport.
+ *
+ * @param request
+ * {Object} request Request parameters, if
+ * undefined _request object will be used.
+ * @private
+ */
+ function _ajax(request) {
+ var rq = _request;
+ if ((request != null) && (typeof(request) != 'undefined')) {
+ rq = request;
+ }
+
+ var url = rq.url;
+ var data = rq.data;
+ if (rq.attachHeadersAsQueryString) {
+ url = _attachHeaders(rq);
+ if (data != '') {
+ url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(data);
+ }
+ data = '';
+ }
+
+ var async = typeof(rq.async) != 'undefined' ? rq.async : true;
+ _jqxhr = jQuery.ajax({
+ url : url,
+ type : rq.method,
+ error : function(jqXHR, textStatus, errorThrown) {
+ if (jqXHR.status < 300) {
+ _reconnect(_jqxhr, rq);
+ } else {
+ _prepareCallback(textStatus, "error", jqXHR.status, rq.transport);
+ }
+ },
+ success: function(data, textStatus, jqXHR) {
+
+ if (rq.reconnect && (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) {
+ if (!rq.executeCallbackBeforeReconnect) {
+ _reconnect(_jqxhr, rq);
+ }
+
+ if (_handleProtocol(rq, data)) {
+ _prepareCallback(data, "messageReceived", 200, rq.transport);
+ }
+
+ if (rq.executeCallbackBeforeReconnect) {
+ _reconnect(_jqxhr, rq);
+ }
+ } else {
+ jQuery.atmosphere.log(_request.logLevel, ["AJAX reconnect maximum try reached " + _request.requestCount]);
+ _onError();
+ }
+ },
+ beforeSend : function(jqXHR) {
+ _doRequest(jqXHR, rq, false);
+ },
+ crossDomain : rq.enableXDR,
+ async: async
+ });
+ }
+
+ /**
+ * Build websocket object.
+ *
+ * @param location
+ * {string} Web socket url.
+ * @returns {websocket} Web socket object.
+ * @private
+ */
+ function _getWebSocket(location) {
+ if (_request.webSocketImpl != null) {
+ return _request.webSocketImpl;
+ } else {
+ if (window.WebSocket) {
+ return new WebSocket(location);
+ } else {
+ return new MozWebSocket(location);
+ }
+ }
+ }
+
+ /**
+ * Build web socket url from request url.
+ *
+ * @return {string} Web socket url (start with "ws" or "wss" for
+ * secure web socket).
+ * @private
+ */
+ function _buildWebSocketUrl() {
+ var url = _attachHeaders(_request);
+
+ return decodeURI(jQuery('<a href="' + url + '"/>')[0].href.replace(/^http/, "ws"));
+ }
+
+ /**
+ * Build SSE url from request url.
+ *
+ * @return a url with Atmosphere's headers
+ * @private
+ */
+ function _buildSSEUrl() {
+ var url = _attachHeaders(_request);
+ return url;
+ }
+
+ /**
+ * Open SSE. <br>
+ * Automatically use fallback transport if SSE can't be
+ * opened.
+ *
+ * @private
+ */
+ function _executeSSE(sseOpened) {
+
+ _response.transport = "sse";
+
+ var location = _buildSSEUrl(_request.url);
+
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Invoking executeSSE");
+ jQuery.atmosphere.debug("Using URL: " + location);
+ }
+
+ if (sseOpened) {
+ _open('re-opening', "sse", _request);
+ }
+
+ if (_request.enableProtocol && sseOpened) {
+ var time = jQuery.now() - _request.ctime;
+ _request.lastTimestamp = Number(_request.stime) + Number(time);
+ }
+
+ if (sseOpened && !_request.reconnect) {
+ if (_sse != null) {
+ _clearState();
+ }
+ return;
+ }
+ _sse = new EventSource(location, {withCredentials: _request.withCredentials});
+
+ if (_request.connectTimeout > 0) {
+ _request.id = setTimeout(function() {
+ if (!sseOpened) {
+ _clearState();
+ }
+ }, _request.connectTimeout);
+ }
+
+ _sse.onopen = function(event) {
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("SSE successfully opened");
+ }
+
+ if (!sseOpened) {
+ _open('opening', "sse", _request);
+ }
+ sseOpened = true;
+
+ if (_request.method == 'POST') {
+ _response.state = "messageReceived";
+ _sse.send(_request.data);
+ }
+ };
+
+ _sse.onmessage = function(message) {
+ if (message.origin != window.location.protocol + "//" + window.location.host) {
+ jQuery.atmosphere.log(_request.logLevel, ["Origin was not " + window.location.protocol + "//" + window.location.host]);
+ return;
+ }
+
+ if (!_handleProtocol(_request, message.data)) return;
+
+ _response.state = 'messageReceived';
+ _response.status = 200;
+
+ var message = message.data;
+ var skipCallbackInvocation = _trackMessageSize(message, _request, _response);
+
+ if (jQuery.trim(message).length == 0) {
+ skipCallbackInvocation = true;
+ }
+
+ if (!skipCallbackInvocation) {
+ _invokeCallback();
+ _response.responseBody = '';
+ }
+ };
+
+ _sse.onerror = function(message) {
+
+ clearTimeout(_request.id);
+ _response.state = 'closed';
+ _response.responseBody = "";
+ _response.status = !sseOpened ? 501 : 200;
+ _invokeCallback();
+ _clearState();
+
+ if (_abordingConnection) {
+ jQuery.atmosphere.log(_request.logLevel, ["SSE closed normally"]);
+ } else if (!sseOpened) {
+ _reconnectWithFallbackTransport("SSE failed. Downgrading to fallback transport and resending");
+ } else if (_request.reconnect && (_response.transport == 'sse')) {
+ if (_requestCount++ < _request.maxReconnectOnClose) {
+ _request.id = setTimeout(function() {
+ _executeSSE(true);
+ }, _request.reconnectInterval);
+ _response.responseBody = "";
+ } else {
+ jQuery.atmosphere.log(_request.logLevel, ["SSE reconnect maximum try reached " + _requestCount]);
+ _onError();
+ }
+ }
+ };
+ }
+
+ /**
+ * Open web socket. <br>
+ * Automatically use fallback transport if web socket can't be
+ * opened.
+ *
+ * @private
+ */
+ function _executeWebSocket(webSocketOpened) {
+
+ _response.transport = "websocket";
+
+ if (_request.enableProtocol && webSocketOpened) {
+ var time = jQuery.now() - _request.ctime;
+ _request.lastTimestamp = Number(_request.stime) + Number(time);
+ }
+
+ var location = _buildWebSocketUrl(_request.url);
+ var closed = false;
+
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Invoking executeWebSocket");
+ jQuery.atmosphere.debug("Using URL: " + location);
+ }
+
+ if (webSocketOpened) {
+ _open('re-opening', "websocket", _request);
+ }
+
+ if (webSocketOpened && !_request.reconnect) {
+ if (_websocket != null) {
+ _clearState();
+ }
+ return;
+ }
+
+ _websocket = _getWebSocket(location);
+
+ if (_request.connectTimeout > 0) {
+ _request.id = setTimeout(function() {
+ if (!webSocketOpened) {
+ var _message = {
+ code : 1002,
+ reason : "",
+ wasClean : false
+ };
+ _websocket.onclose(_message);
+ // Close it anyway
+ try {
+ _clearState();
+ } catch (e) {
+ }
+ return;
+ }
+
+ }, _request.connectTimeout);
+ }
+
+ _request.id = setTimeout(function() {
+ setTimeout(function () {
+ _clearState();
+ }, _request.reconnectInterval)
+ }, _request.timeout);
+
+ _websocket.onopen = function(message) {
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Websocket successfully opened");
+ }
+
+ if (!webSocketOpened) {
+ _open('opening', "websocket", _request);
+ }
+
+ webSocketOpened = true;
+
+ if (_request.method == 'POST') {
+ _response.state = "messageReceived";
+ _websocket.send(_request.data);
+ }
+ };
+
+ _websocket.onmessage = function(message) {
+
+ clearTimeout(_request.id);
+ _request.id = setTimeout(function() {
+ setTimeout(function () {
+ _clearState();
+ }, _request.reconnectInterval)
+ }, _request.timeout);
+
+ if (!_handleProtocol(_request, message.data)) return;
+
+ _response.state = 'messageReceived';
+ _response.status = 200;
+
+ var message = message.data;
+ var skipCallbackInvocation = _trackMessageSize(message, _request, _response);
+
+ if (!skipCallbackInvocation) {
+ _invokeCallback();
+ _response.responseBody = '';
+ }
+ };
+
+ _websocket.onerror = function(message) {
+ clearTimeout(_request.id)
+ };
+
+ _websocket.onclose = function(message) {
+ if (closed) return
+
+ var reason = message.reason;
+ if (reason === "") {
+ switch (message.code) {
+ case 1000:
+ reason = "Normal closure; the connection successfully completed whatever purpose for which " +
+ "it was created.";
+ break;
+ case 1001:
+ reason = "The endpoint is going away, either because of a server failure or because the " +
+ "browser is navigating away from the page that opened the connection.";
+ break;
+ case 1002:
+ reason = "The endpoint is terminating the connection due to a protocol error.";
+ break;
+ case 1003:
+ reason = "The connection is being terminated because the endpoint received data of a type it " +
+ "cannot accept (for example, a text-only endpoint received binary data).";
+ break;
+ case 1004:
+ reason = "The endpoint is terminating the connection because a data frame was received that " +
+ "is too large.";
+ break;
+ case 1005:
+ reason = "Unknown: no status code was provided even though one was expected.";
+ break;
+ case 1006:
+ reason = "Connection was closed abnormally (that is, with no close frame being sent).";
+ break;
+ }
+ }
+
+ jQuery.atmosphere.warn("Websocket closed, reason: " + reason);
+ jQuery.atmosphere.warn("Websocket closed, wasClean: " + message.wasClean);
+
+ _response.state = 'closed';
+ _response.responseBody = "";
+ _response.status = !webSocketOpened ? 501 : 200;
+ _invokeCallback();
+ clearTimeout(_request.id);
+
+ closed = true;
+
+ if (_abordingConnection) {
+ jQuery.atmosphere.log(_request.logLevel, ["Websocket closed normally"]);
+ } else if (!webSocketOpened) {
+ _reconnectWithFallbackTransport("Websocket failed. Downgrading to Comet and resending");
+
+ } else if (_request.reconnect && _response.transport == 'websocket') {
+ _clearState();
+ if (_request.reconnect && _requestCount++ < _request.maxReconnectOnClose) {
+ _request.id = setTimeout(function() {
+ _response.responseBody = "";
+ _executeWebSocket(true);
+ }, _request.reconnectInterval);
+ } else {
+ jQuery.atmosphere.log(_request.logLevel, ["Websocket reconnect maximum try reached " + _requestCount]);
+ jQuery.atmosphere.warn("Websocket error, reason: " + message.reason);
+ _onError();
+ }
+ }
+ };
+ }
+
+ function _handleProtocol(request, message) {
+ // The first messages is always the uuid.
+ if (request.enableProtocol && request.firstMessage) {
+ request.firstMessage = false;
+ var messages = message.split(request.messageDelimiter);
+ request.uuid = messages[0];
+ request.stime = messages[1];
+ return false;
+ }
+ return true;
+ }
+
+ function _onError() {
+ _clearState();
+
+ _response.state = 'error';
+ _response.responseBody = "";
+ _response.status = 500;
+ _invokeCallback();
+ }
+
+ /**
+ * Track received message and make sure callbacks/functions are only invoked when the complete message
+ * has been received.
+ *
+ * @param message
+ * @param request
+ * @param response
+ */
+ function _trackMessageSize(message, request, response) {
+ if (request.trackMessageLength) {
+
+ // If we have found partial message, prepend them.
+ if (response.partialMessage.length != 0) {
+ message = response.partialMessage + message;
+ }
+
+ var messages = [];
+ var messageLength = 0;
+ var messageStart = message.indexOf(request.messageDelimiter);
+ while (messageStart != -1) {
+ messageLength = message.substring(messageLength, messageStart);
+ message = message.substring(messageStart + request.messageDelimiter.length, message.length);
+
+ if (message.length == 0 || message.length < messageLength) break;
+
+ messageStart = message.indexOf(request.messageDelimiter);
+ messages.push(message.substring(0, messageLength));
+ }
+
+ if (messages.length == 0 || (messageStart != -1 && message.length != 0 && messageLength != message.length)){
+ response.partialMessage = messageLength + request.messageDelimiter + message ;
+ } else {
+ response.partialMessage = "";
+ }
+
+ if (messages.length != 0) {
+ response.responseBody = messages.join(request.messageDelimiter);
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ response.responseBody = message;
+ }
+ return false;
+ }
+
+ /**
+ * Reconnect request with fallback transport. <br>
+ * Used in case websocket can't be opened.
+ *
+ * @private
+ */
+ function _reconnectWithFallbackTransport(errorMessage) {
+ jQuery.atmosphere.log(_request.logLevel, [errorMessage]);
+
+ if (typeof(_request.onTransportFailure) != 'undefined') {
+ _request.onTransportFailure(errorMessage, _request);
+ } else if (typeof(jQuery.atmosphere.onTransportFailure) != 'undefined') {
+ jQuery.atmosphere.onTransportFailure(errorMessage, _request);
+ }
+
+ _request.transport = _request.fallbackTransport;
+ var reconnect = _request.reconnect && _requestCount++ < _request.maxReconnectOnClose;
+ if (reconnect && _request.transport != 'none' || _request.transport == null) {
+ _request.method = _request.fallbackMethod;
+ _response.transport = _request.fallbackTransport;
+ _request.id = setTimeout(function() {
+ _execute();
+ }, _request.reconnectInterval);
+ } else if (!reconnect) {
+ _onError();
+ }
+ }
+
+ /**
+ * Get url from request and attach headers to it.
+ *
+ * @param request
+ * {Object} request Request parameters, if
+ * undefined _request object will be used.
+ *
+ * @returns {Object} Request object, if undefined,
+ * _request object will be used.
+ * @private
+ */
+ function _attachHeaders(request) {
+ var rq = _request;
+ if ((request != null) && (typeof(request) != 'undefined')) {
+ rq = request;
+ }
+
+ var url = rq.url;
+
+ // If not enabled
+ if (!rq.attachHeadersAsQueryString) return url;
+
+ // If already added
+ if (url.indexOf("X-Atmosphere-Framework") != -1) {
+ return url;
+ }
+
+ url += (url.indexOf('?') != -1) ? '&' : '?';
+ url += "X-Atmosphere-tracking-id=" + rq.uuid;
+ url += "&X-Atmosphere-Framework=" + jQuery.atmosphere.version;
+ url += "&X-Atmosphere-Transport=" + rq.transport;
+
+ if (rq.trackMessageLength) {
+ url += "&X-Atmosphere-TrackMessageSize=" + "true";
+ }
+
+ if (rq.lastTimestamp != undefined) {
+ url += "&X-Cache-Date=" + rq.lastTimestamp;
+ } else {
+ url += "&X-Cache-Date=" + 0;
+ }
+
+ if (rq.contentType != '') {
+ url += "&Content-Type=" + rq.contentType;
+ }
+
+ if (rq.enableProtocol) {
+ url += "&X-atmo-protocol=true";
+ }
+
+ jQuery.each(rq.headers, function(name, value) {
+ var h = jQuery.isFunction(value) ? value.call(this, rq, request, _response) : value;
+ if (h != null) {
+ url += "&" + encodeURIComponent(name) + "=" + encodeURIComponent(h);
+ }
+ });
+
+ return url;
+ }
+
+ /**
+ * Build ajax request. <br>
+ * Ajax Request is an XMLHttpRequest object, except for IE6 where
+ * ajax request is an ActiveXObject.
+ *
+ * @return {XMLHttpRequest, ActiveXObject} Ajax request.
+ * @private
+ */
+ function _buildAjaxRequest() {
+ if (jQuery.browser.msie) {
+ if (typeof XMLHttpRequest == "undefined")
+ XMLHttpRequest = function () {
+ try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
+ catch (e) {}
+ try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
+ catch (e) {}
+ try { return new ActiveXObject("Microsoft.XMLHTTP"); }
+ catch (e) {}
+ //Microsoft.XMLHTTP points to Msxml2.XMLHTTP and is redundant
+ throw new Error("This browser does not support XMLHttpRequest.");
+ };
+ }
+ return new XMLHttpRequest();
+ }
+
+ /**
+ * Execute ajax request. <br>
+ *
+ * @param request
+ * {Object} request Request parameters, if
+ * undefined _request object will be used.
+ * @private
+ */
+ function _executeRequest(request) {
+ var rq = _request;
+ if ((request != null) || (typeof(request) != 'undefined')) {
+ rq = request;
+ }
+
+ // CORS fake using JSONP
+ if ((rq.transport == 'jsonp') || ((rq.enableXDR) && (jQuery.atmosphere.checkCORSSupport()))) {
+ _jsonp(rq);
+ return;
+ }
+
+ if (rq.transport == 'ajax') {
+ _ajax(request);
+ return;
+ }
+
+ if (jQuery.browser.msie && jQuery.browser.version < 10) {
+ if ((rq.transport == 'streaming')) {
+ rq.enableXDR && window.XDomainRequest ? _ieXDR(rq) : _ieStreaming(rq);
+ return;
+ }
+
+ if ((rq.enableXDR) && (window.XDomainRequest)) {
+ _ieXDR(rq);
+ return;
+ }
+ }
+
+ if (rq.reconnect && ( rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest)) {
+ var ajaxRequest = _buildAjaxRequest();
+ _doRequest(ajaxRequest, rq, true);
+
+ if (rq.suspend) {
+ _activeRequest = ajaxRequest;
+ }
+
+ if (rq.transport != 'polling') {
+ _response.transport = rq.transport;
+ }
+
+ if (!jQuery.browser.msie) {
+ ajaxRequest.onerror = function() {
+ try {
+ _response.status = XMLHttpRequest.status;
+ } catch(e) {
+ _response.status = 500;
+ }
+
+ if (!_response.status) {
+ _response.status = 500;
+ }
+ _clearState();
+
+ if (rq.reconnect) {
+ _reconnect(ajaxRequest, rq, true);
+ } else {
+ _onError();
+ }
+ };
+ }
+
+ ajaxRequest.onreadystatechange = function() {
+ if (_abordingConnection) {
+ return;
+ }
+
+ var skipCallbackInvocation = false;
+ var update = false;
+
+ // Remote server disconnected us, reconnect.
+ if (rq.transport == 'streaming'
+ && rq.readyState > 2
+ && ajaxRequest.readyState == 4) {
+
+ rq.readyState = 0;
+ rq.lastIndex = 0;
+
+ _reconnect(ajaxRequest, rq, true);
+ return;
+ }
+
+ rq.readyState = ajaxRequest.readyState;
+
+ if (ajaxRequest.readyState == 4) {
+ if (jQuery.browser.msie) {
+ update = true;
+ } else if (rq.transport == 'streaming') {
+ update = true;
+ } else if (rq.transport == 'long-polling') {
+ update = true;
+ clearTimeout(rq.id);
+ }
+ } else if (rq.transport == 'streaming' && jQuery.browser.msie && ajaxRequest.readyState >= 3) {
+ update = true;
+ } else if (!jQuery.browser.msie && ajaxRequest.readyState == 3 && ajaxRequest.status == 200 && rq.transport != 'long-polling') {
+ update = true;
+ } else {
+ clearTimeout(rq.id);
+ }
+
+ if (update) {
+ var responseText = ajaxRequest.responseText;
+
+ // MSIE status can be higher than 1000, Chrome can be 0
+ if (ajaxRequest.status >= 500 || ajaxRequest.status == 0) {
+ if (rq.reconnect) {
+ _reconnect(ajaxRequest, rq, true);
+ } else {
+ _onError();
+ }
+ return;
+ }
+
+ _readHeaders(ajaxRequest, _request);
+
+ if (rq.transport == 'streaming') {
+ var text = responseText.substring(rq.lastIndex, responseText.length);
+ _response.isJunkEnded = true;
+
+ //fix junk is comming in parts
+ if (!_response.junkFull && (text.indexOf("<!-- Welcome to the Atmosphere Framework.") == -1 || text.indexOf("<!-- EOD -->") == -1)) {
+ return;
+ }
+ _response.junkFull = true;
+
+ //if it's the start and we see the junk start
+ //fix for reconnecting on chrome - junk is comming in parts
+ if (rq.lastIndex == 0 && text.indexOf("<!-- Welcome to the Atmosphere Framework.") != -1 && text.indexOf("<!-- EOD -->") != -1) {
+ _response.isJunkEnded = false;
+ }
+
+ if (!_response.isJunkEnded) {
+ var endOfJunk = "<!-- EOD -->";
+ var endOfJunkLength = endOfJunk.length;
+ var junkEnd = text.indexOf(endOfJunk) + endOfJunkLength;
+
+ if (junkEnd > endOfJunkLength && junkEnd != text.length) {
+ _response.responseBody = text.substring(junkEnd);
+ rq.lastIndex = responseText.length;
+ if (!_handleProtocol( _request, _response.responseBody)) {
+ return;
+ }
+ skipCallbackInvocation = _trackMessageSize(_response.responseBody, rq, _response);
+ } else {
+ skipCallbackInvocation = true;
+ }
+ } else {
+ var message = responseText.substring(rq.lastIndex, responseText.length);
+ rq.lastIndex = responseText.length;
+ if (!_handleProtocol( _request, message)) {
+ return;
+ }
+ skipCallbackInvocation = _trackMessageSize(message, rq, _response);
+ }
+ rq.lastIndex = responseText.length;
+
+ if (jQuery.browser.opera) {
+ jQuery.atmosphere.iterate(function() {
+ if (ajaxRequest.responseText.length > rq.lastIndex) {
+ try {
+ _response.status = ajaxRequest.status;
+ _response.headers = parseHeaders(ajaxRequest.getAllResponseHeaders());
+
+ _readHeaders(ajaxRequest, _request);
+ }
+ catch(e) {
+ _response.status = 404;
+ }
+ _response.state = "messageReceived";
+ _response.responseBody = ajaxRequest.responseText.substring(rq.lastIndex);
+ rq.lastIndex = ajaxRequest.responseText.length;
+
+ if (!_handleProtocol( _request, _response.responseBody)) {
+ _reconnect(ajaxRequest, rq, false);
+ return;
+ }
+ _invokeCallback();
+ if ((rq.transport == 'streaming') && (ajaxRequest.responseText.length > rq.maxStreamingLength)) {
+ // Close and reopen connection on large data received
+ _clearState();
+ _doRequest(_buildAjaxRequest(), rq, true);
+ }
+ }
+ }, 0);
+ }
+
+ if (skipCallbackInvocation) {
+ return;
+ }
+ } else {
+ if (!_handleProtocol( _request, responseText)) {
+ _reconnect(ajaxRequest, rq, false);
+ return;
+ }
+
+ _trackMessageSize(responseText, rq, _response);
+ rq.lastIndex = responseText.length;
+ }
+
+ try {
+ _response.status = ajaxRequest.status;
+ _response.headers = parseHeaders(ajaxRequest.getAllResponseHeaders());
+
+ _readHeaders(ajaxRequest, rq);
+ } catch(e) {
+ _response.status = 404;
+ }
+
+ if (rq.suspend) {
+ _response.state = _response.status == 0 ? "closed" : "messageReceived";
+ } else {
+ _response.state = "messagePublished";
+ }
+
+ if (!rq.executeCallbackBeforeReconnect) {
+ _reconnect(ajaxRequest, rq, false);
+ }
+
+ // For backward compatibility with Atmosphere < 0.8
+ if (_response.responseBody.indexOf("parent.callback") != -1) {
+ jQuery.atmosphere.log(rq.logLevel, ["parent.callback no longer supported with 0.8 version and up. Please upgrade"]);
+ }
+
+ _invokeCallback();
+
+ if (rq.executeCallbackBeforeReconnect) {
+ _reconnect(ajaxRequest, rq, false);
+ }
+
+ if ((rq.transport == 'streaming') && (responseText.length > rq.maxStreamingLength)) {
+ // Close and reopen connection on large data received
+ _clearState();
+ _doRequest(_buildAjaxRequest(), rq, true);
+ }
+ }
+ };
+ ajaxRequest.send(rq.data);
+
+ if (rq.suspend) {
+ rq.id = setTimeout(function() {
+ if (_subscribed) {
+ setTimeout(function () {
+ _clearState();
+ _executeRequest(rq);
+ }, rq.reconnectInterval)
+ }
+ }, rq.timeout);
+ }
+ _subscribed = true;
+
+ } else {
+ if (rq.logLevel == 'debug') {
+ jQuery.atmosphere.log(rq.logLevel, ["Max re-connection reached."]);
+ }
+ _onError();
+ }
+ }
+
+ /**
+ * Do ajax request.
+ * @param ajaxRequest Ajax request.
+ * @param request Request parameters.
+ * @param create If ajax request has to be open.
+ */
+ function _doRequest(ajaxRequest, request, create) {
+ // Prevent Android to cache request
+ var url = _attachHeaders(request);
+ url = jQuery.atmosphere.prepareURL(url);
+
+ if (create) {
+ ajaxRequest.open(request.method, url, true);
+ if (request.connectTimeout > -1) {
+ request.id = setTimeout(function() {
+ if (request.requestCount == 0) {
+ _clearState();
+ _prepareCallback("Connect timeout", "closed", 200, request.transport);
+ }
+ }, request.connectTimeout);
+ }
+ }
+
+ if (_request.withCredentials) {
+ if ("withCredentials" in ajaxRequest) {
+ ajaxRequest.withCredentials = true;
+ }
+ }
+
+ if (!_request.dropAtmosphereHeaders) {
+ ajaxRequest.setRequestHeader("X-Atmosphere-Framework", jQuery.atmosphere.version);
+ ajaxRequest.setRequestHeader("X-Atmosphere-Transport", request.transport);
+ if (request.lastTimestamp != undefined) {
+ ajaxRequest.setRequestHeader("X-Cache-Date", request.lastTimestamp);
+ } else {
+ ajaxRequest.setRequestHeader("X-Cache-Date", 0);
+ }
+
+ if (request.trackMessageLength) {
+ ajaxRequest.setRequestHeader("X-Atmosphere-TrackMessageSize", "true")
+ }
+
+ if (request.contentType != '') {
+ ajaxRequest.setRequestHeader("Content-Type", request.contentType);
+ }
+ ajaxRequest.setRequestHeader("X-Atmosphere-tracking-id", request.uuid);
+ }
+
+ jQuery.each(request.headers, function(name, value) {
+ var h = jQuery.isFunction(value) ? value.call(this, ajaxRequest, request, create, _response) : value;
+ if (h != null) {
+ ajaxRequest.setRequestHeader(name, h);
+ }
+ });
+ }
+
+ function _reconnect(ajaxRequest, request, force) {
+ var reconnect = request.reconnect && _requestCount++ < request.maxReconnectOnClose;
+
+ if (reconnect && force || (request.suspend && ajaxRequest.status == 200 && request.transport != 'streaming' && _subscribed)) {
+ if (request.reconnect) {
+ _open('re-opening', request.transport, request);
+ request.id = setTimeout(function() {
+ _executeRequest();
+ }, request.reconnectInterval);
+ }
+ } else if (!reconnect) {
+ _onError();
+ }
+ }
+
+ // From jquery-stream, which is APL2 licensed as well.
+ function _ieXDR(request) {
+ if (request.transport != "polling") {
+ _ieStream = _configureXDR(request);
+ _ieStream.open();
+ } else {
+ _configureXDR(request).open();
+ }
+ }
+
+ // From jquery-stream
+ function _configureXDR(request) {
+ var rq = _request;
+ if ((request != null) && (typeof(request) != 'undefined')) {
+ rq = request;
+ }
+
+ var transport = rq.transport;
+ var lastIndex = 0;
+ var xdrCallback = function (xdr) {
+ var responseBody = xdr.responseText;
+ var isJunkEnded = false;
+
+ if (responseBody.indexOf("<!-- Welcome to the Atmosphere Framework.") != -1) {
+ isJunkEnded = true;
+ }
+
+ if (isJunkEnded) {
+ var endOfJunk = "<!-- EOD -->";
+ var endOfJunkLenght = endOfJunk.length;
+ var junkEnd = responseBody.indexOf(endOfJunk);
+ if (junkEnd !== -1) {
+ responseBody = responseBody.substring(junkEnd + endOfJunkLenght + lastIndex);
+ lastIndex += responseBody.length;
+ }
+ }
+
+ if (!_handleProtocol(request, responseBody)) return;
+
+ _prepareCallback(responseBody, "messageReceived", 200, transport);
+ };
+
+ var xdr = new window.XDomainRequest();
+ var rewriteURL = rq.rewriteURL || function(url) {
+ // Maintaining session by rewriting URL
+ // http://stackoverflow.com/questions/6453779/maintaining-session-by-rewriting-url
+ var match = /(?:^|;\s*)(JSESSIONID|PHPSESSID)=([^;]*)/.exec(document.cookie);
+
+ switch (match && match[1]) {
+ case "JSESSIONID":
+ return url.replace(/;jsessionid=[^\?]*|(\?)|$/, ";jsessionid=" + match[2] + "$1");
+ case "PHPSESSID":
+ return url.replace(/\?PHPSESSID=[^&]*&?|\?|$/, "?PHPSESSID=" + match[2] + "&").replace(/&$/, "");
+ }
+ return url;
+ };
+
+ // Handles open and message event
+ xdr.onprogress = function() {
+ handle(xdr);
+ };
+
+ // Handles error event
+ xdr.onerror = function() {
+ // If the server doesn't send anything back to XDR will fail with polling
+ if (rq.transport != 'polling') {
+ _prepareCallback(xdr.responseText, "error", 500, transport);
+ }
+
+ _reconnect(xdr, rq, false);
+ };
+
+ // Handles close event
+ xdr.onload = function() {
+ handle(xdr);
+ };
+
+ var handle = function (xdr) {
+ // XDomain loop forever on itself without this.
+ // TODO: Clearly I need to come with something better than that solution
+ if (rq.lastMessage == xdr.responseText) return;
+
+ if (rq.executeCallbackBeforeReconnect) {
+ xdrCallback(xdr);
+ }
+
+ if (rq.transport == "long-polling" && (rq.reconnect && (rq.maxRequest == -1 || rq.requestCount++ < rq.maxRequest))) {
+ xdr.status = 200;
+ _reconnect(xdr, rq, false);
+ }
+
+ if (!rq.executeCallbackBeforeReconnect) {
+ xdrCallback(xdr);
+ }
+ rq.lastMessage = xdr.responseText;
+ };
+
+ return {
+ open: function() {
+ if (rq.method == 'POST') {
+ rq.attachHeadersAsQueryString = true;
+ }
+ var url = _attachHeaders(rq);
+ if (rq.method == 'POST') {
+ url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(rq.data);
+ }
+ xdr.open(rq.method, rewriteURL(url));
+ xdr.send();
+ if (rq.connectTimeout > -1) {
+ rq.id = setTimeout(function() {
+ if (rq.requestCount == 0) {
+ _clearState();
+ _prepareCallback("Connect timeout", "closed", 200, rq.transport);
+ }
+ }, rq.connectTimeout);
+ }
+ },
+ close: function() {
+ xdr.abort();
+ _prepareCallback(xdr.responseText, "closed", 200, transport);
+ }
+ };
+ }
+
+ // From jquery-stream, which is APL2 licensed as well.
+ function _ieStreaming(request) {
+ _ieStream = _configureIE(request);
+ _ieStream.open();
+ }
+
+ function _configureIE(request) {
+ var rq = _request;
+ if ((request != null) && (typeof(request) != 'undefined')) {
+ rq = request;
+ }
+
+ var stop;
+ var doc = new window.ActiveXObject("htmlfile");
+
+ doc.open();
+ doc.close();
+
+ var url = rq.url;
+
+ if (rq.transport != 'polling') {
+ _response.transport = rq.transport;
+ }
+
+ return {
+ open: function() {
+ var iframe = doc.createElement("iframe");
+
+ url = _attachHeaders(rq);
+ if (rq.data != '') {
+ url += "&X-Atmosphere-Post-Body=" + encodeURIComponent(rq.data);
+ }
+
+ // Finally attach a timestamp to prevent Android and IE caching.
+ url = jQuery.atmosphere.prepareURL(url);
+
+ iframe.src = url;
+ doc.body.appendChild(iframe);
+
+ // For the server to respond in a consistent format regardless of user agent, we polls response text
+ var cdoc = iframe.contentDocument || iframe.contentWindow.document;
+
+ stop = jQuery.atmosphere.iterate(function() {
+ try {
+ if (!cdoc.firstChild) {
+ return;
+ }
+
+ // Detects connection failure
+ if (cdoc.readyState === "complete") {
+ try {
+ jQuery.noop(cdoc.fileSize);
+ } catch(e) {
+ _prepareCallback("Connection Failure", "error", 500, rq.transport);
+ return false;
+ }
+ }
+
+ var res = cdoc.body ? cdoc.body.lastChild : cdoc;
+ var readResponse = function() {
+ // Clones the element not to disturb the original one
+ var clone = res.cloneNode(true);
+
+ // If the last character is a carriage return or a line feed, IE ignores it in the innerText property
+ // therefore, we add another non-newline character to preserve it
+ clone.appendChild(cdoc.createTextNode("."));
+
+ var text = clone.innerText;
+ var isJunkEnded = true;
+
+ if (text.indexOf("<!-- Welcome to the Atmosphere Framework.") == -1) {
+ isJunkEnded = false;
+ }
+
+ if (isJunkEnded) {
+ var endOfJunk = "<!-- EOD -->";
+ var endOfJunkLength = endOfJunk.length;
+ var junkEnd = text.indexOf(endOfJunk) + endOfJunkLength;
+
+ text = text.substring(junkEnd);
+ }
+
+ text = text.substring(0, text.length - 1);
+
+ _handleProtocol(rq, text);
+ return text;
+
+ };
+
+ //To support text/html content type
+ if (!jQuery.nodeName(res, "pre")) {
+ // Injects a plaintext element which renders text without interpreting the HTML and cannot be stopped
+ // it is deprecated in HTML5, but still works
+ var head = cdoc.head || cdoc.getElementsByTagName("head")[0] || cdoc.documentElement || cdoc;
+ var script = cdoc.createElement("script");
+
+ script.text = "document.write('<plaintext>')";
+
+ head.insertBefore(script, head.firstChild);
+ head.removeChild(script);
+
+ // The plaintext element will be the response container
+ res = cdoc.body.lastChild;
+ }
+
+ // Handles open event
+ _prepareCallback(readResponse(), "opening", 200, rq.transport);
+
+ // Handles message and close event
+ stop = jQuery.atmosphere.iterate(function() {
+ var text = readResponse();
+ if (text.length > rq.lastIndex) {
+ _response.status = 200;
+
+ // Empties response every time that it is handled
+ res.innerText = "";
+ _prepareCallback(text, "messageReceived", 200, rq.transport);
+
+ rq.lastIndex = 0;
+ }
+
+ if (cdoc.readyState === "complete") {
+ _prepareCallback("", "closed", 200, rq.transport);
+ _prepareCallback("", "re-opening", 200, rq.transport);
+ rq.id = setTimeout(function() {
+ _ieStreaming(rq);
+ }, rq.reconnectInterval);
+ return false;
+ }
+ }, null);
+
+ return false;
+ } catch (err) {
+ if (_requestCount++ < rq.maxReconnectOnClose) {
+ rq.id = setTimeout(function() {
+ _ieStreaming(rq);
+ }, rq.reconnectInterval);
+ } else {
+ _onError();
+ }
+ doc.execCommand("Stop");
+ doc.close();
+ return false;
+ }
+ });
+ },
+
+ close: function() {
+ if (stop) {
+ stop();
+ }
+
+ doc.execCommand("Stop");
+ _prepareCallback("", "closed", 200, rq.transport);
+ }
+ };
+ }
+
+ /*
+ * Send message. <br>
+ * Will be automatically dispatch to other connected.
+ *
+ * @param {Object,string} Message to send.
+ * @private
+ */
+ function _push(message) {
+
+ if (_response.status == 408) {
+ _pushOnClose(message);
+ } else if (_localStorageService != null) {
+ _pushLocal(message);
+ } else if (_activeRequest != null || _sse != null) {
+ _pushAjaxMessage(message);
+ } else if (_ieStream != null) {
+ _pushIE(message);
+ } else if (_jqxhr != null) {
+ _pushJsonp(message);
+ } else if (_websocket != null) {
+ _pushWebSocket(message);
+ }
+ }
+
+ function _pushOnClose(message) {
+ var rq = _getPushRequest(message);
+ rq.transport = "ajax";
+ rq.method = "GET";
+ rq.async = false;
+ rq.reconnect = false;
+ _executeRequest(rq);
+ }
+
+ function _pushLocal(message) {
+ _localStorageService.send(message);
+ }
+
+ function _intraPush(message) {
+ // IE 9 will crash if not.
+ if (message.length == 0) return;
+
+ try {
+ if (_localStorageService) {
+ _localStorageService.localSend(message);
+ } else if (_storageService) {
+ _storageService.signal("localMessage", jQuery.stringifyJSON({id: guid , event: message}));
+ }
+ } catch (err) {
+ jQuery.atmosphere.error(err);
+ }
+ }
+
+ /**
+ * Send a message using currently opened ajax request (using
+ * http-streaming or long-polling). <br>
+ *
+ * @param {string, Object} Message to send. This is an object, string
+ * message is saved in data member.
+ * @private
+ */
+ function _pushAjaxMessage(message) {
+ var rq = _getPushRequest(message);
+ _executeRequest(rq);
+ }
+
+ /**
+ * Send a message using currently opened ie streaming (using
+ * http-streaming or long-polling). <br>
+ *
+ * @param {string, Object} Message to send. This is an object, string
+ * message is saved in data member.
+ * @private
+ */
+ function _pushIE(message) {
+ if (_request.enableXDR && jQuery.atmosphere.checkCORSSupport()) {
+ var rq = _getPushRequest(message);
+ // Do not reconnect since we are pushing.
+ rq.reconnect = false;
+ _jsonp(rq);
+ } else {
+ _pushAjaxMessage(message);
+ }
+ }
+
+ /**
+ * Send a message using jsonp transport. <br>
+ *
+ * @param {string, Object} Message to send. This is an object, string
+ * message is saved in data member.
+ * @private
+ */
+ function _pushJsonp(message) {
+ _pushAjaxMessage(message);
+ }
+
+ function _getStringMessage(message) {
+ var msg = message;
+ if (typeof(msg) == 'object') {
+ msg = message.data;
+ }
+ return msg;
+ }
+
+ /**
+ * Build request use to push message using method 'POST' <br>.
+ * Transport is defined as 'polling' and 'suspend' is set to false.
+ *
+ * @return {Object} Request object use to push message.
+ * @private
+ */
+ function _getPushRequest(message) {
+ var msg = _getStringMessage(message);
+
+ var rq = {
+ connected: false,
+ timeout: 60000,
+ method: 'POST',
+ url: _request.url,
+ contentType : _request.contentType,
+ headers: {},
+ reconnect : true,
+ callback: null,
+ data : msg,
+ suspend : false,
+ maxRequest : -1,
+ logLevel : 'info',
+ requestCount : 0,
+ withCredentials : _request.withCredentials,
+ transport: 'polling',
+ attachHeadersAsQueryString: true,
+ enableXDR: _request.enableXDR,
+ uuid : _request.uuid,
+ enableProtocol : false,
+ maxReconnectOnClose : _request.maxReconnectOnClose
+ };
+
+ if (typeof(message) == 'object') {
+ rq = jQuery.extend(rq, message);
+ }
+
+ return rq;
+ }
+
+ /**
+ * Send a message using currently opened websocket. <br>
+ *
+ */
+ function _pushWebSocket(message) {
+ var msg = _getStringMessage(message);
+ var data;
+ try {
+ if (_request.webSocketUrl != null) {
+ data = _request.webSocketPathDelimiter
+ + _request.webSocketUrl
+ + _request.webSocketPathDelimiter
+ + msg;
+ } else {
+ data = msg;
+ }
+
+ _websocket.send(data);
+
+ } catch (e) {
+ _websocket.onclose = function(message) {
+ };
+ _clearState();
+
+ _reconnectWithFallbackTransport("Websocket failed. Downgrading to Comet and resending " + data);
+ _pushAjaxMessage(message);
+ }
+ }
+
+ function _localMessage(message) {
+ var m = jQuery.parseJSON(message);
+ if (m.id != guid) {
+ if (typeof(_request.onLocalMessage) != 'undefined') {
+ _request.onLocalMessage(m.event);
+ } else if (typeof(jQuery.atmosphere.onLocalMessage) != 'undefined') {
+ jQuery.atmosphere.onLocalMessage(m.event);
+ }
+ }
+ }
+
+ function _prepareCallback(messageBody, state, errorCode, transport) {
+ _response.responseBody = messageBody;
+ if (state == "messageReceived") {
+ if (_trackMessageSize(messageBody, _request, _response)) {
+ return;
+ }
+ }
+
+ _response.transport = transport;
+ _response.status = errorCode;
+ _response.state = state;
+
+ _invokeCallback();
+ }
+
+ function _readHeaders(xdr, request) {
+ if (!request.readResponsesHeaders && !request.enableProtocol) {
+ request.lastTimestamp = jQuery.now();
+ request.uuid = jQuery.atmosphere.guid();
+ return;
+ }
+
+ try {
+ var tempDate = xdr.getResponseHeader('X-Cache-Date');
+ if (tempDate && tempDate != null && tempDate.length > 0 ) {
+ request.lastTimestamp = tempDate.split(" ").pop();
+ }
+
+ var tempUUID = xdr.getResponseHeader('X-Atmosphere-tracking-id');
+ if (tempUUID && tempUUID != null) {
+ request.uuid = tempUUID.split(" ").pop();
+ }
+
+ // HOTFIX for firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=608735
+ if (request.headers) {
+ jQuery.each(_request.headers, function (name) {
+ var v = xdr.getResponseHeader(name);
+ if (v) {
+ _response.headers[name] = v;
+ }
+ });
+ }
+ } catch (e) {
+ }
+ }
+
+ function _invokeFunction(response) {
+ _f(response, _request);
+ // Global
+ _f(response, jQuery.atmosphere);
+ }
+
+ function _f(response, f) {
+ switch (response.state) {
+ case "messageReceived" :
+ _requestCount = 0;
+ if (typeof(f.onMessage) != 'undefined') f.onMessage(response);
+ break;
+ case "error" :
+ if (typeof(f.onError) != 'undefined') f.onError(response);
+ break;
+ case "opening" :
+ if (typeof(f.onOpen) != 'undefined') f.onOpen(response);
+ break;
+ case "messagePublished" :
+ if (typeof(f.onMessagePublished) != 'undefined') f.onMessagePublished(response);
+ break;
+ case "re-opening" :
+ if (typeof(f.onReconnect) != 'undefined') f.onReconnect(_request, response);
+ break;
+ case "unsubscribe" :
+ case "closed" :
+ var closed = typeof(_request.closed) != 'undefined' ? _request.closed : false;
+ if (typeof(f.onClose) != 'undefined' && !closed) f.onClose(response);
+ _request.closed = true;
+ break;
+ }
+ }
+
+ /**
+ * Invoke request callbacks.
+ *
+ * @private
+ */
+ function _invokeCallback() {
+ var call = function (index, func) {
+ func(_response);
+ };
+
+ if (_localStorageService == null && _localSocketF != null) {
+ _localSocketF(_response.responseBody);
+ }
+
+ _request.reconnect = _request.mrequest;
+
+ var messages = (typeof(_response.responseBody) == 'string' && _request.trackMessageLength) ?
+ _response.responseBody.split(_request.messageDelimiter) : new Array(_response.responseBody);
+ for (var i = 0; i < messages.length; i++) {
+
+ if (messages.length > 1 && messages[i].length == 0) {
+ continue;
+ }
+ _response.responseBody = jQuery.trim(messages[i]);
+
+ // Ugly see issue 400.
+ if (_response.responseBody.length == 0 && _response.transport == 'streaming' && _response.state == "messageReceived") {
+ var ua = navigator.userAgent.toLowerCase();
+ var isAndroid = ua.indexOf("android") > -1;
+ if (isAndroid) {
+ continue;
+ }
+ }
+
+ _invokeFunction(_response);
+
+ // Invoke global callbacks
+ if (jQuery.atmosphere.callbacks.length > 0) {
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Invoking " + jQuery.atmosphere.callbacks.length + " global callbacks: " + _response.state);
+ }
+ try {
+ jQuery.each(jQuery.atmosphere.callbacks, call);
+ } catch (e) {
+ jQuery.atmosphere.log(_request.logLevel, ["Callback exception" + e]);
+ }
+ }
+
+ // Invoke request callback
+ if (typeof(_request.callback) == 'function') {
+ if (_request.logLevel == 'debug') {
+ jQuery.atmosphere.debug("Invoking request callbacks");
+ }
+ try {
+ _request.callback(_response);
+ } catch (e) {
+ jQuery.atmosphere.log(_request.logLevel, ["Callback exception" + e]);
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Close request.
+ *
+ * @private
+ */
+ function _close() {
+ _abordingConnection = true;
+ _request.reconnect = false;
+ _response.request = _request;
+ _response.state = 'unsubscribe';
+ _response.responseBody = "";
+ _response.status = 408;
+ _invokeCallback();
+
+ _clearState();
+ }
+
+ function _clearState() {
+ if (_ieStream != null) {
+ _ieStream.close();
+ _ieStream = null;
+ }
+ if (_jqxhr != null) {
+ _jqxhr.abort();
+ _jqxhr = null;
+ }
+ if (_activeRequest != null) {
+ _activeRequest.abort();
+ _activeRequest = null;
+ }
+ if (_websocket != null) {
+ _websocket.close();
+ _websocket = null;
+ }
+ if (_sse != null) {
+ _sse.close();
+ _sse = null;
+ }
+ _clearStorage();
+ }
+
+ function _clearStorage() {
+ // Stop sharing a connection
+ if (_storageService != null) {
+ // Clears trace timer
+ clearInterval(_traceTimer);
+ // Removes the trace
+ document.cookie = encodeURIComponent("atmosphere-" + _request.url) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
+ // The heir is the parent unless unloading
+ _storageService.signal("close", {reason: "", heir: !_abordingConnection ? guid : (_storageService.get("children") || [])[0]});
+ _storageService.close();
+ }
+ if (_localStorageService != null) {
+ _localStorageService.close();
+ }
+ }
+
+ this.subscribe = function(options) {
+ _subscribe(options);
+ _execute();
+ };
+
+ this.execute = function() {
+ _execute();
+ };
+
+ this.invokeCallback = function() {
+ _invokeCallback();
+ };
+
+ this.close = function() {
+ _close();
+ };
+
+ this.getUrl = function() {
+ return _request.url;
+ };
+
+ this.getUUID = function() {
+ return _request.uuid;
+ };
+
+ this.push = function(message) {
+ _push(message);
+ };
+
+ this.pushLocal = function(message) {
+ _intraPush(message);
+ };
+
+ this.enableProtocol = function(message) {
+ return _request.enableProtocol;
+ };
+
+ this.response = _response;
+ },
+
+ subscribe: function(url, callback, request) {
+ if (typeof(callback) == 'function') {
+ jQuery.atmosphere.addCallback(callback);
+ }
+
+ if (typeof(url) != "string") {
+ request = url;
+ } else {
+ request.url = url;
+ }
+
+ var rq = new jQuery.atmosphere.AtmosphereRequest(request);
+ rq.execute();
+
+ jQuery.atmosphere.requests[jQuery.atmosphere.requests.length] = rq;
+ return rq;
+ },
+
+ addCallback: function(func) {
+ if (jQuery.inArray(func, jQuery.atmosphere.callbacks) == -1) {
+ jQuery.atmosphere.callbacks.push(func);
+ }
+ },
+
+ removeCallback: function(func) {
+ var index = jQuery.inArray(func, jQuery.atmosphere.callbacks);
+ if (index != -1) {
+ jQuery.atmosphere.callbacks.splice(index, 1);
+ }
+ },
+
+ unsubscribe : function() {
+ if (jQuery.atmosphere.requests.length > 0) {
+ var requestsClone = [].concat(jQuery.atmosphere.requests);
+ for (var i = 0; i < requestsClone.length; i++) {
+ var rq = requestsClone[i];
+ rq.close();
+ if (rq.enableProtocol()) {
+ jQuery.ajax({url: this._closeUrl(rq), async:false});
+ }
+ clearTimeout(rq.response.request.id);
+ }
+ }
+ jQuery.atmosphere.requests = [];
+ jQuery.atmosphere.callbacks = [];
+ },
+
+ _closeUrl : function(rq) {
+ var query = "X-Atmosphere-Transport=close&X-Atmosphere-tracking-id=" + rq.getUUID();
+ var url = rq.getUrl().replace(/([?&])_=[^&]*/, query);
+ return url + (url === rq.getUrl() ? (/\?/.test(rq.getUrl()) ? "&" : "?") + query : "");
+ },
+
+ unsubscribeUrl: function(url) {
+ var idx = -1;
+ if (jQuery.atmosphere.requests.length > 0) {
+ for (var i = 0; i < jQuery.atmosphere.requests.length; i++) {
+ var rq = jQuery.atmosphere.requests[i];
+
+ // Suppose you can subscribe once to an url
+ if (rq.getUrl() == url) {
+ rq.close();
+ if (rq.enableProtocol()) {
+ jQuery.ajax({url :this._closeUrl(rq), async:false});
+ }
+ clearTimeout(rq.response.request.id);
+ idx = i;
+ break;
+ }
+ }
+ }
+ if (idx >= 0) {
+ jQuery.atmosphere.requests.splice(idx, 1);
+ }
+ },
+
+ publish: function(request) {
+ if (typeof(request.callback) == 'function') {
+ jQuery.atmosphere.addCallback(callback);
+ }
+ request.transport = "polling";
+
+ var rq = new jQuery.atmosphere.AtmosphereRequest(request);
+ jQuery.atmosphere.requests[jQuery.atmosphere.requests.length] = rq;
+ return rq;
+ },
+
+ checkCORSSupport : function() {
+ if (jQuery.browser.msie && !window.XDomainRequest) {
+ return true;
+ } else if (jQuery.browser.opera && jQuery.browser.version < 12.0) {
+ return true;
+ }
+
+ // Force Android to use CORS as some version like 2.2.3 fail otherwise
+ var ua = navigator.userAgent.toLowerCase();
+ var isAndroid = ua.indexOf("android") > -1;
+ if (isAndroid) {
+ return true;
+ }
+ return false;
+ },
+
+ S4 : function() {
+ return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+ },
+
+ guid : function() {
+ return (jQuery.atmosphere.S4() + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + "-" + jQuery.atmosphere.S4() + jQuery.atmosphere.S4() + jQuery.atmosphere.S4());
+ },
+
+ // From jQuery-Stream
+ prepareURL: function(url) {
+ // Attaches a time stamp to prevent caching
+ var ts = jQuery.now();
+ var ret = url.replace(/([?&])_=[^&]*/, "$1_=" + ts);
+
+ return ret + (ret === url ? (/\?/.test(url) ? "&" : "?") + "_=" + ts : "");
+ },
+
+ // From jQuery-Stream
+ param : function(data) {
+ return jQuery.param(data, jQuery.ajaxSettings.traditional);
+ },
+
+ supportStorage : function() {
+ var storage = window.localStorage;
+ if (storage) {
+ try {
+ storage.setItem("t", "t");
+ storage.removeItem("t");
+ // The storage event of Internet Explorer and Firefox 3 works strangely
+ return window.StorageEvent && !jQuery.browser.msie && !(jQuery.browser.mozilla && jQuery.browser.version.split(".")[0] === "1");
+ } catch (e) {
+ }
+ }
+
+ return false;
+ },
+
+ iterate : function (fn, interval) {
+ var timeoutId;
+
+ // Though the interval is 0 for real-time application, there is a delay between setTimeout calls
+ // For detail, see https://developer.mozilla.org/en/window.setTimeout#Minimum_delay_and_timeout_nesting
+ interval = interval || 0;
+
+ (function loop() {
+ timeoutId = setTimeout(function() {
+ if (fn() === false) {
+ return;
+ }
+
+ loop();
+ }, interval);
+ })();
+
+ return function() {
+ clearTimeout(timeoutId);
+ };
+ },
+
+ log: function (level, args) {
+ if (window.console) {
+ var logger = window.console[level];
+ if (typeof logger == 'function') {
+ logger.apply(window.console, args);
+ }
+ }
+ },
+
+ warn: function() {
+ jQuery.atmosphere.log('warn', arguments);
+ },
+
+ info :function() {
+ jQuery.atmosphere.log('info', arguments);
+ },
+
+ debug: function() {
+ jQuery.atmosphere.log('debug', arguments);
+ },
+
+ error: function() {
+ jQuery.atmosphere.log('error', arguments);
+ }
+ };
+}();
+
+// http://stackoverflow.com/questions/9645803/whats-the-replacement-for-browser
+// Limit scope pollution from any deprecated API
+(function () {
+
+ var matched, browser;
+
+// Use of jQuery.browser is frowned upon.
+// More details: http://api.jquery.com/jQuery.browser
+// jQuery.uaMatch maintained for back-compat
+ jQuery.uaMatch = function (ua) {
+ ua = ua.toLowerCase();
+
+ var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+ /(webkit)[ \/]([\w.]+)/.exec(ua) ||
+ /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
+ /(msie) ([\w.]+)/.exec(ua) ||
+ ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+ [];
+
+ return {
+ browser: match[ 1 ] || "",
+ version: match[ 2 ] || "0"
+ };
+ };
+
+ matched = jQuery.uaMatch(navigator.userAgent);
+ browser = {};
+
+ if (matched.browser) {
+ browser[ matched.browser ] = true;
+ browser.version = matched.version;
+ }
+
+// Chrome is Webkit, but Webkit is also Safari.
+ if (browser.chrome) {
+ browser.webkit = true;
+ } else if (browser.webkit) {
+ browser.safari = true;
+ }
+
+ jQuery.browser = browser;
+
+ jQuery.sub = function () {
+ function jQuerySub(selector, context) {
+ return new jQuerySub.fn.init(selector, context);
+ }
+
+ jQuery.extend(true, jQuerySub, this);
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init(selector, context) {
+ if (context && context instanceof jQuery && !(context instanceof jQuerySub)) {
+ context = jQuerySub(context);
+ }
+
+ return jQuery.fn.init.call(this, selector, context, rootjQuerySub);
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ return jQuerySub;
+ };
+
+})();
+
+/*
+ * jQuery stringifyJSON
+ * http://github.com/flowersinthesand/jquery-stringifyJSON
+ *
+ * Copyright 2011, Donghwan Kim
+ * Licensed under the Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ */
+// This plugin is heavily based on Douglas Crockford's reference implementation
+(function(jQuery) {
+
+ var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, meta = {
+ '\b' : '\\b',
+ '\t' : '\\t',
+ '\n' : '\\n',
+ '\f' : '\\f',
+ '\r' : '\\r',
+ '"' : '\\"',
+ '\\' : '\\\\'
+ };
+
+ function quote(string) {
+ return '"' + string.replace(escapable, function(a) {
+ var c = meta[a];
+ return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"';
+ }
+
+ function f(n) {
+ return n < 10 ? "0" + n : n;
+ }
+
+ function str(key, holder) {
+ var i, v, len, partial, value = holder[key], type = typeof value;
+
+ if (value && typeof value === "object" && typeof value.toJSON === "function") {
+ value = value.toJSON(key);
+ type = typeof value;
+ }
+
+ switch (type) {
+ case "string":
+ return quote(value);
+ case "number":
+ return isFinite(value) ? String(value) : "null";
+ case "boolean":
+ return String(value);
+ case "object":
+ if (!value) {
+ return "null";
+ }
+
+ switch (Object.prototype.toString.call(value)) {
+ case "[object Date]":
+ return isFinite(value.valueOf()) ? '"' + value.getUTCFullYear() + "-" + f(value.getUTCMonth() + 1) + "-" + f(value.getUTCDate()) + "T" +
+ f(value.getUTCHours()) + ":" + f(value.getUTCMinutes()) + ":" + f(value.getUTCSeconds()) + "Z" + '"' : "null";
+ case "[object Array]":
+ len = value.length;
+ partial = [];
+ for (i = 0; i < len; i++) {
+ partial.push(str(i, value) || "null");
+ }
+
+ return "[" + partial.join(",") + "]";
+ default:
+ partial = [];
+ for (i in value) {
+ if (Object.prototype.hasOwnProperty.call(value, i)) {
+ v = str(i, value);
+ if (v) {
+ partial.push(quote(i) + ":" + v);
+ }
+ }
+ }
+
+ return "{" + partial.join(",") + "}";
+ }
+ }
+ }
+
+ jQuery.stringifyJSON = function(value) {
+ if (window.JSON && window.JSON.stringify) {
+ return window.JSON.stringify(value);
+ }
+
+ return str("", {"": value});
+ };
+
+}(jQuery)); \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/base.scss b/WebContent/VAADIN/themes/base/base.scss
index 87754b6777..83e463fa00 100644
--- a/WebContent/VAADIN/themes/base/base.scss
+++ b/WebContent/VAADIN/themes/base/base.scss
@@ -4,6 +4,7 @@
@import "button/nativebutton.scss";
@import "button/checkbox.scss";
@import "layout/layout.scss";
+@import "calendar/calendar.scss";
@import "caption/caption.scss";
@import "colorpicker/colorpicker.scss";
@import "common/common.scss";
@@ -64,6 +65,7 @@ $line-height: normal;
@include base-checkbox;
@include base-caption;
@include base-colorpicker;
+ @include base-calendar;
// here for now to preserve old semantics
@include base-common;
diff --git a/WebContent/VAADIN/themes/base/calendar/calendar.scss b/WebContent/VAADIN/themes/base/calendar/calendar.scss
new file mode 100644
index 0000000000..8ff97df0f9
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/calendar/calendar.scss
@@ -0,0 +1,378 @@
+@mixin base-calendar($primaryStyleName : v-calendar) {
+
+/* Global resize style */
+.#{$primaryStyleName}-nresize DIV DIV {
+ cursor: n-resize !important;
+}
+
+.#{$primaryStyleName}-sresize DIV DIV {
+ cursor: s-resize !important;
+}
+
+/* Header bar */
+.#{$primaryStyleName} {
+ background-color: #fff;
+}
+
+.#{$primaryStyleName}-header-month,.#{$primaryStyleName}-header-week {
+ border-bottom: 1px solid #c1c1c1;
+}
+
+.#{$primaryStyleName}-header-day {
+ text-align: center;
+ color: #666;
+ font-size: 12px;
+ line-height: normal;
+}
+
+.#{$primaryStyleName}-header-week .#{$primaryStyleName}-header-day:hover {
+ cursor: pointer;
+ color: #222
+}
+
+.#{$primaryStyleName}-header-day-today {
+ font-weight: bold;
+ color: #444;
+}
+
+.#{$primaryStyleName}-header-month td:first-child {
+ padding-left: 19px;
+ /* Same as VCalendar.MONTHLY_WEEKTOOLBARWIDTH - .#{$primaryStyleName}-week-numbers border */
+}
+
+.#{$primaryStyleName}-header-week .#{$primaryStyleName}-back,.#{$primaryStyleName}-header-week .#{$primaryStyleName}-next
+ {
+ border: none;
+ padding: 0;
+ margin: 0;
+ height: 12px;
+ width: 12px;
+ overflow: hidden;
+ background: transparent url(img/arrows.png) no-repeat 50% 0;
+ opacity: .3;
+ filter: alpha(opacity = 30);
+ cursor: default;
+}
+
+.#{$primaryStyleName}-header-week .#{$primaryStyleName}-back:hover,.#{$primaryStyleName}-header-week .#{$primaryStyleName}-next:hover
+ {
+ opacity: .6;
+ filter: alpha(opacity = 60);
+}
+
+.#{$primaryStyleName}-header-week .#{$primaryStyleName}-back:active,.#{$primaryStyleName}-header-week .#{$primaryStyleName}-next:active
+ {
+ opacity: 1;
+ filter: alpha(opacity = 100);
+}
+
+.#{$primaryStyleName}-header-week .#{$primaryStyleName}-next {
+ background-position: 50% -12px;
+}
+
+/* Month grid */
+.#{$primaryStyleName}-month {
+ outline: none;
+}
+
+.#{$primaryStyleName}-week-numbers {
+ width: 20px;
+ border-right: 1px solid #ccc;
+}
+
+.#{$primaryStyleName}-week-number {
+ border: none;
+ background: transparent;
+ padding: 0;
+ margin: 0;
+ cursor: pointer;
+ opacity: .5;
+ width: 20px;
+ text-align: center;
+ border-bottom: 1px solid #ddd;
+}
+
+.#{$primaryStyleName}-week-number:hover {
+ opacity: 1;
+}
+
+.#{$primaryStyleName}-month-day {
+ border-bottom: 1px solid #ccc;
+ border-right: 1px solid #ccc;
+ outline: none;
+}
+
+.#{$primaryStyleName}-month-day-today {
+ background-color: #e7f0f5;
+}
+
+.#{$primaryStyleName}-month-day-selected {
+ background-color: #fffee7;
+}
+
+.#{$primaryStyleName}-month-day-dragemphasis {
+ background-color: #a8a8a8;
+}
+
+.#{$primaryStyleName}-month-day-scrollable {
+ overflow-y: scroll;
+}
+
+.#{$primaryStyleName}-day-number {
+ height: 18px;
+ line-height: 18px;
+ font-size: 12px;
+ text-align: right;
+ padding-right: 3px;
+ white-space: nowrap;
+}
+
+.#{$primaryStyleName}-day-number:hover {
+ cursor: pointer;
+ opacity: .6;
+ filter: alpha(opacity = 60);
+}
+
+.#{$primaryStyleName}-month .#{$primaryStyleName}-spacer,.#{$primaryStyleName}-month .#{$primaryStyleName}-bottom-spacer,.#{$primaryStyleName}-month .#{$primaryStyleName}-bottom-spacer-empty
+ {
+ /* Bottom spacer is used in GWT to measure the event height (offsetHeight) */
+ height: 15px;
+ font-size: 11px;
+}
+
+.#{$primaryStyleName}-month .#{$primaryStyleName}-bottom-spacer:hover {
+ cursor: pointer;
+ opacity: .6;
+ filter: alpha(opacity = 60);
+}
+
+.#{$primaryStyleName}-event {
+ line-height: 14px;
+ font-size: 11px;
+ padding: 0 0 0 4px;
+ cursor: pointer;
+ overflow: hidden;
+ text-overflow: ellipsis;
+
+ outline: none;
+}
+
+.#{$primaryStyleName}-event-month {
+ margin-bottom: 1px;
+ white-space: nowrap;
+}
+
+.#{$primaryStyleName}-event-month:hover {
+ text-decoration: underline;
+}
+
+.#{$primaryStyleName}-event-all-day {
+ background: #999;
+ display: block;
+ margin-left: -2px;
+}
+
+div.#{$primaryStyleName}-event-all-day {
+ color: #fff;
+ height: 14px;
+}
+
+.#{$primaryStyleName}-event-continued-from {
+ margin-left: 0;
+}
+
+.#{$primaryStyleName}-event-start {
+ -webkit-border-top-left-radius: 6px;
+ -webkit-border-bottom-left-radius: 6px;
+ -moz-border-radius-topleft: 6px;
+ -moz-border-radius-bottomleft: 6px;
+ border-top-left-radius: 6px;
+ border-bottom-left-radius: 6px;
+ margin-left: 0;
+}
+
+.#{$primaryStyleName}-event-end {
+ -webkit-border-top-right-radius: 6px;
+ -webkit-border-bottom-right-radius: 6px;
+ -moz-border-radius-topright: 6px;
+ -moz-border-radius-bottomright: 6px;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+}
+
+/* Week/day view */
+.#{$primaryStyleName}-week-wrapper {
+ position: relative;
+}
+
+/*.v-ie7 .#{$primaryStyleName}-week-wrapper TABLE{
+ table-layout: fixed;
+}*/
+.#{$primaryStyleName}-times {
+ width: 51px;
+}
+
+.#{$primaryStyleName}-time {
+ padding: 0 8px 7px 0;
+ margin-top: -7px;
+ text-align: right;
+ font-size: 11px;
+ color: #666;
+ border-right: 1px solid #ccc;
+}
+
+.#{$primaryStyleName}-weekly-longevents {
+ border-left: 1px solid #ccc;
+ border-bottom: 2px solid #bbb;
+ margin-left: 50px;
+}
+
+.#{$primaryStyleName}-weekly-longevents .#{$primaryStyleName}-datecell {
+ border-right: 1px solid #ccc;
+ padding: 1px 0 0;
+}
+
+.#{$primaryStyleName}-weekly-longevents .#{$primaryStyleName}-event {
+ height: 14px;
+ margin-bottom: 1px;
+}
+
+.#{$primaryStyleName}-weekly-longevents .#{$primaryStyleName}-event:hover {
+ text-decoration: underline;
+}
+
+.#{$primaryStyleName}-day-times {
+ border-right: 1px solid #ccc;
+ outline: none;
+}
+
+.#{$primaryStyleName}-day-times .v-datecellslot,.#{$primaryStyleName}-day-times .v-datecellslot-even {
+ border-bottom: 1px solid #ccc;
+}
+
+.#{$primaryStyleName}-day-times .v-datecellslot-even {
+ border-bottom-color: #eee;
+}
+
+.#{$primaryStyleName}-day-times .v-daterange {
+ background-color: #a8a8a8;
+}
+
+.#{$primaryStyleName}-day-times .v-reserved {
+ background-color: #FF3333;
+}
+
+.#{$primaryStyleName}-day-times .dragemphasis {
+ background-color: #a8a8a8;
+}
+
+.#{$primaryStyleName}-week-wrapper .#{$primaryStyleName}-event {
+ padding: 0;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ margin-top: -1px;
+}
+
+.#{$primaryStyleName}-event-caption {
+ position: absolute;
+ z-index: 1;
+ top: 2px;
+ left: 4px;
+ width: 100%;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ line-height: normal;
+}
+
+.#{$primaryStyleName}-event-content {
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ border: 1px solid #777;
+ background: #eee;
+ opacity: .8;
+ filter: alpha(opacity = 80);
+ height: 14px; /* "min-height" */
+}
+
+.#{$primaryStyleName}-current-time {
+ position: absolute;
+ left: 0;
+ width: 100%;
+ height: 1px;
+ overflow: hidden;
+ background: #5a6c86;
+ opacity: .6;
+ filter: alpha(opacity = 60);
+ z-index: 2;
+}
+
+.#{$primaryStyleName}-event-resizetop {
+ position: absolute;
+ cursor: n-resize;
+ height: 5%;
+ min-height: 3px;
+ top: 0;
+ width: 100%;
+ z-index: 1;
+}
+
+.#{$primaryStyleName}-event-resizebottom {
+ position: absolute;
+ cursor: s-resize;
+ height: 5%;
+ min-height: 3px;
+ bottom: 0;
+ width: 100%;
+ z-index: 1;
+}
+
+.#{$primaryStyleName}-month-sizedheight .#{$primaryStyleName}-month-day {
+ height: 100px;
+}
+
+.#{$primaryStyleName}-month-sizedwidth .#{$primaryStyleName}-month-day {
+ width: 100px;
+}
+
+.#{$primaryStyleName}-header-month-Hsized .#{$primaryStyleName}-header-day {
+ width: 101px;
+}
+
+/* for others */
+.#{$primaryStyleName}-header-month-Hsized td:first-child {
+ padding-left: 21px;
+}
+
+.#{$primaryStyleName}-header-day-Hsized {
+ width: 200px;
+}
+
+.#{$primaryStyleName}-week-numbers-Vsized .#{$primaryStyleName}-week-number {
+ height: 100px;
+ line-height: 100px;
+}
+
+.#{$primaryStyleName}-week-wrapper-Vsized {
+ height: 400px;
+ overflow-x: hidden !important;
+}
+
+.#{$primaryStyleName}-times-Vsized .#{$primaryStyleName}-time {
+ height: 38px;
+}
+
+.#{$primaryStyleName}-times-Hsized .#{$primaryStyleName}-time {
+ width: 42px;
+}
+
+.#{$primaryStyleName}-day-times-Vsized .v-datecellslot,.#{$primaryStyleName}-day-times-Vsized .v-datecellslot-even {
+ height: 18px;
+}
+
+.#{$primaryStyleName}-day-times-Hsized, .#{$primaryStyleName}-day-times-Hsized .v-datecellslot,.#{$primaryStyleName}-day-times-Hsized .v-datecellslot-even {
+ width: 200px;
+}
+
+} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/calendar/img/arrows.png b/WebContent/VAADIN/themes/base/calendar/img/arrows.png
new file mode 100644
index 0000000000..9905c0b065
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/calendar/img/arrows.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/base/common/common.scss b/WebContent/VAADIN/themes/base/common/common.scss
index e7fdd3fe84..48890488fb 100644
--- a/WebContent/VAADIN/themes/base/common/common.scss
+++ b/WebContent/VAADIN/themes/base/common/common.scss
@@ -204,6 +204,11 @@ body &.v-app-loading {
padding: 2px;
}
+/* Removes clear button from input fields introduced by IE10 */
+input::-ms-clear {
+ display: none;
+}
+
.v-drag-element {
z-index: 60000;
/* override any other position: properties */
@@ -232,5 +237,13 @@ body &.v-app-loading {
width: 0;
height: 0;
}
+}
-} \ No newline at end of file
+/* Outside the base mixin because elements might be added directly to the body */
+.v-assistive-device-only {
+ position: absolute;
+ top: -2000px;
+ left: -2000px;
+ width: 10px;
+ overflow: hidden;
+}
diff --git a/WebContent/VAADIN/themes/base/datefield/datefield.scss b/WebContent/VAADIN/themes/base/datefield/datefield.scss
index 1d3d408ed2..cbba9b46f3 100644
--- a/WebContent/VAADIN/themes/base/datefield/datefield.scss
+++ b/WebContent/VAADIN/themes/base/datefield/datefield.scss
@@ -59,10 +59,21 @@
.v-disabled .#{$primaryStyleName}-calendarpanel-day-today {
cursor: default;
}
-.#{$primaryStyleName}-calendarpanel-day-disabled {
+.#{$primaryStyleName}-calendarpanel-day-disabled,
+.#{$primaryStyleName}-calendarpanel-day-outside-range {
cursor: default;
opacity: .5;
}
+
+.#{$primaryStyleName}-calendarpanel-prevyear,
+.#{$primaryStyleName}-calendarpanel-nextyear,
+.#{$primaryStyleName}-calendarpanel-prevmonth,
+.#{$primaryStyleName}-calendarpanel-nextmonth {
+ button.outside-range{
+ opacity: .5;
+ }
+}
+
.#{$primaryStyleName}-calendarpanel-day-selected {
cursor: default;
background: #333;
diff --git a/WebContent/VAADIN/themes/base/debug/debug.scss b/WebContent/VAADIN/themes/base/debug/debug.scss
index b6d22e8433..687370270e 100644
--- a/WebContent/VAADIN/themes/base/debug/debug.scss
+++ b/WebContent/VAADIN/themes/base/debug/debug.scss
@@ -29,4 +29,221 @@
.v-app .invalidlayout * {
background: #f99 !important;
}
+
+ /* NEW debug window */
+ $mainbg: #fff;
+ $darkborder: #666;
+ $lightborder: #999;
+ $maincolor: #666;
+ $activecolor: #000;
+
+ @font-face {
+ font-family: 'vdebugfont';
+ src:url('fonts/font.eot');
+ src:url('fonts/font.eot?#iefix') format('embedded-opentype'),
+ url('fonts/font.woff') format('woff'),
+ url('fonts/font.ttf') format('truetype'),
+ url('fonts/font.svg#fontawesome') format('svg');
+ font-weight: normal;
+ font-style: normal;
+ }
+
+ .v-debugwindow [data-icon]:before,
+ .v-debugwindow-menu [data-icon]:before {
+ font-family: 'vdebugfont';
+ content: attr(data-icon);
+ speak: none;
+ font-weight: normal;
+ font-variant: normal;
+ text-transform: none;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ font-style: normal;
+ vertical-align: text-bottom;
+ }
+
+ .v-debugwindow {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+
+ -moz-opacity: 0.8;
+ -webkit-opacity: 0.8;
+ opacity: 0.8;
+ color: $maincolor;
+
+ font-size: 13px;
+ }
+ .v-debugwindow:hover {
+ -moz-opacity: 1;
+ -webkit-opacity: 1;
+ opacity: 1;
+ }
+ .v-debugwindow * {
+ font-size: inherit !important;
+ }
+
+ .v-debugwindow-size0, .v-debugwindow-menu .v-debugwindow-button-size0 {
+ font-size: 10px;
+ }
+ .v-debugwindow-size1, .v-debugwindow-menu .v-debugwindow-button-size1 {
+ font-size: 13px;
+ }
+ .v-debugwindow-size2, .v-debugwindow-menu .v-debugwindow-button-size2 {
+ font-size: 16px;
+ }
+
+ .v-debugwindow-head {
+ text-align: right;
+ cursor: move;
+ bakcground-color: transparent;
+ }
+
+ .v-debugwindow-tabs {
+ display: inline-block;
+ background-color: $mainbg;
+ }
+
+ .v-debugwindow-tab, .v-debugwindow-controls > * {
+ width: 2em;
+ border: none;
+ margin: 0;
+ line-height: 1.5em;
+ background-color: $mainbg;
+ color: $maincolor;
+ }
+ .v-debugwindow-tab {
+ position: relative;
+ top: 1px;
+ border-width: 1px 0 1px 1px;
+ border-style: solid;
+ border-color: $darkborder;
+ border-radius: 2px 2px 0 0;
+ }
+ .v-debugwindow-tab-selected {
+ color: $maincolor;
+ background-color: $mainbg;
+ border-bottom: 1px solid #fff;
+ }
+
+ .v-debugwindow-controls {
+ position: relative;
+ top: 1px;
+ display: inline-block;
+ background-color: $mainbg;
+ border: 1px solid $darkborder;
+ border-radius: 2px 2px 0 0;
+ }
+
+ .v-debugwindow-section-head {
+ text-align: left;
+ background-color: $mainbg;
+ border: 1px solid $darkborder;
+ border-bottom: 1px solid $lightborder;
+
+ box-shadow: 0px 0px 7px 0 rgba(55,55,55,0.6);
+ min-height: 1.5em;
+ }
+
+ .v-debugwindow-button {
+ border: none;
+ background-color: transparent;
+ color: $maincolor;
+ }
+ .v-debugwindow-button:hover {
+ color: $activecolor;
+ text-decoration: underline;
+ }
+ .v-debugwindow-button-active {
+ color: $maincolor;
+ box-shadow: 1px 1px 3px 0 inset;
+ }
+
+ .v-debugwindow-content {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+
+ box-shadow: 0px 0px 7px 0 rgba(55,55,55,0.6);
+
+ background-color: $mainbg;
+ border: 1px solid $darkborder;
+ border-top: none;
+
+ font-family: monospace;
+ }
+
+ .v-debugwindow-menu {
+ background-color: $mainbg;
+ padding: 4px;
+ border: 1px solid $lightborder;
+ border-top: none;
+
+ border-radius: 0 0 5px 5px;
+
+ box-shadow: 0px 0px 7px 0 rgba(55,55,55,0.6);
+ }
+ .v-debugwindow-menu-content {
+ min-width: 100px;
+ }
+ .v-debugwindow-menu-content .v-debugwindow-button {
+ line-height: 22px;
+ }
+ .v-debugwindow-menu-content > div > .v-debugwindow-button {
+ width: 33%;
+ }
+
+
+ /* LOG */
+ .v-debugwindow-reset {
+ color: #fff;
+ background-color: #4C92ED;
+ padding: 4px;
+ }
+
+ .v-debugwindow-row {
+ display: table-row;
+ }
+ .v-debugwindow-row:nth-child(odd) {
+ background-color: rgba(0, 61, 255, 0.11);
+ }
+ .v-debugwindow-row.ERROR {
+ color: #550000;
+ background-color: #FFC5C5;
+ }
+ .v-debugwindow-row.WARNING {
+ background-color: #FFFF99;
+ }
+
+ .v-debugwindow-row > span {
+ display: table-cell;
+ padding: 4px;
+ }
+
+ .v-debugwindow-time {
+ text-align: right;
+ color: #999;
+ }
+ .v-debugwindow-message {
+ white-space: nowrap;
+ width: 100%
+ }
+ .v-debugwindow-message:hover {
+ white-space: normal;
+ word-wrap: break-word;
+ }
+ .v-debugwindow-message em {
+ background-color: #C4E6F8;
+ }
+
+ /* HIERARCHY */
+ .v-debugwindow-row > span.caption {
+ color: #999;
+ text-align: right;
+ white-space: nowrap;
+ }
+ .v-debugwindow-row > span.value {
+ width: 100%;
+ }
+
} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/debug/fonts/font.dev.svg b/WebContent/VAADIN/themes/base/debug/fonts/font.dev.svg
new file mode 100644
index 0000000000..24fa9ceeed
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/debug/fonts/font.dev.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+This is a custom SVG font generated by IcoMoon.
+<iconset grid="14"></iconset>
+</metadata>
+<defs>
+<font id="fontawesome" horiz-adv-x="448" >
+<font-face units-per-em="448" ascent="384" descent="-64" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode="&#xf002;" d="M 288.00,176.00q0.00,46.25 -32.875,79.125t-79.125,32.875t-79.125-32.875t-32.875-79.125t 32.875-79.125t 79.125-32.875t 79.125,32.875t 32.875,79.125zM 416.00-32.00q0.00-13.00 -9.50-22.50t-22.50-9.50q-13.50,0.00 -22.50,9.50l-85.75,85.50q-44.75-31.00 -99.75-31.00q-35.75,0.00 -68.375,13.875t-56.25,37.50t-37.50,56.25t-13.875,68.375 t 13.875,68.375t 37.50,56.25t 56.25,37.50t 68.375,13.875t 68.375-13.875t 56.25-37.50t 37.50-56.25t 13.875-68.375q0.00-55.00 -31.00-99.75l 85.75-85.75q 9.25-9.25 9.25-22.50z" horiz-adv-x="416" data-tags="search, magnifier, lookup, find" />
+<glyph unicode="&#xf00c;" d="M 417.75,242.50q0.00-10.00 -7.00-17.00l-181.00-181.00l-34.00-34.00q-7.00-7.00 -17.00-7.00t-17.00,7.00l-34.00,34.00l-90.50,90.50q-7.00,7.00 -7.00,17.00t 7.00,17.00l 34.00,34.00q 7.00,7.00 17.00,7.00t 17.00-7.00l 73.50-73.75l 164.00,164.25q 7.00,7.00 17.00,7.00t 17.00-7.00l 34.00-34.00q 7.00-7.00 7.00-17.00z" data-tags="ok, checkmark, tick, correct" />
+<glyph unicode="&#xf00d;" d="M 324.50,53.50q0.00-10.00 -7.00-17.00l-34.00-34.00q-7.00-7.00 -17.00-7.00t-17.00,7.00l-73.50,73.50l-73.50-73.50q-7.00-7.00 -17.00-7.00t-17.00,7.00l-34.00,34.00q-7.00,7.00 -7.00,17.00t 7.00,17.00l 73.50,73.50l-73.50,73.50q-7.00,7.00 -7.00,17.00t 7.00,17.00l 34.00,34.00q 7.00,7.00 17.00,7.00t 17.00-7.00l 73.50-73.50l 73.50,73.50q 7.00,7.00 17.00,7.00t 17.00-7.00l 34.00-34.00q 7.00-7.00 7.00-17.00 t-7.00-17.00l-73.50-73.50l 73.50-73.50q 7.00-7.00 7.00-17.00z" horiz-adv-x="352" data-tags="remove, cancel, close, delete, mutiply" />
+<glyph unicode="&#xf011;" d="M 384.00,160.00q0.00-39.00 -15.25-74.50t-41.00-61.25t-61.25-41.00t-74.50-15.25t-74.50,15.25t-61.25,41.00t-41.00,61.25t-15.25,74.50q0.00,45.50 20.125,85.75t 56.625,67.50q 10.75,8.00 23.875,6.25t 20.875-12.50q 8.00-10.50 6.125-23.625t-12.375-21.125q-24.50-18.50 -37.875-45.25t-13.375-57.00q0.00-26.00 10.125-49.625t 27.375-40.875t 40.875-27.375 t 49.625-10.125t 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625q0.00,30.25 -13.375,57.00t-37.875,45.25q-10.50,8.00 -12.375,21.125t 6.125,23.625q 7.75,10.75 21.00,12.50t 23.75-6.25q 36.50-27.25 56.625-67.50t 20.125-85.75zM 224.00,352.00l0.00-160.00 q0.00-13.00 -9.50-22.50t-22.50-9.50t-22.50,9.50t-9.50,22.50l0.00,160.00 q0.00,13.00 9.50,22.50t 22.50,9.50t 22.50-9.50t 9.50-22.50z" horiz-adv-x="384" data-tags="off, switch, power" />
+<glyph unicode="&#xf014;" d="M 128.00,200.00l0.00-144.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-16.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,144.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 16.00,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75zM 192.00,200.00l0.00-144.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-16.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,144.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 16.00,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75zM 256.00,200.00l0.00-144.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-16.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,144.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 16.00,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75zM 288.00,19.00l0.00,237.00 l-224.00,0.00 l0.00-237.00 q0.00-5.50 1.75-10.125t 3.625-6.75t 2.625-2.125l 208.00,0.00 q 0.75,0.00 2.625,2.125t 3.625,6.75t 1.75,10.125zM 120.00,288.00l 112.00,0.00 l-12.00,29.25q-1.75,2.25 -4.25,2.75l-79.25,0.00 q-2.50-0.50 -4.25-2.75zM 352.00,280.00l0.00-16.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-24.00,0.00 l0.00-237.00 q0.00-20.75 -11.75-35.875t-28.25-15.125l-208.00,0.00 q-16.50,0.00 -28.25,14.625t-11.75,35.375l0.00,238.00 l-24.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,16.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 77.25,0.00 l 17.50,41.75q 3.75,9.25 13.50,15.75t 19.75,6.50l 80.00,0.00 q 10.00,0.00 19.75-6.50t 13.50-15.75l 17.50-41.75l 77.25,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75z" horiz-adv-x="352" data-tags="trash, remove, delete, bin" />
+<glyph unicode="&#xf017;" d="M 272.00,152.00l0.00-16.00 q0.00-3.25 -2.375-5.625t-5.625-2.375l-96.00,0.00 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,112.00 q0.00,3.25 2.375,5.625t 5.625,2.375l 16.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625l0.00-88.00 l 72.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625zM 320.00,160.00q0.00,26.00 -10.125,49.625t-27.375,40.875t-40.875,27.375t-49.625,10.125t-49.625-10.125 t-40.875-27.375t-27.375-40.875t-10.125-49.625t 10.125-49.625t 27.375-40.875t 40.875-27.375t 49.625-10.125t 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625zM 384.00,160.00q0.00-52.25 -25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875 t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" data-tags="time, clock" />
+<glyph unicode="&#xf066;" d="M 192.00,144.00l0.00-112.00 q0.00-6.50 -4.75-11.25t-11.25-4.75t-11.25,4.75l-36.00,36.00l-83.00-83.00q-2.50-2.50 -5.75-2.50t-5.75,2.50l-28.50,28.50q-2.50,2.50 -2.50,5.75t 2.50,5.75l 83.00,83.00l-36.00,36.00q-4.75,4.75 -4.75,11.25t 4.75,11.25t 11.25,4.75l 112.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25zM 380.75,312.00q0.00-3.25 -2.50-5.75l-83.00-83.00l 36.00-36.00q 4.75-4.75 4.75-11.25t-4.75-11.25 t-11.25-4.75l-112.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,112.00 q0.00,6.50 4.75,11.25t 11.25,4.75t 11.25-4.75l 36.00-36.00l 83.00,83.00q 2.50,2.50 5.75,2.50t 5.75-2.50l 28.50-28.50q 2.50-2.50 2.50-5.75z" horiz-adv-x="384" data-tags="resize-small, contract, collapse" />
+<glyph unicode="&#xf071;" d="M 256.00,40.25l0.00,47.50 q0.00,3.50 -2.375,5.875t-5.625,2.375l-48.00,0.00 q-3.25,0.00 -5.625-2.375t-2.375-5.875l0.00-47.50 q0.00-3.50 2.375-5.875t 5.625-2.375l 48.00,0.00 q 3.25,0.00 5.625,2.375t 2.375,5.875zM 255.50,133.75l 4.50,114.75q0.00,3.00 -2.50,4.75q-3.25,2.75 -6.00,2.75l-55.00,0.00 q-2.75,0.00 -6.00-2.75q-2.50-1.75 -2.50-5.25l 4.25-114.25q0.00-2.50 2.50-4.125t 6.00-1.625l 46.25,0.00 q 3.50,0.00 5.875,1.625t 2.625,4.125zM 252.00,367.25l 192.00-352.00q 8.75-15.75 -0.50-31.50q-4.25-7.25 -11.625-11.50t-15.875-4.25l-384.00,0.00 q-8.50,0.00 -15.875,4.25t-11.625,11.50q-9.25,15.75 -0.50,31.50l 192.00,352.00q 4.25,7.75 11.75,12.25t 16.25,4.50t 16.25-4.50t 11.75-12.25z" data-tags="warning-sign, sign" />
+<glyph unicode="&#xf05a;" d="M 256.00,40.00l0.00,16.00 q0.00,3.50 -2.25,5.75t-5.75,2.25l-24.00,0.00 l0.00,120.00 q0.00,3.50 -2.25,5.75t-5.75,2.25l-80.00,0.00 q-3.50,0.00 -5.75-2.25t-2.25-5.75l0.00-16.00 q0.00-3.50 2.25-5.75t 5.75-2.25l 24.00,0.00 l0.00-96.00 l-24.00,0.00 q-3.50,0.00 -5.75-2.25t-2.25-5.75l0.00-16.00 q0.00-3.50 2.25-5.75t 5.75-2.25l 112.00,0.00 q 3.50,0.00 5.75,2.25t 2.25,5.75zM 224.00,232.00l0.00,48.00 q0.00,3.50 -2.25,5.75t-5.75,2.25l-48.00,0.00 q-3.50,0.00 -5.75-2.25t-2.25-5.75l0.00-48.00 q0.00-3.50 2.25-5.75 t 5.75-2.25l 48.00,0.00 q 3.50,0.00 5.75,2.25t 2.25,5.75zM 384.00,160.00q0.00-52.25 -25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" data-tags="info-sign, information, sign" />
+<glyph unicode="&#xf06a;" d="M 192.00,352.00q 52.25,0.00 96.375-25.75t 69.875-69.875t 25.75-96.375t-25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75zM 224.00,40.25l0.00,47.50 q0.00,3.50 -2.25,5.875t-5.50,2.375l-48.00,0.00 q-3.25,0.00 -5.75-2.50t-2.50-5.75l0.00-47.50 q0.00-3.25 2.50-5.75t 5.75-2.50l 48.00,0.00 q 3.25,0.00 5.50,2.375t 2.25,5.875zM 223.50,126.25l 4.50,155.25q0.00,3.00 -2.50,4.50q-2.50,2.00 -6.00,2.00l-55.00,0.00 q-3.50,0.00 -6.00-2.00q-2.50-1.50 -2.50-4.50l 4.25-155.25q0.00-2.50 2.50-4.375t 6.00-1.875l 46.25,0.00 q 3.50,0.00 5.875,1.875t 2.625,4.375z" horiz-adv-x="384" data-tags="exclamation-sign, sign, notification, attention, warning" />
+<glyph unicode="&#xf05b;" d="M 299.25,128.00l-27.25,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 27.25,0.00 q-8.00,27.00 -28.125,47.125t-47.125,28.125l0.00-27.25 q0.00-6.50 -4.75-11.25t-11.25-4.75l-32.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,27.25 q-27.00-8.00 -47.125-28.125t-28.125-47.125l 27.25,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-27.25,0.00 q 8.00-27.00 28.125-47.125t 47.125-28.125l0.00,27.25 q0.00,6.50 4.75,11.25t 11.25,4.75l 32.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25l0.00-27.25 q 27.00,8.00 47.125,28.125t 28.125,47.125zM 384.00,176.00l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-35.75,0.00 q-9.25-40.25 -38.625-69.625t-69.625-38.625l0.00-35.75 q0.00-6.50 -4.75-11.25t-11.25-4.75l-32.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,35.75 q-40.25,9.25 -69.625,38.625t-38.625,69.625l-35.75,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 35.75,0.00 q 9.25,40.25 38.625,69.625t 69.625,38.625l0.00,35.75 q0.00,6.50 4.75,11.25t 11.25,4.75l 32.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25l0.00-35.75 q 40.25-9.25 69.625-38.625t 38.625-69.625l 35.75,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" data-tags="screenshot, target, goal, spot" />
+<glyph unicode="&#xf0c9;" d="M 384.00,48.00l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-352.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 352.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25zM 384.00,176.00l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-352.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 352.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25zM 384.00,304.00l0.00-32.00 q0.00-6.50 -4.75-11.25 t-11.25-4.75l-352.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 352.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" data-tags="reorder, list, menu" />
+<glyph unicode="&#xf0d0;" d="M 297.50,238.75l 73.25,73.25l-26.75,26.75l-73.25-73.25zM 409.25,312.00q0.00-6.75 -4.50-11.25l-321.50-321.50q-4.50-4.50 -11.25-4.50t-11.25,4.50l-49.50,49.50q-4.50,4.50 -4.50,11.25t 4.50,11.25l 321.50,321.50q 4.50,4.50 11.25,4.50t 11.25-4.50l 49.50-49.50q 4.50-4.50 4.50-11.25zM 71.50,359.50l 24.50-7.50l-24.50-7.50l-7.50-24.50l-7.50,24.50l-24.50,7.50l 24.50,7.50l 7.50,24.50zM 159.00,319.00 l 49.00-15.00l-49.00-15.00l-15.00-49.00l-15.00,49.00l-49.00,15.00l 49.00,15.00l 15.00,49.00zM 391.50,199.50l 24.50-7.50l-24.50-7.50l-7.50-24.50l-7.50,24.50l-24.50,7.50l 24.50,7.50l 7.50,24.50zM 231.50,359.50l 24.50-7.50l-24.50-7.50l-7.50-24.50l-7.50,24.50l-24.50,7.50l 24.50,7.50l 7.50,24.50z" horiz-adv-x="416" data-tags="magic, wand, wizard" />
+<glyph unicode="&#xf0e8;" d="M 448.00,72.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-80.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 24.00,0.00 l0.00,48.00 l-128.00,0.00 l0.00-48.00 l 24.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-80.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 24.00,0.00 l0.00,48.00 l-128.00,0.00 l0.00-48.00 l 24.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-80.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 24.00,0.00 l0.00,48.00 q0.00,13.00 9.50,22.50t 22.50,9.50l 128.00,0.00 l0.00,48.00 l-24.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 80.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-24.00,0.00 l0.00-48.00 l 128.00,0.00 q 13.00,0.00 22.50-9.50t 9.50-22.50l0.00-48.00 l 24.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00 z" data-tags="sitemap, tree" />
+<glyph unicode="&#xf013;" d="M 256.00,160.00q0.00,26.50 -18.75,45.25t-45.25,18.75t-45.25-18.75t-18.75-45.25t 18.75-45.25t 45.25-18.75t 45.25,18.75t 18.75,45.25zM 384.00,187.25l0.00-55.50 q0.00-3.00 -2.00-5.75t-5.00-3.25l-46.25-7.00q-4.75-13.50 -9.75-22.75q 8.75-12.50 26.75-34.50q 2.50-3.00 2.50-6.25t-2.25-5.75q-6.75-9.25 -24.75-27.00t-23.50-17.75q-3.00,0.00 -6.50,2.25l-34.50,27.00q-11.00-5.75 -22.75-9.50 q-4.00-34.00 -7.25-46.50q-1.75-7.00 -9.00-7.00l-55.50,0.00 q-3.50,0.00 -6.125,2.125t-2.875,5.375l-7.00,46.00q-12.25,4.00 -22.50,9.25l-35.25-26.75q-2.50-2.25 -6.25-2.25q-3.50,0.00 -6.25,2.75q-31.50,28.50 -41.25,42.00q-1.75,2.50 -1.75,5.75q0.00,3.00 2.00,5.75q 3.75,5.25 12.75,16.625t 13.50,17.625q-6.75,12.50 -10.25,24.75l-45.75,6.75q-3.25,0.50 -5.25,3.125t-2.00,5.875l0.00,55.50 q0.00,3.00 2.00,5.75t 4.75,3.25 l 46.50,7.00q 3.50,11.50 9.75,23.00q-10.00,14.25 -26.75,34.50q-2.50,3.00 -2.50,6.00q0.00,2.50 2.25,5.75q 6.50,9.00 24.625,26.875t 23.625,17.875q 3.25,0.00 6.50-2.50l 34.50-26.75q 11.00,5.75 22.75,9.50q 4.00,34.00 7.25,46.50q 1.75,7.00 9.00,7.00l 55.50,0.00 q 3.50,0.00 6.125-2.125t 2.875-5.375l 7.00-46.00q 12.25-4.00 22.50-9.25l 35.50,26.75q 2.25,2.25 6.00,2.25q 3.25,0.00 6.25-2.50q 32.25-29.75 41.25-42.50q 1.75-2.00 1.75-5.50 q0.00-3.00 -2.00-5.75q-3.75-5.25 -12.75-16.625t-13.50-17.625q 6.50-12.50 10.25-24.50l 45.75-7.00q 3.25-0.50 5.25-3.125t 2.00-5.875z" horiz-adv-x="384" data-tags="cog, settings, options, gear, preferences" />
+<glyph unicode="&#xf0ec;" d="M 448.00,88.00l0.00-48.00 q0.00-3.25 -2.375-5.625t-5.625-2.375l-344.00,0.00 l0.00-48.00 q0.00-3.25 -2.375-5.625t-5.625-2.375q-3.00,0.00 -6.00,2.50l-79.75,80.00q-2.25,2.25 -2.25,5.50q0.00,3.50 2.25,5.75l 80.00,80.00q 2.25,2.25 5.75,2.25q 3.25,0.00 5.625-2.375t 2.375-5.625l0.00-48.00 l 344.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625zM 448.00,224.00q0.00-3.50 -2.25-5.75l-80.00-80.00q-2.25-2.25 -5.75-2.25 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,48.00 l-344.00,0.00 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,48.00 q0.00,3.25 2.375,5.625t 5.625,2.375l 344.00,0.00 l0.00,48.00 q0.00,3.50 2.25,5.75t 5.75,2.25q 3.00,0.00 6.00-2.50l 79.75-79.75q 2.25-2.25 2.25-5.75z" data-tags="exchange, transfer, tab, traffic" />
+<glyph unicode="&#xf0f0;" d="M 96.00,48.00q0.00-6.50 -4.75-11.25t-11.25-4.75t-11.25,4.75t-4.75,11.25t 4.75,11.25t 11.25,4.75t 11.25-4.75t 4.75-11.25zM 352.00,32.75q0.00-30.25 -18.25-47.50t-48.50-17.25l-218.50,0.00 q-30.25,0.00 -48.50,17.25t-18.25,47.50q0.00,17.00 1.375,32.75t 6.00,34.50t 11.875,33.125t 20.25,25.75t 30.00,15.125q-5.50-13.00 -5.50-30.00l0.00-50.75 q-14.50-5.00 -23.25-17.50t-8.75-27.75q0.00-20.00 14.00-34.00t 34.00-14.00 t 34.00,14.00t 14.00,34.00q0.00,15.25 -8.875,27.75t-23.125,17.50l0.00,50.75 q0.00,15.50 6.25,23.25q 33.00-26.00 73.75-26.00t 73.75,26.00q 6.25-7.75 6.25-23.25l0.00-16.00 q-26.50,0.00 -45.25-18.75t-18.75-45.25l0.00-22.25 q-8.00-7.25 -8.00-17.75q0.00-10.00 7.00-17.00t 17.00-7.00t 17.00,7.00t 7.00,17.00q0.00,10.50 -8.00,17.75l0.00,22.25 q0.00,13.00 9.50,22.50t 22.50,9.50t 22.50-9.50t 9.50-22.50l0.00-22.25 q-8.00-7.25 -8.00-17.75q0.00-10.00 7.00-17.00 t 17.00-7.00t 17.00,7.00t 7.00,17.00q0.00,10.50 -8.00,17.75l0.00,22.25 q0.00,17.00 -8.625,31.875t-23.375,23.375q0.00,2.50 0.125,10.625t0.00,12.00t-0.625,10.375t-1.75,11.75t-3.25,10.00q 17.00-3.75 30.00-15.125t 20.25-25.75t 11.875-33.125t 6.00-34.50t 1.375-32.75zM 272.00,256.00q0.00-39.75 -28.125-67.875t-67.875-28.125t-67.875,28.125t-28.125,67.875t 28.125,67.875t 67.875,28.125 t 67.875-28.125t 28.125-67.875z" horiz-adv-x="352" data-tags="user-md, medic, doctor" />
+<glyph unicode="&#xf023;" d="M 176.00,128.00q0.00,13.25 -9.375,22.625t-22.625,9.375t-22.625-9.375t-9.375-22.625q0.00-9.25 4.75-16.75t 12.75-11.75l-17.25-57.25q-1.25-3.75 1.25-7.00t 6.50-3.25l 48.00,0.00 q 4.00,0.00 6.50,3.25t 1.25,7.00l-17.25,57.25q 8.00,4.25 12.75,11.75t 4.75,16.75zM 80.00,192.00l 128.00,0.00 l0.00,48.00 q0.00,26.50 -18.75,45.25t-45.25,18.75t-45.25-18.75t-18.75-45.25l0.00-48.00 zM 288.00,168.00l0.00-144.00 q0.00-10.00 -7.00-17.00 t-17.00-7.00l-240.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,144.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 8.00,0.00 l0.00,48.00 q0.00,46.00 33.00,79.00t 79.00,33.00t 79.00-33.00t 33.00-79.00l0.00-48.00 l 8.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00z" horiz-adv-x="288" data-tags="lock, password, secure, private, protected, encrypted" />
+<glyph unicode="&#xf10c;" d="M 320.00,160.00q0.00,26.00 -10.125,49.625t-27.375,40.875t-40.875,27.375t-49.625,10.125t-49.625-10.125t-40.875-27.375t-27.375-40.875t-10.125-49.625t 10.125-49.625t 27.375-40.875t 40.875-27.375t 49.625-10.125t 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625zM 384.00,160.00q0.00-52.25 -25.75-96.375 t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" data-tags="circle-blank" />
+<glyph unicode="&#xf111;" d="M 384.00,160.00q0.00-52.25 -25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" data-tags="circle" />
+<glyph unicode="&#xf110;" d="M 124.00,48.00q0.00-15.00 -10.625-25.50t-25.375-10.50q-15.00,0.00 -25.50,10.50t-10.50,25.50t 10.50,25.50t 25.50,10.50q 14.75,0.00 25.375-10.50t 10.625-25.50zM 232.00,0.00q0.00-13.25 -9.375-22.625t-22.625-9.375t-22.625,9.375t-9.375,22.625t 9.375,22.625t 22.625,9.375t 22.625-9.375t 9.375-22.625zM 80.00,160.00q0.00-16.50 -11.75-28.25t-28.25-11.75t-28.25,11.75t-11.75,28.25 t 11.75,28.25t 28.25,11.75t 28.25-11.75t 11.75-28.25zM 340.00,48.00q0.00-11.50 -8.25-19.75t-19.75-8.25t-19.75,8.25t-8.25,19.75t 8.25,19.75t 19.75,8.25t 19.75-8.25t 8.25-19.75zM 132.00,272.00q0.00-18.25 -12.875-31.125t-31.125-12.875t-31.125,12.875t-12.875,31.125t 12.875,31.125t 31.125,12.875t 31.125-12.875t 12.875-31.125zM 248.00,320.00q0.00-20.00 -14.00-34.00t-34.00-14.00 t-34.00,14.00t-14.00,34.00t 14.00,34.00t 34.00,14.00t 34.00-14.00t 14.00-34.00zM 384.00,160.00q0.00-10.00 -7.00-17.00t-17.00-7.00t-17.00,7.00t-7.00,17.00t 7.00,17.00t 17.00,7.00t 17.00-7.00t 7.00-17.00zM 332.00,272.00q0.00-8.25 -5.875-14.125t-14.125-5.875t-14.125,5.875t-5.875,14.125t 5.875,14.125t 14.125,5.875t 14.125-5.875t 5.875-14.125z" horiz-adv-x="392" data-tags="spinner, loading, busy, progress" />
+<glyph unicode="&#xf05e;" d="M 320.00,160.00q0.00,34.75 -17.75,65.00l-175.25-175.25q 30.25-17.75 65.00-17.75q 26.00,0.00 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625zM 81.75,95.00l 175.25,175.25q-30.25,17.75 -65.00,17.75q-26.00,0.00 -49.625-10.125t-40.875-27.375t-27.375-40.875t-10.125-49.625q0.00-34.75 17.75-65.00zM 384.00,160.00q0.00-52.25 -25.75-96.375 t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" data-tags="ban-circle, block, forbidden" />
+<glyph unicode="&#xf065;" d="M 188.75,120.00q0.00-3.25 -2.50-5.75l-83.00-83.00l 36.00-36.00q 4.75-4.75 4.75-11.25t-4.75-11.25t-11.25-4.75l-112.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,112.00 q0.00,6.50 4.75,11.25t 11.25,4.75t 11.25-4.75l 36.00-36.00l 83.00,83.00q 2.50,2.50 5.75,2.50t 5.75-2.50l 28.50-28.50q 2.50-2.50 2.50-5.75zM 384.00,336.00l0.00-112.00 q0.00-6.50 -4.75-11.25t-11.25-4.75t-11.25,4.75l-36.00,36.00l-83.00-83.00 q-2.50-2.50 -5.75-2.50t-5.75,2.50l-28.50,28.50q-2.50,2.50 -2.50,5.75t 2.50,5.75l 83.00,83.00l-36.00,36.00q-4.75,4.75 -4.75,11.25t 4.75,11.25t 11.25,4.75l 112.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" data-tags="resize-full, expand, enlarge" />
+<glyph unicode="&#xf021;" d="M 377.75,120.00q0.00-1.25 -0.25-1.75q-16.00-67.00 -67.00-108.625t-119.50-41.625q-36.50,0.00 -70.625,13.75t-60.875,39.25l-32.25-32.25q-4.75-4.75 -11.25-4.75t-11.25,4.75t-4.75,11.25l0.00,112.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 112.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25t-4.75-11.25l-34.25-34.25q 17.75-16.50 40.25-25.50t 46.75-9.00q 33.50,0.00 62.50,16.25t 46.50,44.75q 2.75,4.25 13.25,29.25 q 2.00,5.75 7.50,5.75l 48.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625zM 384.00,320.00l0.00-112.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-112.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25t 4.75,11.25l 34.50,34.50q-37.00,34.25 -87.25,34.25q-33.50,0.00 -62.50-16.25t-46.50-44.75q-2.75-4.25 -13.25-29.25q-2.00-5.75 -7.50-5.75l-49.75,0.00 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,1.75 q 16.25,67.00 67.50,108.625t 120.00,41.625 q 36.50,0.00 71.00-13.875t 61.25-39.125l 32.50,32.25q 4.75,4.75 11.25,4.75t 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" data-tags="refresh, synchronize" />
+<glyph unicode="&#xf02e;" d="M 291.00,352.00q 5.75,0.00 11.00-2.25q 8.25-3.25 13.125-10.25t 4.875-15.50l0.00-322.25 q0.00-8.50 -4.875-15.50t-13.125-10.25q-4.75-2.00 -11.00-2.00q-12.00,0.00 -20.75,8.00l-110.25,106.00l-110.25-106.00q-9.00-8.25 -20.75-8.25q-5.75,0.00 -11.00,2.25q-8.25,3.25 -13.125,10.25t-4.875,15.50l0.00,322.25 q0.00,8.50 4.875,15.50t 13.125,10.25q 5.25,2.25 11.00,2.25l 262.00,0.00 z" horiz-adv-x="320" data-tags="bookmark, favorite, ribbon" />
+<glyph unicode="&#x20;" horiz-adv-x="224" />
+<glyph class="hidden" unicode="&#xf000;" d="M0,384L 448 -64L0 -64 z" horiz-adv-x="0" />
+</font></defs></svg> \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/debug/fonts/font.eot b/WebContent/VAADIN/themes/base/debug/fonts/font.eot
new file mode 100644
index 0000000000..310a74dfce
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/debug/fonts/font.eot
Binary files differ
diff --git a/WebContent/VAADIN/themes/base/debug/fonts/font.svg b/WebContent/VAADIN/themes/base/debug/fonts/font.svg
new file mode 100644
index 0000000000..8149b583fd
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/debug/fonts/font.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+This is a custom SVG font generated by IcoMoon.
+<iconset grid="14"></iconset>
+</metadata>
+<defs>
+<font id="fontawesome" horiz-adv-x="448" >
+<font-face units-per-em="448" ascent="384" descent="-64" />
+<missing-glyph horiz-adv-x="448" />
+<glyph unicode="&#xf002;" d="M 288.00,176.00q0.00,46.25 -32.875,79.125t-79.125,32.875t-79.125-32.875t-32.875-79.125t 32.875-79.125t 79.125-32.875t 79.125,32.875t 32.875,79.125zM 416.00-32.00q0.00-13.00 -9.50-22.50t-22.50-9.50q-13.50,0.00 -22.50,9.50l-85.75,85.50q-44.75-31.00 -99.75-31.00q-35.75,0.00 -68.375,13.875t-56.25,37.50t-37.50,56.25t-13.875,68.375 t 13.875,68.375t 37.50,56.25t 56.25,37.50t 68.375,13.875t 68.375-13.875t 56.25-37.50t 37.50-56.25t 13.875-68.375q0.00-55.00 -31.00-99.75l 85.75-85.75q 9.25-9.25 9.25-22.50z" horiz-adv-x="416" />
+<glyph unicode="&#xf00c;" d="M 417.75,242.50q0.00-10.00 -7.00-17.00l-181.00-181.00l-34.00-34.00q-7.00-7.00 -17.00-7.00t-17.00,7.00l-34.00,34.00l-90.50,90.50q-7.00,7.00 -7.00,17.00t 7.00,17.00l 34.00,34.00q 7.00,7.00 17.00,7.00t 17.00-7.00l 73.50-73.75l 164.00,164.25q 7.00,7.00 17.00,7.00t 17.00-7.00l 34.00-34.00q 7.00-7.00 7.00-17.00z" />
+<glyph unicode="&#xf00d;" d="M 324.50,53.50q0.00-10.00 -7.00-17.00l-34.00-34.00q-7.00-7.00 -17.00-7.00t-17.00,7.00l-73.50,73.50l-73.50-73.50q-7.00-7.00 -17.00-7.00t-17.00,7.00l-34.00,34.00q-7.00,7.00 -7.00,17.00t 7.00,17.00l 73.50,73.50l-73.50,73.50q-7.00,7.00 -7.00,17.00t 7.00,17.00l 34.00,34.00q 7.00,7.00 17.00,7.00t 17.00-7.00l 73.50-73.50l 73.50,73.50q 7.00,7.00 17.00,7.00t 17.00-7.00l 34.00-34.00q 7.00-7.00 7.00-17.00 t-7.00-17.00l-73.50-73.50l 73.50-73.50q 7.00-7.00 7.00-17.00z" horiz-adv-x="352" />
+<glyph unicode="&#xf011;" d="M 384.00,160.00q0.00-39.00 -15.25-74.50t-41.00-61.25t-61.25-41.00t-74.50-15.25t-74.50,15.25t-61.25,41.00t-41.00,61.25t-15.25,74.50q0.00,45.50 20.125,85.75t 56.625,67.50q 10.75,8.00 23.875,6.25t 20.875-12.50q 8.00-10.50 6.125-23.625t-12.375-21.125q-24.50-18.50 -37.875-45.25t-13.375-57.00q0.00-26.00 10.125-49.625t 27.375-40.875t 40.875-27.375 t 49.625-10.125t 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625q0.00,30.25 -13.375,57.00t-37.875,45.25q-10.50,8.00 -12.375,21.125t 6.125,23.625q 7.75,10.75 21.00,12.50t 23.75-6.25q 36.50-27.25 56.625-67.50t 20.125-85.75zM 224.00,352.00l0.00-160.00 q0.00-13.00 -9.50-22.50t-22.50-9.50t-22.50,9.50t-9.50,22.50l0.00,160.00 q0.00,13.00 9.50,22.50t 22.50,9.50t 22.50-9.50t 9.50-22.50z" horiz-adv-x="384" />
+<glyph unicode="&#xf014;" d="M 128.00,200.00l0.00-144.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-16.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,144.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 16.00,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75zM 192.00,200.00l0.00-144.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-16.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,144.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 16.00,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75zM 256.00,200.00l0.00-144.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-16.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,144.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 16.00,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75zM 288.00,19.00l0.00,237.00 l-224.00,0.00 l0.00-237.00 q0.00-5.50 1.75-10.125t 3.625-6.75t 2.625-2.125l 208.00,0.00 q 0.75,0.00 2.625,2.125t 3.625,6.75t 1.75,10.125zM 120.00,288.00l 112.00,0.00 l-12.00,29.25q-1.75,2.25 -4.25,2.75l-79.25,0.00 q-2.50-0.50 -4.25-2.75zM 352.00,280.00l0.00-16.00 q0.00-3.50 -2.25-5.75t-5.75-2.25l-24.00,0.00 l0.00-237.00 q0.00-20.75 -11.75-35.875t-28.25-15.125l-208.00,0.00 q-16.50,0.00 -28.25,14.625t-11.75,35.375l0.00,238.00 l-24.00,0.00 q-3.50,0.00 -5.75,2.25t-2.25,5.75l0.00,16.00 q0.00,3.50 2.25,5.75t 5.75,2.25l 77.25,0.00 l 17.50,41.75q 3.75,9.25 13.50,15.75t 19.75,6.50l 80.00,0.00 q 10.00,0.00 19.75-6.50t 13.50-15.75l 17.50-41.75l 77.25,0.00 q 3.50,0.00 5.75-2.25t 2.25-5.75z" horiz-adv-x="352" />
+<glyph unicode="&#xf017;" d="M 272.00,152.00l0.00-16.00 q0.00-3.25 -2.375-5.625t-5.625-2.375l-96.00,0.00 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,112.00 q0.00,3.25 2.375,5.625t 5.625,2.375l 16.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625l0.00-88.00 l 72.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625zM 320.00,160.00q0.00,26.00 -10.125,49.625t-27.375,40.875t-40.875,27.375t-49.625,10.125t-49.625-10.125 t-40.875-27.375t-27.375-40.875t-10.125-49.625t 10.125-49.625t 27.375-40.875t 40.875-27.375t 49.625-10.125t 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625zM 384.00,160.00q0.00-52.25 -25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875 t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" />
+<glyph unicode="&#xf066;" d="M 192.00,144.00l0.00-112.00 q0.00-6.50 -4.75-11.25t-11.25-4.75t-11.25,4.75l-36.00,36.00l-83.00-83.00q-2.50-2.50 -5.75-2.50t-5.75,2.50l-28.50,28.50q-2.50,2.50 -2.50,5.75t 2.50,5.75l 83.00,83.00l-36.00,36.00q-4.75,4.75 -4.75,11.25t 4.75,11.25t 11.25,4.75l 112.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25zM 380.75,312.00q0.00-3.25 -2.50-5.75l-83.00-83.00l 36.00-36.00q 4.75-4.75 4.75-11.25t-4.75-11.25 t-11.25-4.75l-112.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,112.00 q0.00,6.50 4.75,11.25t 11.25,4.75t 11.25-4.75l 36.00-36.00l 83.00,83.00q 2.50,2.50 5.75,2.50t 5.75-2.50l 28.50-28.50q 2.50-2.50 2.50-5.75z" horiz-adv-x="384" />
+<glyph unicode="&#xf071;" d="M 256.00,40.25l0.00,47.50 q0.00,3.50 -2.375,5.875t-5.625,2.375l-48.00,0.00 q-3.25,0.00 -5.625-2.375t-2.375-5.875l0.00-47.50 q0.00-3.50 2.375-5.875t 5.625-2.375l 48.00,0.00 q 3.25,0.00 5.625,2.375t 2.375,5.875zM 255.50,133.75l 4.50,114.75q0.00,3.00 -2.50,4.75q-3.25,2.75 -6.00,2.75l-55.00,0.00 q-2.75,0.00 -6.00-2.75q-2.50-1.75 -2.50-5.25l 4.25-114.25q0.00-2.50 2.50-4.125t 6.00-1.625l 46.25,0.00 q 3.50,0.00 5.875,1.625t 2.625,4.125zM 252.00,367.25l 192.00-352.00q 8.75-15.75 -0.50-31.50q-4.25-7.25 -11.625-11.50t-15.875-4.25l-384.00,0.00 q-8.50,0.00 -15.875,4.25t-11.625,11.50q-9.25,15.75 -0.50,31.50l 192.00,352.00q 4.25,7.75 11.75,12.25t 16.25,4.50t 16.25-4.50t 11.75-12.25z" />
+<glyph unicode="&#xf05a;" d="M 256.00,40.00l0.00,16.00 q0.00,3.50 -2.25,5.75t-5.75,2.25l-24.00,0.00 l0.00,120.00 q0.00,3.50 -2.25,5.75t-5.75,2.25l-80.00,0.00 q-3.50,0.00 -5.75-2.25t-2.25-5.75l0.00-16.00 q0.00-3.50 2.25-5.75t 5.75-2.25l 24.00,0.00 l0.00-96.00 l-24.00,0.00 q-3.50,0.00 -5.75-2.25t-2.25-5.75l0.00-16.00 q0.00-3.50 2.25-5.75t 5.75-2.25l 112.00,0.00 q 3.50,0.00 5.75,2.25t 2.25,5.75zM 224.00,232.00l0.00,48.00 q0.00,3.50 -2.25,5.75t-5.75,2.25l-48.00,0.00 q-3.50,0.00 -5.75-2.25t-2.25-5.75l0.00-48.00 q0.00-3.50 2.25-5.75 t 5.75-2.25l 48.00,0.00 q 3.50,0.00 5.75,2.25t 2.25,5.75zM 384.00,160.00q0.00-52.25 -25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" />
+<glyph unicode="&#xf06a;" d="M 192.00,352.00q 52.25,0.00 96.375-25.75t 69.875-69.875t 25.75-96.375t-25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75zM 224.00,40.25l0.00,47.50 q0.00,3.50 -2.25,5.875t-5.50,2.375l-48.00,0.00 q-3.25,0.00 -5.75-2.50t-2.50-5.75l0.00-47.50 q0.00-3.25 2.50-5.75t 5.75-2.50l 48.00,0.00 q 3.25,0.00 5.50,2.375t 2.25,5.875zM 223.50,126.25l 4.50,155.25q0.00,3.00 -2.50,4.50q-2.50,2.00 -6.00,2.00l-55.00,0.00 q-3.50,0.00 -6.00-2.00q-2.50-1.50 -2.50-4.50l 4.25-155.25q0.00-2.50 2.50-4.375t 6.00-1.875l 46.25,0.00 q 3.50,0.00 5.875,1.875t 2.625,4.375z" horiz-adv-x="384" />
+<glyph unicode="&#xf05b;" d="M 299.25,128.00l-27.25,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 27.25,0.00 q-8.00,27.00 -28.125,47.125t-47.125,28.125l0.00-27.25 q0.00-6.50 -4.75-11.25t-11.25-4.75l-32.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,27.25 q-27.00-8.00 -47.125-28.125t-28.125-47.125l 27.25,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-27.25,0.00 q 8.00-27.00 28.125-47.125t 47.125-28.125l0.00,27.25 q0.00,6.50 4.75,11.25t 11.25,4.75l 32.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25l0.00-27.25 q 27.00,8.00 47.125,28.125t 28.125,47.125zM 384.00,176.00l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-35.75,0.00 q-9.25-40.25 -38.625-69.625t-69.625-38.625l0.00-35.75 q0.00-6.50 -4.75-11.25t-11.25-4.75l-32.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,35.75 q-40.25,9.25 -69.625,38.625t-38.625,69.625l-35.75,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 35.75,0.00 q 9.25,40.25 38.625,69.625t 69.625,38.625l0.00,35.75 q0.00,6.50 4.75,11.25t 11.25,4.75l 32.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25l0.00-35.75 q 40.25-9.25 69.625-38.625t 38.625-69.625l 35.75,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" />
+<glyph unicode="&#xf0c9;" d="M 384.00,48.00l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-352.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 352.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25zM 384.00,176.00l0.00-32.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-352.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 352.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25zM 384.00,304.00l0.00-32.00 q0.00-6.50 -4.75-11.25 t-11.25-4.75l-352.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,32.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 352.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" />
+<glyph unicode="&#xf0d0;" d="M 297.50,238.75l 73.25,73.25l-26.75,26.75l-73.25-73.25zM 409.25,312.00q0.00-6.75 -4.50-11.25l-321.50-321.50q-4.50-4.50 -11.25-4.50t-11.25,4.50l-49.50,49.50q-4.50,4.50 -4.50,11.25t 4.50,11.25l 321.50,321.50q 4.50,4.50 11.25,4.50t 11.25-4.50l 49.50-49.50q 4.50-4.50 4.50-11.25zM 71.50,359.50l 24.50-7.50l-24.50-7.50l-7.50-24.50l-7.50,24.50l-24.50,7.50l 24.50,7.50l 7.50,24.50zM 159.00,319.00 l 49.00-15.00l-49.00-15.00l-15.00-49.00l-15.00,49.00l-49.00,15.00l 49.00,15.00l 15.00,49.00zM 391.50,199.50l 24.50-7.50l-24.50-7.50l-7.50-24.50l-7.50,24.50l-24.50,7.50l 24.50,7.50l 7.50,24.50zM 231.50,359.50l 24.50-7.50l-24.50-7.50l-7.50-24.50l-7.50,24.50l-24.50,7.50l 24.50,7.50l 7.50,24.50z" horiz-adv-x="416" />
+<glyph unicode="&#xf0e8;" d="M 448.00,72.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-80.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 24.00,0.00 l0.00,48.00 l-128.00,0.00 l0.00-48.00 l 24.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-80.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 24.00,0.00 l0.00,48.00 l-128.00,0.00 l0.00-48.00 l 24.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-80.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 24.00,0.00 l0.00,48.00 q0.00,13.00 9.50,22.50t 22.50,9.50l 128.00,0.00 l0.00,48.00 l-24.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,80.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 80.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00l0.00-80.00 q0.00-10.00 -7.00-17.00t-17.00-7.00l-24.00,0.00 l0.00-48.00 l 128.00,0.00 q 13.00,0.00 22.50-9.50t 9.50-22.50l0.00-48.00 l 24.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00 z" />
+<glyph unicode="&#xf013;" d="M 256.00,160.00q0.00,26.50 -18.75,45.25t-45.25,18.75t-45.25-18.75t-18.75-45.25t 18.75-45.25t 45.25-18.75t 45.25,18.75t 18.75,45.25zM 384.00,187.25l0.00-55.50 q0.00-3.00 -2.00-5.75t-5.00-3.25l-46.25-7.00q-4.75-13.50 -9.75-22.75q 8.75-12.50 26.75-34.50q 2.50-3.00 2.50-6.25t-2.25-5.75q-6.75-9.25 -24.75-27.00t-23.50-17.75q-3.00,0.00 -6.50,2.25l-34.50,27.00q-11.00-5.75 -22.75-9.50 q-4.00-34.00 -7.25-46.50q-1.75-7.00 -9.00-7.00l-55.50,0.00 q-3.50,0.00 -6.125,2.125t-2.875,5.375l-7.00,46.00q-12.25,4.00 -22.50,9.25l-35.25-26.75q-2.50-2.25 -6.25-2.25q-3.50,0.00 -6.25,2.75q-31.50,28.50 -41.25,42.00q-1.75,2.50 -1.75,5.75q0.00,3.00 2.00,5.75q 3.75,5.25 12.75,16.625t 13.50,17.625q-6.75,12.50 -10.25,24.75l-45.75,6.75q-3.25,0.50 -5.25,3.125t-2.00,5.875l0.00,55.50 q0.00,3.00 2.00,5.75t 4.75,3.25 l 46.50,7.00q 3.50,11.50 9.75,23.00q-10.00,14.25 -26.75,34.50q-2.50,3.00 -2.50,6.00q0.00,2.50 2.25,5.75q 6.50,9.00 24.625,26.875t 23.625,17.875q 3.25,0.00 6.50-2.50l 34.50-26.75q 11.00,5.75 22.75,9.50q 4.00,34.00 7.25,46.50q 1.75,7.00 9.00,7.00l 55.50,0.00 q 3.50,0.00 6.125-2.125t 2.875-5.375l 7.00-46.00q 12.25-4.00 22.50-9.25l 35.50,26.75q 2.25,2.25 6.00,2.25q 3.25,0.00 6.25-2.50q 32.25-29.75 41.25-42.50q 1.75-2.00 1.75-5.50 q0.00-3.00 -2.00-5.75q-3.75-5.25 -12.75-16.625t-13.50-17.625q 6.50-12.50 10.25-24.50l 45.75-7.00q 3.25-0.50 5.25-3.125t 2.00-5.875z" horiz-adv-x="384" />
+<glyph unicode="&#xf0ec;" d="M 448.00,88.00l0.00-48.00 q0.00-3.25 -2.375-5.625t-5.625-2.375l-344.00,0.00 l0.00-48.00 q0.00-3.25 -2.375-5.625t-5.625-2.375q-3.00,0.00 -6.00,2.50l-79.75,80.00q-2.25,2.25 -2.25,5.50q0.00,3.50 2.25,5.75l 80.00,80.00q 2.25,2.25 5.75,2.25q 3.25,0.00 5.625-2.375t 2.375-5.625l0.00-48.00 l 344.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625zM 448.00,224.00q0.00-3.50 -2.25-5.75l-80.00-80.00q-2.25-2.25 -5.75-2.25 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,48.00 l-344.00,0.00 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,48.00 q0.00,3.25 2.375,5.625t 5.625,2.375l 344.00,0.00 l0.00,48.00 q0.00,3.50 2.25,5.75t 5.75,2.25q 3.00,0.00 6.00-2.50l 79.75-79.75q 2.25-2.25 2.25-5.75z" />
+<glyph unicode="&#xf0f0;" d="M 96.00,48.00q0.00-6.50 -4.75-11.25t-11.25-4.75t-11.25,4.75t-4.75,11.25t 4.75,11.25t 11.25,4.75t 11.25-4.75t 4.75-11.25zM 352.00,32.75q0.00-30.25 -18.25-47.50t-48.50-17.25l-218.50,0.00 q-30.25,0.00 -48.50,17.25t-18.25,47.50q0.00,17.00 1.375,32.75t 6.00,34.50t 11.875,33.125t 20.25,25.75t 30.00,15.125q-5.50-13.00 -5.50-30.00l0.00-50.75 q-14.50-5.00 -23.25-17.50t-8.75-27.75q0.00-20.00 14.00-34.00t 34.00-14.00 t 34.00,14.00t 14.00,34.00q0.00,15.25 -8.875,27.75t-23.125,17.50l0.00,50.75 q0.00,15.50 6.25,23.25q 33.00-26.00 73.75-26.00t 73.75,26.00q 6.25-7.75 6.25-23.25l0.00-16.00 q-26.50,0.00 -45.25-18.75t-18.75-45.25l0.00-22.25 q-8.00-7.25 -8.00-17.75q0.00-10.00 7.00-17.00t 17.00-7.00t 17.00,7.00t 7.00,17.00q0.00,10.50 -8.00,17.75l0.00,22.25 q0.00,13.00 9.50,22.50t 22.50,9.50t 22.50-9.50t 9.50-22.50l0.00-22.25 q-8.00-7.25 -8.00-17.75q0.00-10.00 7.00-17.00 t 17.00-7.00t 17.00,7.00t 7.00,17.00q0.00,10.50 -8.00,17.75l0.00,22.25 q0.00,17.00 -8.625,31.875t-23.375,23.375q0.00,2.50 0.125,10.625t0.00,12.00t-0.625,10.375t-1.75,11.75t-3.25,10.00q 17.00-3.75 30.00-15.125t 20.25-25.75t 11.875-33.125t 6.00-34.50t 1.375-32.75zM 272.00,256.00q0.00-39.75 -28.125-67.875t-67.875-28.125t-67.875,28.125t-28.125,67.875t 28.125,67.875t 67.875,28.125 t 67.875-28.125t 28.125-67.875z" horiz-adv-x="352" />
+<glyph unicode="&#xf023;" d="M 176.00,128.00q0.00,13.25 -9.375,22.625t-22.625,9.375t-22.625-9.375t-9.375-22.625q0.00-9.25 4.75-16.75t 12.75-11.75l-17.25-57.25q-1.25-3.75 1.25-7.00t 6.50-3.25l 48.00,0.00 q 4.00,0.00 6.50,3.25t 1.25,7.00l-17.25,57.25q 8.00,4.25 12.75,11.75t 4.75,16.75zM 80.00,192.00l 128.00,0.00 l0.00,48.00 q0.00,26.50 -18.75,45.25t-45.25,18.75t-45.25-18.75t-18.75-45.25l0.00-48.00 zM 288.00,168.00l0.00-144.00 q0.00-10.00 -7.00-17.00 t-17.00-7.00l-240.00,0.00 q-10.00,0.00 -17.00,7.00t-7.00,17.00l0.00,144.00 q0.00,10.00 7.00,17.00t 17.00,7.00l 8.00,0.00 l0.00,48.00 q0.00,46.00 33.00,79.00t 79.00,33.00t 79.00-33.00t 33.00-79.00l0.00-48.00 l 8.00,0.00 q 10.00,0.00 17.00-7.00t 7.00-17.00z" horiz-adv-x="288" />
+<glyph unicode="&#xf10c;" d="M 320.00,160.00q0.00,26.00 -10.125,49.625t-27.375,40.875t-40.875,27.375t-49.625,10.125t-49.625-10.125t-40.875-27.375t-27.375-40.875t-10.125-49.625t 10.125-49.625t 27.375-40.875t 40.875-27.375t 49.625-10.125t 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625zM 384.00,160.00q0.00-52.25 -25.75-96.375 t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" />
+<glyph unicode="&#xf111;" d="M 384.00,160.00q0.00-52.25 -25.75-96.375t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" />
+<glyph unicode="&#xf110;" d="M 124.00,48.00q0.00-15.00 -10.625-25.50t-25.375-10.50q-15.00,0.00 -25.50,10.50t-10.50,25.50t 10.50,25.50t 25.50,10.50q 14.75,0.00 25.375-10.50t 10.625-25.50zM 232.00,0.00q0.00-13.25 -9.375-22.625t-22.625-9.375t-22.625,9.375t-9.375,22.625t 9.375,22.625t 22.625,9.375t 22.625-9.375t 9.375-22.625zM 80.00,160.00q0.00-16.50 -11.75-28.25t-28.25-11.75t-28.25,11.75t-11.75,28.25 t 11.75,28.25t 28.25,11.75t 28.25-11.75t 11.75-28.25zM 340.00,48.00q0.00-11.50 -8.25-19.75t-19.75-8.25t-19.75,8.25t-8.25,19.75t 8.25,19.75t 19.75,8.25t 19.75-8.25t 8.25-19.75zM 132.00,272.00q0.00-18.25 -12.875-31.125t-31.125-12.875t-31.125,12.875t-12.875,31.125t 12.875,31.125t 31.125,12.875t 31.125-12.875t 12.875-31.125zM 248.00,320.00q0.00-20.00 -14.00-34.00t-34.00-14.00 t-34.00,14.00t-14.00,34.00t 14.00,34.00t 34.00,14.00t 34.00-14.00t 14.00-34.00zM 384.00,160.00q0.00-10.00 -7.00-17.00t-17.00-7.00t-17.00,7.00t-7.00,17.00t 7.00,17.00t 17.00,7.00t 17.00-7.00t 7.00-17.00zM 332.00,272.00q0.00-8.25 -5.875-14.125t-14.125-5.875t-14.125,5.875t-5.875,14.125t 5.875,14.125t 14.125,5.875t 14.125-5.875t 5.875-14.125z" horiz-adv-x="392" />
+<glyph unicode="&#xf05e;" d="M 320.00,160.00q0.00,34.75 -17.75,65.00l-175.25-175.25q 30.25-17.75 65.00-17.75q 26.00,0.00 49.625,10.125t 40.875,27.375t 27.375,40.875t 10.125,49.625zM 81.75,95.00l 175.25,175.25q-30.25,17.75 -65.00,17.75q-26.00,0.00 -49.625-10.125t-40.875-27.375t-27.375-40.875t-10.125-49.625q0.00-34.75 17.75-65.00zM 384.00,160.00q0.00-52.25 -25.75-96.375 t-69.875-69.875t-96.375-25.75t-96.375,25.75t-69.875,69.875t-25.75,96.375t 25.75,96.375t 69.875,69.875t 96.375,25.75t 96.375-25.75t 69.875-69.875t 25.75-96.375z" horiz-adv-x="384" />
+<glyph unicode="&#xf065;" d="M 188.75,120.00q0.00-3.25 -2.50-5.75l-83.00-83.00l 36.00-36.00q 4.75-4.75 4.75-11.25t-4.75-11.25t-11.25-4.75l-112.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25l0.00,112.00 q0.00,6.50 4.75,11.25t 11.25,4.75t 11.25-4.75l 36.00-36.00l 83.00,83.00q 2.50,2.50 5.75,2.50t 5.75-2.50l 28.50-28.50q 2.50-2.50 2.50-5.75zM 384.00,336.00l0.00-112.00 q0.00-6.50 -4.75-11.25t-11.25-4.75t-11.25,4.75l-36.00,36.00l-83.00-83.00 q-2.50-2.50 -5.75-2.50t-5.75,2.50l-28.50,28.50q-2.50,2.50 -2.50,5.75t 2.50,5.75l 83.00,83.00l-36.00,36.00q-4.75,4.75 -4.75,11.25t 4.75,11.25t 11.25,4.75l 112.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" />
+<glyph unicode="&#xf021;" d="M 377.75,120.00q0.00-1.25 -0.25-1.75q-16.00-67.00 -67.00-108.625t-119.50-41.625q-36.50,0.00 -70.625,13.75t-60.875,39.25l-32.25-32.25q-4.75-4.75 -11.25-4.75t-11.25,4.75t-4.75,11.25l0.00,112.00 q0.00,6.50 4.75,11.25t 11.25,4.75l 112.00,0.00 q 6.50,0.00 11.25-4.75t 4.75-11.25t-4.75-11.25l-34.25-34.25q 17.75-16.50 40.25-25.50t 46.75-9.00q 33.50,0.00 62.50,16.25t 46.50,44.75q 2.75,4.25 13.25,29.25 q 2.00,5.75 7.50,5.75l 48.00,0.00 q 3.25,0.00 5.625-2.375t 2.375-5.625zM 384.00,320.00l0.00-112.00 q0.00-6.50 -4.75-11.25t-11.25-4.75l-112.00,0.00 q-6.50,0.00 -11.25,4.75t-4.75,11.25t 4.75,11.25l 34.50,34.50q-37.00,34.25 -87.25,34.25q-33.50,0.00 -62.50-16.25t-46.50-44.75q-2.75-4.25 -13.25-29.25q-2.00-5.75 -7.50-5.75l-49.75,0.00 q-3.25,0.00 -5.625,2.375t-2.375,5.625l0.00,1.75 q 16.25,67.00 67.50,108.625t 120.00,41.625 q 36.50,0.00 71.00-13.875t 61.25-39.125l 32.50,32.25q 4.75,4.75 11.25,4.75t 11.25-4.75t 4.75-11.25z" horiz-adv-x="384" />
+<glyph unicode="&#xf02e;" d="M 291.00,352.00q 5.75,0.00 11.00-2.25q 8.25-3.25 13.125-10.25t 4.875-15.50l0.00-322.25 q0.00-8.50 -4.875-15.50t-13.125-10.25q-4.75-2.00 -11.00-2.00q-12.00,0.00 -20.75,8.00l-110.25,106.00l-110.25-106.00q-9.00-8.25 -20.75-8.25q-5.75,0.00 -11.00,2.25q-8.25,3.25 -13.125,10.25t-4.875,15.50l0.00,322.25 q0.00,8.50 4.875,15.50t 13.125,10.25q 5.25,2.25 11.00,2.25l 262.00,0.00 z" horiz-adv-x="320" />
+<glyph unicode="&#x20;" horiz-adv-x="224" />
+<glyph class="hidden" unicode="&#xf000;" d="M0,384L 448 -64L0 -64 z" horiz-adv-x="0" />
+</font></defs></svg> \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/base/debug/fonts/font.ttf b/WebContent/VAADIN/themes/base/debug/fonts/font.ttf
new file mode 100644
index 0000000000..e26c910020
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/debug/fonts/font.ttf
Binary files differ
diff --git a/WebContent/VAADIN/themes/base/debug/fonts/font.woff b/WebContent/VAADIN/themes/base/debug/fonts/font.woff
new file mode 100644
index 0000000000..e23e3807d0
--- /dev/null
+++ b/WebContent/VAADIN/themes/base/debug/fonts/font.woff
Binary files differ
diff --git a/WebContent/VAADIN/themes/base/window/window.scss b/WebContent/VAADIN/themes/base/window/window.scss
index b9e7b54139..05f3b115ad 100644
--- a/WebContent/VAADIN/themes/base/window/window.scss
+++ b/WebContent/VAADIN/themes/base/window/window.scss
@@ -38,6 +38,10 @@
}
.#{$primaryStyleName}-header {
font-weight: bold;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ie-user-select: none;
+ user-select: none;
}
/* A more specific selector to make sure padding isn't so easily overridden */
div.#{$primaryStyleName}-header {
@@ -77,20 +81,37 @@ div.#{$primaryStyleName}-header {
.#{$primaryStyleName} div.#{$primaryStyleName}-footer-noresize {
height: 0;
}
-.#{$primaryStyleName}-resizebox-disabled {
+.#{$primaryStyleName}-resizebox-disabled,
+.#{$primaryStyleName}-restorebox-disabled,
+.#{$primaryStyleName}-maximizebox-disabled {
cursor: default;
display: none;
}
-.#{$primaryStyleName}-closebox {
+.#{$primaryStyleName}-closebox,
+.#{$primaryStyleName}-restorebox,
+.#{$primaryStyleName}-maximizebox {
position: absolute;
top: 0;
right: 0;
width: 1em;
height: 1em;
- background: red;
cursor: pointer;
overflow: hidden;
}
+.#{$primaryStyleName}-maximizebox,
+.#{$primaryStyleName}-restorebox {
+ right: 1.1em;
+}
+
+.#{$primaryStyleName}-closebox {
+ background: red;
+}
+.#{$primaryStyleName}-maximizebox {
+ background: blue;
+}
+.#{$primaryStyleName}-restorebox {
+ background: yellow;
+}
.#{$primaryStyleName}-modalitycurtain {
top: 0;
left: 0;
diff --git a/WebContent/VAADIN/themes/chameleon/components/window/window.scss b/WebContent/VAADIN/themes/chameleon/components/window/window.scss
index e9524745f8..92ada43c90 100644
--- a/WebContent/VAADIN/themes/chameleon/components/window/window.scss
+++ b/WebContent/VAADIN/themes/chameleon/components/window/window.scss
@@ -1,25 +1,39 @@
@mixin chameleon-window($primaryStyleName : v-window) {
-.#{$primaryStyleName}-closebox {
+.#{$primaryStyleName}-closebox,
+.#{$primaryStyleName}-restorebox,
+.#{$primaryStyleName}-maximizebox {
width: 14px;
height: 15px;
overflow: hidden;
- text-indent: -50px;
- background: transparent url(../../img/close-btn.png) no-repeat;
vertical-align: middle;
margin: 0;
top: .3em;
- right: .4em;
z-index: 2;
+ &:hover {
+ background-position: 0 -25px;
}
-
-.#{$primaryStyleName}-closebox:hover {
- background-position: 0 -25px;
+ &:active {
+ background-position: 0 -50px;
}
+}
+.#{$primaryStyleName}-closebox {
+ text-indent: -50px;
+ background: transparent url(../../img/close-btn.png) no-repeat;
+ right: .4em;
+}
+.#{$primaryStyleName}-restorebox,
+.#{$primaryStyleName}-maximizebox {
+ right: 1.8em;
+}
+
+.#{$primaryStyleName}-restorebox {
+ background: transparent url(../../img/restore.png) no-repeat;
+}
+.#{$primaryStyleName}-maximizebox {
+ background: transparent url(../../img/maximize.png) no-repeat;
+}
-.#{$primaryStyleName}-closebox:active {
- background-position: 0 -50px;
- }
.#{$primaryStyleName} {
background-image: none;
diff --git a/WebContent/VAADIN/themes/chameleon/img/maximize.png b/WebContent/VAADIN/themes/chameleon/img/maximize.png
new file mode 100644
index 0000000000..5c6488d1a5
--- /dev/null
+++ b/WebContent/VAADIN/themes/chameleon/img/maximize.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/chameleon/img/restore.png b/WebContent/VAADIN/themes/chameleon/img/restore.png
new file mode 100644
index 0000000000..55d004fe53
--- /dev/null
+++ b/WebContent/VAADIN/themes/chameleon/img/restore.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/liferay/window/maximize_sprites.png b/WebContent/VAADIN/themes/liferay/window/maximize_sprites.png
new file mode 100644
index 0000000000..06510063cd
--- /dev/null
+++ b/WebContent/VAADIN/themes/liferay/window/maximize_sprites.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/liferay/window/restore_sprites.png b/WebContent/VAADIN/themes/liferay/window/restore_sprites.png
new file mode 100644
index 0000000000..41ccfaf79f
--- /dev/null
+++ b/WebContent/VAADIN/themes/liferay/window/restore_sprites.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/liferay/window/window.scss b/WebContent/VAADIN/themes/liferay/window/window.scss
index 54bfb37938..583a81d9e4 100644
--- a/WebContent/VAADIN/themes/liferay/window/window.scss
+++ b/WebContent/VAADIN/themes/liferay/window/window.scss
@@ -42,21 +42,35 @@
height: 5px;
}
+.v-window-restorebox,
+.v-window-maximizebox,
.v-window-closebox {
- background: url(closebutton_sprites.png) no-repeat scroll 0 0 transparent;
position: absolute;
width: 24px;
height: 24px;
- right: 9px;
top: 8px;
+ &:hover {
+ background-position: 0 -24px;
+ }
+ &:active {
+ background-position: 0 -48px;
+ }
+
}
-
-.v-window-closebox:hover {
- background-position: 0 -24px;
+.v-window-closebox {
+ right: 9px;
+ background: url(closebutton_sprites.png) no-repeat scroll 0 0 transparent;
}
-.v-window-closebox:active {
- background-position: 0 -48px;
+.v-window-restorebox,
+.v-window-maximizebox {
+ right: 36px;
+}
+.v-window-restorebox {
+ background: url(restore_sprites.png) no-repeat scroll 0 0 transparent;
+}
+.v-window-maximizebox {
+ background: url(maximize_sprites.png) no-repeat scroll 0 0 transparent;
}
.v-window-resizebox {
diff --git a/WebContent/VAADIN/themes/reindeer/notification/notification.scss b/WebContent/VAADIN/themes/reindeer/notification/notification.scss
index 4884f19f8b..ec0d15df2f 100644
--- a/WebContent/VAADIN/themes/reindeer/notification/notification.scss
+++ b/WebContent/VAADIN/themes/reindeer/notification/notification.scss
@@ -10,9 +10,11 @@
font-weight: bold;
}
-.v-ie9 & .#{$primaryStyleName} H1 {
+.v-ie9 &, .v-ie10 & {
+ .#{$primaryStyleName} H1 {
/* Fix for #6793 */
font-weight: bold;
+ }
}
.#{$primaryStyleName} p {
diff --git a/WebContent/VAADIN/themes/reindeer/panel/panel.scss b/WebContent/VAADIN/themes/reindeer/panel/panel.scss
index b095fb4ffb..74ee10837d 100644
--- a/WebContent/VAADIN/themes/reindeer/panel/panel.scss
+++ b/WebContent/VAADIN/themes/reindeer/panel/panel.scss
@@ -12,14 +12,24 @@
border-bottom: 1px solid #e5e5e5;
line-height: 16px; /* accommodate minimum icon size */
}
-.v-webkit & .#{$primaryStyleName}-caption,
-.v-webkit & .#{$primaryStyleName}-nocaption,
-.v-gecko & .#{$primaryStyleName}-caption,
-.v-gecko & .#{$primaryStyleName}-nocaption,
-.v-ie9 & .#{$primaryStyleName}-caption,
-.v-ie9 & .#{$primaryStyleName}-nocaption {
- border-bottom-color: rgba(0,0,0,.08);
+
+.v-webkit &,
+.v-gecko &,
+.v-ie9 &,
+.v-ie10 & {
+ .#{$primaryStyleName}-caption,
+ .#{$primaryStyleName}-nocaption {
+ border-bottom-color: rgba(0,0,0,.08);
+ }
+ .#{$primaryStyleName}-content {
+ border-top-color: rgba(0,0,0,.07);
+ }
+ .#{$primaryStyleName}-deco {
+ border-top-color: rgba(0,0,0,.1);
+ background: rgba(0,0,0,.08);
+ }
}
+
.#{$primaryStyleName}-caption {
padding-bottom: 2px;
}
@@ -30,11 +40,7 @@
border-bottom: none;
border-top: none;
}
-.v-webkit & .#{$primaryStyleName}-content,
-.v-gecko & .#{$primaryStyleName}-content,
-.v-ie9 & .#{$primaryStyleName}-content {
- border-top-color: rgba(0,0,0,.07);
-}
+
.blue .#{$primaryStyleName}-deco {
border-color: #92a3ac;
background: #adc2cd;
@@ -46,12 +52,6 @@
background: #e2e2e2;
overflow: hidden;
}
-.v-webkit & .#{$primaryStyleName}-deco,
-.v-gecko & .#{$primaryStyleName}-deco,
-.v-ie9 & .#{$primaryStyleName}-deco {
- border-top-color: rgba(0,0,0,.1);
- background: rgba(0,0,0,.08);
-}
.#{$primaryStyleName}-caption .v-errorindicator {
height: 16px;
width: 13px;
diff --git a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.scss b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.scss
index fe17d90e26..77d4922535 100644
--- a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.scss
+++ b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-minimal-style.scss
@@ -105,15 +105,17 @@
-moz-border-radius: 7px;
}
-.v-ie9 & .#{$primaryStyleName}-tabs-minimal .#{$primaryStyleName}-tabitem .#{$primaryStyleName}-caption-close {
- &, &:hover, &:active {
+.v-ie9 &, .v-ie10 & {
+ .#{$primaryStyleName}-tabs-minimal .#{$primaryStyleName}-tabitem .#{$primaryStyleName}-caption-close {
+ &, &:hover, &:active {
- /* IE9 suffers from rounding subpixel values errors when measuring the tabs which makes the close button wrap. */
+ /* IE9/IE10 suffers from rounding subpixel values errors when measuring the tabs which makes the close button wrap. */
margin-left: 2.5px;
- /* The close button is a pixel too high in IE9, adjust for that */
+ /* The close button is a pixel too high in IE9/IE10, adjust for that */
margin-top: 1px;
- }
+ }
+ }
}
.#{$primaryStyleName}-tabs-minimal .#{$primaryStyleName}-caption-close:hover,
diff --git a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.scss b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.scss
index 91bb3915be..b62791e4ce 100644
--- a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.scss
+++ b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-normal-style.scss
@@ -156,10 +156,6 @@
}
.v-ie & .#{$primaryStyleName}-tabs .v-errorindicator {
zoom: 1;
- display: inline;
-}
-.v-ie8 & .#{$primaryStyleName}-tabs .v-errorindicator,
-.v-ie9 & .#{$primaryStyleName}-tabs .v-errorindicator {
display: inline-block;
}
diff --git a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.scss b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.scss
index 56bad4ed72..4141586d5a 100644
--- a/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.scss
+++ b/WebContent/VAADIN/themes/reindeer/tabsheet/tabsheet-small-style.scss
@@ -55,11 +55,12 @@
.v-ff & .#{$primaryStyleName}-tabs-bar .#{$primaryStyleName}-caption-close {
margin-top: -14px;
}
-.v-ie9 & .#{$primaryStyleName}-tabs-bar .#{$primaryStyleName}-caption-close:only-child,
-.v-ie9 & .#{$primaryStyleName}-tabs-bar .v-captiontext:first-child + .#{$primaryStyleName}-caption-close {
+.v-ie9 &, .v-ie10 & {
+ .#{$primaryStyleName}-tabs-bar .#{$primaryStyleName}-caption-close:only-child,
+ .#{$primaryStyleName}-tabs-bar .v-captiontext:first-child + .#{$primaryStyleName}-caption-close {
margin-top: -14px;
+ }
}
-
.#{$primaryStyleName}-tabs-bar .#{$primaryStyleName}-caption-close:hover {
background: #bfbfbf;
-webkit-box-shadow: 0 1px 0 #fff;
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/close-active.png b/WebContent/VAADIN/themes/reindeer/window/img/black/close-active.png
new file mode 100644
index 0000000000..07a837b619
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/close-active.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/close-hover.png b/WebContent/VAADIN/themes/reindeer/window/img/black/close-hover.png
new file mode 100644
index 0000000000..bb0a080373
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/close-hover.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/close.png b/WebContent/VAADIN/themes/reindeer/window/img/black/close.png
new file mode 100644
index 0000000000..b26cfb5d57
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/close.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/maximize-active.png b/WebContent/VAADIN/themes/reindeer/window/img/black/maximize-active.png
new file mode 100644
index 0000000000..526563c94f
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/maximize-active.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/maximize-hover.png b/WebContent/VAADIN/themes/reindeer/window/img/black/maximize-hover.png
new file mode 100644
index 0000000000..76d0fdf040
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/maximize-hover.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/maximize.png b/WebContent/VAADIN/themes/reindeer/window/img/black/maximize.png
new file mode 100644
index 0000000000..ecf4cbed35
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/maximize.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/restore-active.png b/WebContent/VAADIN/themes/reindeer/window/img/black/restore-active.png
new file mode 100644
index 0000000000..96f9672605
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/restore-active.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/restore-hover.png b/WebContent/VAADIN/themes/reindeer/window/img/black/restore-hover.png
new file mode 100644
index 0000000000..b319f07684
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/restore-hover.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/black/restore.png b/WebContent/VAADIN/themes/reindeer/window/img/black/restore.png
new file mode 100644
index 0000000000..b440383b91
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/black/restore.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/close-light-hover.png b/WebContent/VAADIN/themes/reindeer/window/img/light/close-hover.png
index 17ac9b8457..17ac9b8457 100644
--- a/WebContent/VAADIN/themes/reindeer/window/img/close-light-hover.png
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/close-hover.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/close-light-pressed.png b/WebContent/VAADIN/themes/reindeer/window/img/light/close-pressed.png
index 2c84b5bcfb..2c84b5bcfb 100644
--- a/WebContent/VAADIN/themes/reindeer/window/img/close-light-pressed.png
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/close-pressed.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/close-light.png b/WebContent/VAADIN/themes/reindeer/window/img/light/close.png
index 4bbc89cee9..4bbc89cee9 100644
--- a/WebContent/VAADIN/themes/reindeer/window/img/close-light.png
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/close.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/content-bg-light.png b/WebContent/VAADIN/themes/reindeer/window/img/light/content-bg.png
index b38c902d83..b38c902d83 100644
--- a/WebContent/VAADIN/themes/reindeer/window/img/content-bg-light.png
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/content-bg.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/light/maximize-active.png b/WebContent/VAADIN/themes/reindeer/window/img/light/maximize-active.png
new file mode 100644
index 0000000000..5ca4e2e6eb
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/maximize-active.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/light/maximize-hover.png b/WebContent/VAADIN/themes/reindeer/window/img/light/maximize-hover.png
new file mode 100644
index 0000000000..c7930c2f4a
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/maximize-hover.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/light/maximize.png b/WebContent/VAADIN/themes/reindeer/window/img/light/maximize.png
new file mode 100644
index 0000000000..a4965ef19c
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/maximize.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/resize-light.png b/WebContent/VAADIN/themes/reindeer/window/img/light/resize.png
index 0c0c9123b9..0c0c9123b9 100644
--- a/WebContent/VAADIN/themes/reindeer/window/img/resize-light.png
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/resize.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/light/restore-active.png b/WebContent/VAADIN/themes/reindeer/window/img/light/restore-active.png
new file mode 100644
index 0000000000..d135c4d66c
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/restore-active.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/light/restore-hover.png b/WebContent/VAADIN/themes/reindeer/window/img/light/restore-hover.png
new file mode 100644
index 0000000000..b03639c001
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/restore-hover.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/light/restore.png b/WebContent/VAADIN/themes/reindeer/window/img/light/restore.png
new file mode 100644
index 0000000000..1c3fba4020
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/light/restore.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/maximize.png b/WebContent/VAADIN/themes/reindeer/window/img/maximize.png
new file mode 100644
index 0000000000..86ffff9760
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/maximize.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/img/restore.png b/WebContent/VAADIN/themes/reindeer/window/img/restore.png
new file mode 100644
index 0000000000..119ea04259
--- /dev/null
+++ b/WebContent/VAADIN/themes/reindeer/window/img/restore.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/reindeer/window/window.scss b/WebContent/VAADIN/themes/reindeer/window/window.scss
index e6a73ee2c0..e8f0011397 100644
--- a/WebContent/VAADIN/themes/reindeer/window/window.scss
+++ b/WebContent/VAADIN/themes/reindeer/window/window.scss
@@ -14,7 +14,7 @@
border-color: rgba(0,0,0,.2);
}
.#{$primaryStyleName}-outerheader {
- padding: 12px 32px 0 14px;
+ padding: 12px 52px 0 14px;
height: 37px;
background: black repeat-x;
background-image: url(img/header-bg.png); /** sprite-ref: verticals; sprite-alignment: repeat */
@@ -61,6 +61,24 @@
.#{$primaryStyleName}-closebox:active {
background-image: url(img/close-pressed.png); /** sprite-ref: verticals */
}
+.#{$primaryStyleName}-maximizebox,
+.#{$primaryStyleName}-restorebox {
+ top: 12px;
+ right: 28px;
+ width: 15px;
+ height: 16px;
+ background: transparent;
+}
+.#{$primaryStyleName}-maximizebox {
+ &, &:hover,&:active {
+ background-image: url(img/maximize.png); /** sprite-ref: verticals */
+ }
+}
+.#{$primaryStyleName}-restorebox {
+ &, &:hover,&:active {
+ background-image: url(img/restore.png); /** sprite-ref: verticals */
+ }
+}
.#{$primaryStyleName}-contents {
background: #fff;
}
@@ -77,45 +95,71 @@
Light style window -----------------------------
**/
-.#{$primaryStyleName}-light .#{$primaryStyleName}-outerheader {
- background: transparent;
- padding: 15px 32px 0 18px;
- height: 23px;
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-header {
- font-size: 16px;
- color: #292e34;
- text-shadow: none;
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-resizebox {
- width: 12px;
- height: 12px;
- background-image: url(img/resize-light.png); /** sprite-ref: verticals */
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-footer {
- background: transparent;
- height: 12px;
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-closebox {
- right: 1px;
- top: 17px;
- width: 19px;
- height: 15px;
- background-image: url(img/close-light.png); /** sprite-ref: verticals */
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-closebox:hover {
- background-image: url(img/close-light-hover.png); /** sprite-ref: verticals */
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-closebox:active {
- background-image: url(img/close-light-pressed.png); /** sprite-ref: verticals */
-}
-.#{$primaryStyleName}-light .#{$primaryStyleName}-contents {
- background: transparent;
-}
-/* This must be the last sprite added to the verticals-sprite image */
-.#{$primaryStyleName}-light .#{$primaryStyleName}-wrap {
- background: #f7f7f8 repeat-x;
- background-image: url(img/content-bg-light.png); /** sprite-ref: verticals; sprite-alignment: repeat */
+.#{$primaryStyleName}-light {
+ .#{$primaryStyleName}-outerheader {
+ background: transparent;
+ padding: 15px 52px 0 18px;
+ }
+ .#{$primaryStyleName}-header {
+ font-size: 16px;
+ color: #292e34;
+ text-shadow: none;
+ }
+ .#{$primaryStyleName}-resizebox {
+ width: 12px;
+ height: 12px;
+ background-image: url(img/light/resize.png); /** sprite-ref: verticals */
+ }
+ .#{$primaryStyleName}-footer {
+ background: transparent;
+ height: 12px;
+ }
+ .#{$primaryStyleName}-closebox {
+ right: 1px;
+ top: 17px;
+ width: 19px;
+ height: 15px;
+
+ background-image: url(img/light/close.png); /** sprite-ref: verticals */
+ &:hover {
+ background-image: url(img/light/close-hover.png); /** sprite-ref: verticals */
+ }
+ &:active {
+ background-image: url(img/light/close-pressed.png); /** sprite-ref: verticals */
+ }
+ }
+
+ .#{$primaryStyleName}-maximizebox {
+ top: 17px;
+
+ background-image: url(img/light/maximize.png); /** sprite-ref: verticals */
+ &:hover {
+ background-image: url(img/light/maximize-hover.png); /** sprite-ref: verticals */
+ }
+ &:active {
+ background-image: url(img/light/maximize-active.png); /** sprite-ref: verticals */
+ }
+ }
+ .#{$primaryStyleName}-restorebox {
+ top: 17px;
+
+ background-image: url(img/light/restore.png); /** sprite-ref: verticals */
+ &:hover {
+ background-image: url(img/light/restore-hover.png); /** sprite-ref: verticals */
+ }
+ &:active {
+ background-image: url(img/light/restore-active.png); /** sprite-ref: verticals */
+ }
+ }
+
+ .#{$primaryStyleName}-contents {
+ background: transparent;
+ }
+ /* This must be the last sprite added to the verticals-sprite image */
+ .#{$primaryStyleName}-wrap {
+ background: #f7f7f8 repeat-x;
+ background-image: url(img/light/content-bg.png); /** sprite-ref: verticals; sprite-alignment: repeat */
+ }
}
@@ -123,63 +167,97 @@
Black style window -----------------------------
**/
-.#{$primaryStyleName}-black .#{$primaryStyleName}-wrap {
- border-color: #2e3030;
- border-radius: 8px;
- -webkit-border-radius: 8px;
- -moz-border-radius: 8px;
- overflow: hidden;
-}
-.v-sa & .#{$primaryStyleName}-black .#{$primaryStyleName}-wrap,
-.v-op & .#{$primaryStyleName}-black .#{$primaryStyleName}-wrap {
- border-color: rgba(0,0,0,.8);
-}
-.#{$primaryStyleName}-black .#{$primaryStyleName}-wrap {
- background-color: #1d2021;
- -moz-border-radius: 7px;
- -webkit-border-radius: 7px;
-}
-.v-sa & .#{$primaryStyleName}-black .#{$primaryStyleName}-wrap,
-.v-op & .#{$primaryStyleName}-black .#{$primaryStyleName}-wrap {
- background-color: rgba(29,32,33,.9);
-}
-.#{$primaryStyleName}-black .#{$primaryStyleName}-outerheader {
- height: 29px;
- padding: 7px 14px;
- background: transparent repeat-x;
- background-image: url(img/black/header-bg.png); /** sprite-ref: black-verticals; sprite-alignment: repeat */
- text-align: center;
- -moz-border-radius-topright: 7px;
- -moz-border-radius-topleft: 7px;
- -webkit-border-top-right-radius: 7px;
- -webkit-border-top-left-radius: 7px;
- overflow: hidden;
- border: none;
-}
-.#{$primaryStyleName}-black .#{$primaryStyleName}-header {
- font-size: 12px;
- font-weight: normal;
- color: #dddfe1;
-}
-.#{$primaryStyleName}-black .#{$primaryStyleName}-closebox {
- top: 8px;
-}
-.#{$primaryStyleName}-black .#{$primaryStyleName}-footer {
- background: transparent;
- border: none;
- height: 14px;
-}
-.#{$primaryStyleName}-black .#{$primaryStyleName}-resizebox {
- background: transparent no-repeat;
- background-image: url(img/black/resize.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 4px */
- width: 14px;
- height: 14px;
-}
-/* Must be last to make this image last in the sprites */
-.#{$primaryStyleName}-black .#{$primaryStyleName}-contents {
- border: none;
- background: transparent repeat-x;
- background-image: url(img/black/content-bg.png); /** sprite-ref: black-verticals; sprite-alignment: repeat */
+.#{$primaryStyleName}-black {
+ .#{$primaryStyleName}-wrap {
+ border-color: #2e3030;
+ border-radius: 8px;
+ -webkit-border-radius: 8px;
+ -moz-border-radius: 8px;
+ overflow: hidden;
+ }
+ .v-sa & .#{$primaryStyleName}-wrap,
+ .v-op & .#{$primaryStyleName}-wrap {
+ border-color: rgba(0,0,0,.8);
+ }
+
+ .#{$primaryStyleName}-wrap {
+ background-color: #1d2021;
+ -moz-border-radius: 7px;
+ -webkit-border-radius: 7px;
+ }
+ .v-sa & .#{$primaryStyleName}-wrap,
+ .v-op & .#{$primaryStyleName}-wrap {
+ background-color: rgba(29,32,33,.9);
+ }
+ .#{$primaryStyleName}-outerheader {
+ height: 29px;
+ padding: 7px 14px;
+ background: transparent repeat-x;
+ background-image: url(img/black/header-bg.png); /** sprite-ref: black-verticals; sprite-alignment: repeat */
+ text-align: center;
+ -moz-border-radius-topright: 7px;
+ -moz-border-radius-topleft: 7px;
+ -webkit-border-top-right-radius: 7px;
+ -webkit-border-top-left-radius: 7px;
+ overflow: hidden;
+ border: none;
+ }
+ .#{$primaryStyleName}-header {
+ font-size: 12px;
+ font-weight: normal;
+ color: #dddfe1;
+ }
+ .#{$primaryStyleName}-closebox {
+ top: 8px;
+
+ background-image: url(img/black/close.png); /** sprite-ref: verticals */
+ &:hover {
+ background-image: url(img/black/close-hover.png); /** sprite-ref: verticals */
+ }
+ &:active {
+ background-image: url(img/black/close-pressed.png); /** sprite-ref: verticals */
+ }
+ }
+ .#{$primaryStyleName}-footer {
+ background: transparent;
+ border: none;
+ height: 14px;
+ }
+ .#{$primaryStyleName}-resizebox {
+ background: transparent no-repeat;
+ background-image: url(img/black/resize.png); /** sprite-ref: black-verticals; sprite-margin-bottom: 4px */
+ width: 14px;
+ height: 14px;
+ }
+ .#{$primaryStyleName}-maximizebox {
+ top: 8px;
+
+ background-image: url(img/black/maximize.png); /** sprite-ref: verticals */
+ &:hover {
+ background-image: url(img/black/maximize-hover.png); /** sprite-ref: verticals */
+ }
+ &:active {
+ background-image: url(img/black/maximize-active.png); /** sprite-ref: verticals */
+ }
+ }
+ .#{$primaryStyleName}-restorebox {
+ top: 8px;
+
+ background-image: url(img/black/restore.png); /** sprite-ref: verticals */
+ &:hover {
+ background-image: url(img/black/restore-hover.png); /** sprite-ref: verticals */
+ }
+ &:active {
+ background-image: url(img/black/restore-active.png); /** sprite-ref: verticals */
+ }
+ }
+
+ /* Must be last to make this image last in the sprites */
+ .#{$primaryStyleName}-contents {
+ border: none;
+ background: transparent repeat-x;
+ background-image: url(img/black/content-bg.png); /** sprite-ref: black-verticals; sprite-alignment: repeat */
+ }
}
} \ No newline at end of file
diff --git a/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.scss b/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.scss
index 3b8773e9e6..ab4afb1c69 100644
--- a/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.scss
+++ b/WebContent/VAADIN/themes/runo/tabsheet/tabsheet.scss
@@ -142,9 +142,6 @@
background: #babfc0;
overflow: hidden;
margin: 0;
-}
-.v-ie8 & .#{$primaryStyleName}-deco,
-.v-ie9 & .#{$primaryStyleName}-deco {
width: 100%;
}
/* Light-style */
diff --git a/WebContent/VAADIN/themes/runo/window/img/maximize.png b/WebContent/VAADIN/themes/runo/window/img/maximize.png
new file mode 100644
index 0000000000..c7a1a8d418
--- /dev/null
+++ b/WebContent/VAADIN/themes/runo/window/img/maximize.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/runo/window/img/restore.png b/WebContent/VAADIN/themes/runo/window/img/restore.png
new file mode 100644
index 0000000000..15ac00ddb2
--- /dev/null
+++ b/WebContent/VAADIN/themes/runo/window/img/restore.png
Binary files differ
diff --git a/WebContent/VAADIN/themes/runo/window/window.scss b/WebContent/VAADIN/themes/runo/window/window.scss
index 994238f2ad..d2048e027e 100644
--- a/WebContent/VAADIN/themes/runo/window/window.scss
+++ b/WebContent/VAADIN/themes/runo/window/window.scss
@@ -13,7 +13,7 @@
.#{$primaryStyleName}-outerheader {
height: 49px;
margin-left: 9px;
- padding: 15px 40px 11px 12px;
+ padding: 15px 61px 11px 12px;
background: transparent url(img/top-right.png) no-repeat right top;
}
.#{$primaryStyleName}-header {
@@ -51,17 +51,48 @@
background: transparent;
display: block;
}
-.#{$primaryStyleName}-closebox {
+.#{$primaryStyleName}-closebox,
+.#{$primaryStyleName}-maximizebox,
+.#{$primaryStyleName}-restorebox {
position: absolute;
top: 21px;
- right: 24px;
+ height: 12px;
+ background: transparent url(img/close.png);
+}
+.#{$primaryStyleName}-closebox {
width: 12px;
height: 12px;
+ right: 24px;
background: transparent url(img/close.png);
+ &:hover {
+ background-position: 0 -12px;
+ }
}
-.#{$primaryStyleName}-closebox:hover {
- background-position: 0 -12px;
+
+.#{$primaryStyleName}-maximizebox,
+.#{$primaryStyleName}-restorebox {
+ right: 42px;
}
+
+.#{$primaryStyleName}-restorebox {
+ width: 15px;
+ height: 14px;
+
+ background: transparent url(img/restore.png);
+ &:hover {
+ background-position: 0 -14px;
+ }
+}
+.#{$primaryStyleName}-maximizebox {
+ width: 13px;
+ height: 12px;
+
+ background: transparent url(img/maximize.png);
+ &:hover {
+ background-position: 0 -12px;
+ }
+}
+
.#{$primaryStyleName}-modalitycurtain {
background: #fff;
}
diff --git a/WebContent/VAADIN/themes/tests-calendar/styles.css b/WebContent/VAADIN/themes/tests-calendar/styles.css
new file mode 100644
index 0000000000..7a37fcfdaf
--- /dev/null
+++ b/WebContent/VAADIN/themes/tests-calendar/styles.css
@@ -0,0 +1,96 @@
+@import url(../reindeer/legacy-styles.css);
+
+.v-app {
+ background: #fff;
+ }
+
+
+/** Customized phase colors*/
+
+
+/**
+ * Green
+ */
+
+/* For month view */
+.v-calendar .v-calendar-event-color1 {
+ color: #4f8324;
+ }
+.v-calendar .v-calendar-event-color1-all-day {
+ background-color: #61c114;
+ }
+
+/* For week/day view */
+.v-calendar .v-calendar-event-color1 .v-calendar-event-caption {
+ color: #4f8324;
+ }
+.v-calendar .v-calendar-event-color1 .v-calendar-event-content {
+ border-color: #61c114;
+ background-color: #daff70;
+ }
+
+
+/**
+ * Blue
+ */
+
+/* For month view */
+.v-calendar .v-calendar-event-color2 {
+ color: #1c4b8b;
+ }
+.v-calendar .v-calendar-event-color2-all-day {
+ background-color: #0a56bc;
+ }
+
+/* For week/day view */
+.v-calendar .v-calendar-event-color2 .v-calendar-event-caption {
+ color: #1c4b8b;
+ }
+.v-calendar .v-calendar-event-color2 .v-calendar-event-content {
+ border-color: #0a56bc;
+ background-color: #529bff;
+ }
+
+
+/**
+ * Red
+ */
+
+/* For month view */
+.v-calendar .v-calendar-event-color3 {
+ color: #831d1d;
+ }
+.v-calendar .v-calendar-event-color3-all-day {
+ background-color: #bd1a1a;
+ }
+
+/* For week/day view */
+.v-calendar .v-calendar-event-color3 .v-calendar-event-caption {
+ color: #831d1d;
+ }
+.v-calendar .v-calendar-event-color3 .v-calendar-event-content {
+ border-color: #bd1a1a;
+ background-color: #ff9d9d;
+ }
+
+
+/**
+ * Orange
+ */
+
+/* For month view */
+.v-calendar .v-calendar-event-color4 {
+ color: #8b5923;
+ }
+.v-calendar .v-calendar-event-color4-all-day {
+ background-color: #cd6a00;
+ }
+
+/* For week/day view */
+.v-calendar .v-calendar-event-color4 .v-calendar-event-caption {
+ color: #8b5923;
+ }
+.v-calendar .v-calendar-event-color4 .v-calendar-event-content {
+ border-color: #cd6a00;
+ background-color: #faa345;
+ } \ No newline at end of file
diff --git a/WebContent/VAADIN/vaadinBootstrap.js b/WebContent/VAADIN/vaadinBootstrap.js
index 81adfcccc6..b2995dd0bd 100644
--- a/WebContent/VAADIN/vaadinBootstrap.js
+++ b/WebContent/VAADIN/vaadinBootstrap.js
@@ -120,6 +120,11 @@
url += '&theme=' + encodeURIComponent(theme);
}
+ var extraParams = getConfig('extraParams')
+ if (extraParams !== undefined) {
+ url += extraParams;
+ }
+
url += '&' + vaadin.getBrowserDetailsParameters(appId);
// Timestamp to avoid caching
@@ -295,8 +300,20 @@
}
// Detect touch device support
- try { document.createEvent("TouchEvent"); url += "&v-td=1";} catch(e){};
-
+ var supportsTouch = false;
+ try {
+ document.createEvent("TouchEvent");
+ supportsTouch = true;
+ } catch (e) {
+ // Chrome and IE10 touch detection
+ supportsTouch = 'ontouchstart' in window
+ || navigator.msMaxTouchPoints;
+ }
+
+ if (supportsTouch) {
+ url += "&v-td=1";
+ }
+
return url;
}
};
diff --git a/WebContent/VAADIN/vaadinPush.js.tpl b/WebContent/VAADIN/vaadinPush.js.tpl
new file mode 100644
index 0000000000..3928fba1b6
--- /dev/null
+++ b/WebContent/VAADIN/vaadinPush.js.tpl
@@ -0,0 +1,8 @@
+@jquery.js@
+window.jQueryVaadin = window.jQuery.noConflict(true);
+(function(jQuery, undefined) {
+ @jquery.atmosphere.js@
+})(jQueryVaadin);
+if (console) {
+ console.log("Vaadin push loaded");
+} \ No newline at end of file
diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml
index 57207d7f18..848baea318 100644
--- a/WebContent/WEB-INF/web.xml
+++ b/WebContent/WEB-INF/web.xml
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
-<web-app id="vaadin-uitest" version="2.4"
- xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+<web-app id="vaadin-uitest" version="3.0"
+ xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
+
<!-- THIS IS A DEVELOPMENT AND TESTING web.xml . -->
<display-name>Vaadin</display-name>
@@ -50,6 +51,10 @@
<servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class>
<!-- Non-default values for testing purposes -->
<init-param>
+ <param-name>legacyPropertyToString</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
<param-name>heartbeatInterval</param-name>
<param-value>301</param-value>
</init-param>
@@ -67,6 +72,16 @@
</init-param>
</servlet>
+ <servlet>
+ <servlet-name>VaadinApplicationRunnerWithPush</servlet-name>
+ <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class>
+ <init-param>
+ <param-name>pushmode</param-name>
+ <param-value>automatic</param-value>
+ </init-param>
+ <async-supported>true</async-supported>
+ </servlet>
+
<!-- For testing GAE - the deployment script changes this to use GAEVaadinServlet -->
<servlet>
<servlet-name>IntegrationTest</servlet-name>
@@ -75,6 +90,7 @@
<param-name>UI</param-name>
<param-value>com.vaadin.tests.integration.IntegrationTestUI</param-value>
</init-param>
+ <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>Embed App 1</servlet-name>
@@ -97,6 +113,11 @@
</servlet-mapping>
<servlet-mapping>
+ <servlet-name>VaadinApplicationRunnerWithPush</servlet-name>
+ <url-pattern>/run-push/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
<servlet-name>IntegrationTest</servlet-name>
<url-pattern>/integration/*</url-pattern>
</servlet-mapping>
diff --git a/WebContent/WEB-INF/web.xml.2.4 b/WebContent/WEB-INF/web.xml.2.4
new file mode 100644
index 0000000000..bcc5f3a651
--- /dev/null
+++ b/WebContent/WEB-INF/web.xml.2.4
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app id="vaadin-uitest" version="2.4"
+ xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+ <!-- THIS IS A DEVELOPMENT AND TESTING web.xml for servlet 2.4 -->
+
+ <display-name>Vaadin</display-name>
+ <description>Vaadin examples</description>
+
+ <context-param>
+ <param-name>productionMode</param-name>
+ <param-value>false</param-value>
+ </context-param>
+
+ <context-param>
+ <param-name>resourceCacheTime</param-name>
+ <param-value>3600</param-value>
+ </context-param>
+ <servlet>
+ <servlet-name>Embed App 1</servlet-name>
+ <servlet-class>com.vaadin.server.LegacyVaadinServlet</servlet-class>
+ <init-param>
+ <param-name>application</param-name>
+ <param-value>com.vaadin.tests.components.button.Buttons</param-value>
+ </init-param>
+ </servlet>
+ <servlet>
+ <servlet-name>Embed App 2</servlet-name>
+ <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
+ <init-param>
+ <param-name>UI</param-name>
+ <param-value>com.vaadin.tests.components.label.MarginsInLabels</param-value>
+ </init-param>
+ </servlet>
+ <servlet>
+ <servlet-name>UI provider app</servlet-name>
+ <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
+ <init-param>
+ <param-name>UIProvider</param-name>
+ <param-value>com.vaadin.tests.applicationservlet.InitParamUIProvider</param-value>
+ </init-param>
+ <init-param>
+ <param-name>UI</param-name>
+ <param-value>com.vaadin.tests.VerifyAssertionsEnabled</param-value>
+ </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>VaadinApplicationRunner</servlet-name>
+ <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class>
+ <!-- Non-default values for testing purposes -->
+ <init-param>
+ <param-name>legacyPropertyToString</param-name>
+ <param-value>false</param-value>
+ </init-param>
+ <init-param>
+ <param-name>heartbeatInterval</param-name>
+ <param-value>301</param-value>
+ </init-param>
+ <init-param>
+ <param-name>resourceCacheTime</param-name>
+ <param-value>3601</param-value>
+ </init-param>
+ <init-param>
+ <param-name>closeIdleSessions</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ <init-param>
+ <param-name>testParam</param-name>
+ <param-value>42</param-value>
+ </init-param>
+ </servlet>
+
+ <servlet>
+ <servlet-name>VaadinApplicationRunnerWithPush</servlet-name>
+ <servlet-class>com.vaadin.launcher.ApplicationRunnerServlet</servlet-class>
+ <init-param>
+ <param-name>pushmode</param-name>
+ <param-value>automatic</param-value>
+ </init-param>
+ </servlet>
+
+ <!-- For testing GAE - the deployment script changes this to use GAEVaadinServlet -->
+ <servlet>
+ <servlet-name>IntegrationTest</servlet-name>
+ <servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
+ <init-param>
+ <param-name>UI</param-name>
+ <param-value>com.vaadin.tests.integration.IntegrationTestUI</param-value>
+ </init-param>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>Embed App 1</servlet-name>
+ <url-pattern>/embed1/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>Embed App 2</servlet-name>
+ <url-pattern>/embed2/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>UI provider app</servlet-name>
+ <url-pattern>/uiprovider/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>VaadinApplicationRunner</servlet-name>
+ <url-pattern>/run/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>VaadinApplicationRunnerWithPush</servlet-name>
+ <url-pattern>/run-push/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>IntegrationTest</servlet-name>
+ <url-pattern>/integration/*</url-pattern>
+ </servlet-mapping>
+
+ <servlet-mapping>
+ <servlet-name>IntegrationTest</servlet-name>
+ <url-pattern>/VAADIN/*</url-pattern>
+ </servlet-mapping>
+
+ <welcome-file-list>
+ <welcome-file>index.html</welcome-file>
+ </welcome-file-list>
+
+</web-app>
diff --git a/WebContent/license.html b/WebContent/license.html
index 1a855316eb..22678ca981 100644
--- a/WebContent/license.html
+++ b/WebContent/license.html
@@ -113,10 +113,29 @@
<td><a href="licenses/new-bsd-license.txt">New BSD License</a></td>
</tr>
+ <!-- If vaadin-push used. Atmosphere has some internal dependencies, but they are all Apache 2. -->
+ <tr>
+ <td>Atmosphere Framework^</td>
+ <td><a href="licenses/apache-license-version-2-0.txt">Apache License, Version 2.0</a>,<br/>
+ <a href="licenses/common-development-and-distribution-license-v1-0.txt">Common Development and Distribution License, Version 1.0</a></td>
+ </tr>
+
+ <!-- Used by vaadin-push -->
+ <tr>
+ <td>SLF4J^</td>
+ <td><a href="licenses/the-mit-license.txt">The MIT License</a></td>
+ </tr>
+ <!-- Used by vaadin-push -->
+ <tr>
+ <td>jQuery^</td>
+ <td><a href="licenses/the-mit-license.txt">The MIT License</a></td>
+ </tr>
+
</tbody>
</table>
- <p>* Not required by Vaadin, only used if provided by the user.</p>
+ <p>* Not required by Vaadin, only used if provided by the user.<br/>
+^ Only if <tt>vaadin-push</tt> is used.</p>
<h4>Vaadin Development Dependencies</h4>
diff --git a/WebContent/licenses/common-development-and-distribution-license-v1-0.txt b/WebContent/licenses/common-development-and-distribution-license-v1-0.txt
new file mode 100644
index 0000000000..5cf7a215ec
--- /dev/null
+++ b/WebContent/licenses/common-development-and-distribution-license-v1-0.txt
@@ -0,0 +1,384 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+
+
+ 1. Definitions.
+
+ 1.1. ?Contributor? means each individual or entity that
+ creates or contributes to the creation of Modifications.
+
+ 1.2. ?Contributor Version? means the combination of the
+ Original Software, prior Modifications used by a
+ Contributor (if any), and the Modifications made by that
+ particular Contributor.
+
+ 1.3. ?Covered Software? means (a) the Original Software, or
+ (b) Modifications, or (c) the combination of files
+ containing Original Software with files containing
+ Modifications, in each case including portions thereof.
+
+ 1.4. ?Executable? means the Covered Software in any form
+ other than Source Code.
+
+ 1.5. ?Initial Developer? means the individual or entity
+ that first makes Original Software available under this
+ License.
+
+ 1.6. ?Larger Work? means a work which combines Covered
+ Software or portions thereof with code not governed by the
+ terms of this License.
+
+ 1.7. ?License? means this document.
+
+ 1.8. ?Licensable? means having the right to grant, to the
+ maximum extent possible, whether at the time of the initial
+ grant or subsequently acquired, any and all of the rights
+ conveyed herein.
+
+ 1.9. ?Modifications? means the Source Code and Executable
+ form of any of the following:
+
+ A. Any file that results from an addition to,
+ deletion from or modification of the contents of a
+ file containing Original Software or previous
+ Modifications;
+
+ B. Any new file that contains any part of the
+ Original Software or previous Modification; or
+
+ C. Any new file that is contributed or otherwise made
+ available under the terms of this License.
+
+ 1.10. ?Original Software? means the Source Code and
+ Executable form of computer software code that is
+ originally released under this License.
+
+ 1.11. ?Patent Claims? means any patent claim(s), now owned
+ or hereafter acquired, including without limitation,
+ method, process, and apparatus claims, in any patent
+ Licensable by grantor.
+
+ 1.12. ?Source Code? means (a) the common form of computer
+ software code in which modifications are made and (b)
+ associated documentation included in or with such code.
+
+ 1.13. ?You? (or ?Your?) means an individual or a legal
+ entity exercising rights under, and complying with all of
+ the terms of, this License. For legal entities, ?You?
+ includes any entity which controls, is controlled by, or is
+ under common control with You. For purposes of this
+ definition, ?control? means (a) the power, direct or
+ indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership
+ of more than fifty percent (50%) of the outstanding shares
+ or beneficial ownership of such entity.
+
+ 2. License Grants.
+
+ 2.1. The Initial Developer Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and
+ subject to third party intellectual property claims, the
+ Initial Developer hereby grants You a world-wide,
+ royalty-free, non-exclusive license:
+
+ (a) under intellectual property rights (other than
+ patent or trademark) Licensable by Initial Developer,
+ to use, reproduce, modify, display, perform,
+ sublicense and distribute the Original Software (or
+ portions thereof), with or without Modifications,
+ and/or as part of a Larger Work; and
+
+ (b) under Patent Claims infringed by the making,
+ using or selling of Original Software, to make, have
+ made, use, practice, sell, and offer for sale, and/or
+ otherwise dispose of the Original Software (or
+ portions thereof).
+
+ (c) The licenses granted in Sections 2.1(a) and (b)
+ are effective on the date Initial Developer first
+ distributes or otherwise makes the Original Software
+ available to a third party under the terms of this
+ License.
+
+ (d) Notwithstanding Section 2.1(b) above, no patent
+ license is granted: (1) for code that You delete from
+ the Original Software, or (2) for infringements
+ caused by: (i) the modification of the Original
+ Software, or (ii) the combination of the Original
+ Software with other software or devices.
+
+ 2.2. Contributor Grant.
+
+ Conditioned upon Your compliance with Section 3.1 below and
+ subject to third party intellectual property claims, each
+ Contributor hereby grants You a world-wide, royalty-free,
+ non-exclusive license:
+
+ (a) under intellectual property rights (other than
+ patent or trademark) Licensable by Contributor to
+ use, reproduce, modify, display, perform, sublicense
+ and distribute the Modifications created by such
+ Contributor (or portions thereof), either on an
+ unmodified basis, with other Modifications, as
+ Covered Software and/or as part of a Larger Work; and
+
+
+ (b) under Patent Claims infringed by the making,
+ using, or selling of Modifications made by that
+ Contributor either alone and/or in combination with
+ its Contributor Version (or portions of such
+ combination), to make, use, sell, offer for sale,
+ have made, and/or otherwise dispose of: (1)
+ Modifications made by that Contributor (or portions
+ thereof); and (2) the combination of Modifications
+ made by that Contributor with its Contributor Version
+ (or portions of such combination).
+
+ (c) The licenses granted in Sections 2.2(a) and
+ 2.2(b) are effective on the date Contributor first
+ distributes or otherwise makes the Modifications
+ available to a third party.
+
+ (d) Notwithstanding Section 2.2(b) above, no patent
+ license is granted: (1) for any code that Contributor
+ has deleted from the Contributor Version; (2) for
+ infringements caused by: (i) third party
+ modifications of Contributor Version, or (ii) the
+ combination of Modifications made by that Contributor
+ with other software (except as part of the
+ Contributor Version) or other devices; or (3) under
+ Patent Claims infringed by Covered Software in the
+ absence of Modifications made by that Contributor.
+
+ 3. Distribution Obligations.
+
+ 3.1. Availability of Source Code.
+
+ Any Covered Software that You distribute or otherwise make
+ available in Executable form must also be made available in
+ Source Code form and that Source Code form must be
+ distributed only under the terms of this License. You must
+ include a copy of this License with every copy of the
+ Source Code form of the Covered Software You distribute or
+ otherwise make available. You must inform recipients of any
+ such Covered Software in Executable form as to how they can
+ obtain such Covered Software in Source Code form in a
+ reasonable manner on or through a medium customarily used
+ for software exchange.
+
+ 3.2. Modifications.
+
+ The Modifications that You create or to which You
+ contribute are governed by the terms of this License. You
+ represent that You believe Your Modifications are Your
+ original creation(s) and/or You have sufficient rights to
+ grant the rights conveyed by this License.
+
+ 3.3. Required Notices.
+
+ You must include a notice in each of Your Modifications
+ that identifies You as the Contributor of the Modification.
+ You may not remove or alter any copyright, patent or
+ trademark notices contained within the Covered Software, or
+ any notices of licensing or any descriptive text giving
+ attribution to any Contributor or the Initial Developer.
+
+ 3.4. Application of Additional Terms.
+
+ You may not offer or impose any terms on any Covered
+ Software in Source Code form that alters or restricts the
+ applicable version of this License or the recipients?
+ rights hereunder. You may choose to offer, and to charge a
+ fee for, warranty, support, indemnity or liability
+ obligations to one or more recipients of Covered Software.
+ However, you may do so only on Your own behalf, and not on
+ behalf of the Initial Developer or any Contributor. You
+ must make it absolutely clear that any such warranty,
+ support, indemnity or liability obligation is offered by
+ You alone, and You hereby agree to indemnify the Initial
+ Developer and every Contributor for any liability incurred
+ by the Initial Developer or such Contributor as a result of
+ warranty, support, indemnity or liability terms You offer.
+
+
+ 3.5. Distribution of Executable Versions.
+
+ You may distribute the Executable form of the Covered
+ Software under the terms of this License or under the terms
+ of a license of Your choice, which may contain terms
+ different from this License, provided that You are in
+ compliance with the terms of this License and that the
+ license for the Executable form does not attempt to limit
+ or alter the recipient?s rights in the Source Code form
+ from the rights set forth in this License. If You
+ distribute the Covered Software in Executable form under a
+ different license, You must make it absolutely clear that
+ any terms which differ from this License are offered by You
+ alone, not by the Initial Developer or Contributor. You
+ hereby agree to indemnify the Initial Developer and every
+ Contributor for any liability incurred by the Initial
+ Developer or such Contributor as a result of any such terms
+ You offer.
+
+ 3.6. Larger Works.
+
+ You may create a Larger Work by combining Covered Software
+ with other code not governed by the terms of this License
+ and distribute the Larger Work as a single product. In such
+ a case, You must make sure the requirements of this License
+ are fulfilled for the Covered Software.
+
+ 4. Versions of the License.
+
+ 4.1. New Versions.
+
+ Sun Microsystems, Inc. is the initial license steward and
+ may publish revised and/or new versions of this License
+ from time to time. Each version will be given a
+ distinguishing version number. Except as provided in
+ Section 4.3, no one other than the license steward has the
+ right to modify this License.
+
+ 4.2. Effect of New Versions.
+
+ You may always continue to use, distribute or otherwise
+ make the Covered Software available under the terms of the
+ version of the License under which You originally received
+ the Covered Software. If the Initial Developer includes a
+ notice in the Original Software prohibiting it from being
+ distributed or otherwise made available under any
+ subsequent version of the License, You must distribute and
+ make the Covered Software available under the terms of the
+ version of the License under which You originally received
+ the Covered Software. Otherwise, You may also choose to
+ use, distribute or otherwise make the Covered Software
+ available under the terms of any subsequent version of the
+ License published by the license steward.
+
+ 4.3. Modified Versions.
+
+ When You are an Initial Developer and You want to create a
+ new license for Your Original Software, You may create and
+ use a modified version of this License if You: (a) rename
+ the license and remove any references to the name of the
+ license steward (except to note that the license differs
+ from this License); and (b) otherwise make it clear that
+ the license contains terms which differ from this License.
+
+
+ 5. DISCLAIMER OF WARRANTY.
+
+ COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN ?AS IS?
+ BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+ INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED
+ SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+ PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND
+ PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY
+ COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+ INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF
+ ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF
+ WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+ ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS
+ DISCLAIMER.
+
+ 6. TERMINATION.
+
+ 6.1. This License and the rights granted hereunder will
+ terminate automatically if You fail to comply with terms
+ herein and fail to cure such breach within 30 days of
+ becoming aware of the breach. Provisions which, by their
+ nature, must remain in effect beyond the termination of
+ this License shall survive.
+
+ 6.2. If You assert a patent infringement claim (excluding
+ declaratory judgment actions) against Initial Developer or
+ a Contributor (the Initial Developer or Contributor against
+ whom You assert such claim is referred to as ?Participant?)
+ alleging that the Participant Software (meaning the
+ Contributor Version where the Participant is a Contributor
+ or the Original Software where the Participant is the
+ Initial Developer) directly or indirectly infringes any
+ patent, then any and all rights granted directly or
+ indirectly to You by such Participant, the Initial
+ Developer (if the Initial Developer is not the Participant)
+ and all Contributors under Sections 2.1 and/or 2.2 of this
+ License shall, upon 60 days notice from Participant
+ terminate prospectively and automatically at the expiration
+ of such 60 day notice period, unless if within such 60 day
+ period You withdraw Your claim with respect to the
+ Participant Software against such Participant either
+ unilaterally or pursuant to a written agreement with
+ Participant.
+
+ 6.3. In the event of termination under Sections 6.1 or 6.2
+ above, all end user licenses that have been validly granted
+ by You or any distributor hereunder prior to termination
+ (excluding licenses granted to You by any distributor)
+ shall survive termination.
+
+ 7. LIMITATION OF LIABILITY.
+
+ UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+ (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+ INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+ COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE
+ LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+ CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+ LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK
+ STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+ COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+ INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+ LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL
+ INJURY RESULTING FROM SUCH PARTY?S NEGLIGENCE TO THE EXTENT
+ APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO
+ NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT
+ APPLY TO YOU.
+
+ 8. U.S. GOVERNMENT END USERS.
+
+ The Covered Software is a ?commercial item,? as that term is
+ defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of ?commercial
+ computer software? (as that term is defined at 48 C.F.R. ?
+ 252.227-7014(a)(1)) and ?commercial computer software
+ documentation? as such terms are used in 48 C.F.R. 12.212 (Sept.
+ 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1
+ through 227.7202-4 (June 1995), all U.S. Government End Users
+ acquire Covered Software with only those rights set forth herein.
+ This U.S. Government Rights clause is in lieu of, and supersedes,
+ any other FAR, DFAR, or other clause or provision that addresses
+ Government rights in computer software under this License.
+
+ 9. MISCELLANEOUS.
+
+ This License represents the complete agreement concerning subject
+ matter hereof. If any provision of this License is held to be
+ unenforceable, such provision shall be reformed only to the
+ extent necessary to make it enforceable. This License shall be
+ governed by the law of the jurisdiction specified in a notice
+ contained within the Original Software (except to the extent
+ applicable law, if any, provides otherwise), excluding such
+ jurisdiction?s conflict-of-law provisions. Any litigation
+ relating to this License shall be subject to the jurisdiction of
+ the courts located in the jurisdiction and venue specified in a
+ notice contained within the Original Software, with the losing
+ party responsible for costs, including, without limitation, court
+ costs and reasonable attorneys? fees and expenses. The
+ application of the United Nations Convention on Contracts for the
+ International Sale of Goods is expressly excluded. Any law or
+ regulation which provides that the language of a contract shall
+ be construed against the drafter shall not apply to this License.
+ You agree that You alone are responsible for compliance with the
+ United States export administration regulations (and the export
+ control laws and regulation of any other countries) when You use,
+ distribute or otherwise make available any Covered Software.
+
+ 10. RESPONSIBILITY FOR CLAIMS.
+
+ As between Initial Developer and the Contributors, each party is
+ responsible for claims and damages arising, directly or
+ indirectly, out of its utilization of rights under this License
+ and You agree to work with Initial Developer and Contributors to
+ distribute such responsibility on an equitable basis. Nothing
+ herein is intended or shall be deemed to constitute any admission
+ of liability.
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html
index 03b3f352b9..eef0b1de0c 100644
--- a/WebContent/release-notes.html
+++ b/WebContent/release-notes.html
@@ -38,9 +38,8 @@
<h2 id="tableofcontents">Release Notes for Vaadin Framework @version@</h2>
<ul>
<li><a href="#overview">Overview of Vaadin @version@ Release</a></li>
- <li><a href="#security-fixes">Security fixes in Vaadin @version-minor@</a></li>
- <li><a href="#changelog">Complete change log for Vaadin @version@</a></li>
<li><a href="#enhancements">Enhancements in Vaadin @version-minor@</a></li>
+ <li><a href="#changelog">Complete change log for Vaadin @version@</a></li>
<li><a href="#limitations">Limitations in @version-minor@</a></li>
<li><a href="#vaadin">Vaadin Installation</a></li>
<li><a href="#package">Package Contents</a></li>
@@ -54,49 +53,63 @@
<h2 id="overview">Overview of Vaadin @version@ Release</h2>
<p>
- Vaadin @version@ is a maintenance release that includes a number of important bug
- fixes, as listed in the <a href="#changelog">change log</a> below. You can also
- view the <a
+ Vaadin @version@ is a feature release that includes a number of enhancements as
+ well as important bug fixes, as listed in the <a href="#changelog">change log</a>
+ below. You can also view the <a
href="http://dev.vaadin.com/query?status=closed&resolution=fixed&milestone=Vaadin+@version@&order=priority">list
of the closed issues</a> at the Vaadin developer's site.
</p>
- <p>
- For a list of enhancements in the last feature release, see <a
- href="#enhancements">Enhancements in Vaadin @version-minor@</a> and the <a
- href="http://vaadin.com/download/release/@version-minor@/@version-minor@.0/release-notes.html">Release
- Notes for Vaadin @version-minor@.0</a>.
- </p>
-
- <!-- ================================================================ -->
- <h2 id="security-fixes">Security fixes in Vaadin Framework 7.0.4</h2>
+ <h2 id="enhancements">Enhancements in Vaadin @version-minor@</h2>
<p>
- Vaadin 7.0.4 fixes a critical security issue discovered during an
- internal review. All users of Vaadin portlets are strongly urged to
- upgrade to Vaadin 7.0.4 or Vaadin 6.8.10 immediately.
- </p>
- <p>
- Vaadin portlets (Portlet 2.0 - JSR-286) prior to Vaadin versions 6.8.10
- and 7.0.4 are vulnerable to an attack that allows a remote user who has
- access to a portlet on the portal to read files in the portlet deployment
- directory using specially crafted resource requests provided the attacker
- knows the file name.
- </p>
- <p>
- The vulnerability has been classified as critical as it potentially
- allows unauthorized access to portlet object code and configuration
- information. Files outside the portlet deployment directory are not
- accessible using this vulnerability. Portlets that are not visible
- to the remote user are not vulnerable to this attack.
- Servlet deployments are not vulnerable to this attack.
+ The @version-minor@ includes many major and minor enhancements. Below is a list of
+ the most notable changes:
</p>
+
+ <ul>
+ <li>Server push based on Atmosphere</li>
+ <li>CSS injection through a <b>Styles</b> object from <tt>Page.getCurrent().getStyles()</tt></li>
+ <li>Enhanced Debug Window</li>
+ <li><b>Calendar</b> is now included in the core framework</li>
+ <li>The <b>VaadinServlet</b>/-<b>Portlet</b> and <b>-Service</b> have been refactored</li>
+ <li><b>DateField</b> can now have a range</li>
+ <li><b>Window</b> has Maximize/Restore controls</li>
+ <li>WAI-ARIA support for form fields, <b>Button</b>, and <b>Tree</b></li>
+ <li>The page can be reloaded programmatically with <tt>Page.reload()</tt></li>
+ <li>The legacy behavior of Property.toString() can be toggled using the <tt>legacyPropertyToString</tt> init parameter</li>
+ <li>Sass compiler now supports arithmetics</li>
+ <li>Sass compiler now supports <tt>@content</tt></li>
+ <li>Tooltip delays can be configured</li>
+ <li>Loading indicator delays can be configured</li>
+ <li>Layout components have a default alignment</li>
+ <li><b>DefaultFieldGroupFieldFactory</b> supports date fields</li>
+
+ <li>Add-ons containing a theme should specify it with a <tt>Vaadin-Stylesheet</tt>
+ attribute in the manifest</li>
+
+ <li>Native support for Internet Explorer 10</li>
+ <li>Many locking fixes</li>
+ <li>Java <tt>assert</tt> statements added to critical code sections. Start JVM with <tt>-ea</tt> to use.</li>
+ </ul>
+
<p>
- All users of Vaadin portlets are strongly urged to upgrade Vaadin
- in the portlets immediately. Where that is not possible, access to
- affected portlets should be restricted to trusted users only.
+ For enchancements introduced in Vaadin 7, see the <a
+ href="http://vaadin.com/download/release/7.0/7.0.0/release-notes.html">Release
+ Notes for Vaadin 7.0.0</a>.
</p>
+ <h3 id="limitations">Limitations</h3>
+ <ul>
+ <li>It is currently not possible to specify <tt>font-size</tt> as <tt>em</tt> or
+ <tt>%</tt>, or layout component sizes with <tt>em</tt> (<a
+ href="http://dev.vaadin.com/ticket/10634">#10634</a>)</li>
+ <li>Push using streaming does not work in Opera (<a
+ href="http://dev.vaadin.com/ticket/11642">#11642</a>)</li>
+ <li>Some debug console features such as analyze layouts do not work when push is enabled (<a
+ href="http://dev.vaadin.com/ticket/11536">#11536</a>)</li>
+ </ul>
+
<h3 id="changelog">ChangeLog</h3>
<p>
@@ -113,283 +126,6 @@
list of the closed issues</a> can also be found at <tt>dev.vaadin.com</tt>.
</p>
- <h2 id="enhancements">Enhancements in Vaadin @version-minor@</h2>
-
- <p>
- The @version-minor@ includes many major and minor enhancements and changes first
- introduced in Vaadin @version-minor@.0. Below is a list of the most notable changes:
- </p>
-
- <ul>
- <li>UI replaces Application as the main entry point
- <ul>
- <li>Heartbeat to reliably detect closed UI</li>
- <li>Supports multiple browser tabs by default</li>
- <li>Browser and request details available in UI init</li>
- <li>Direct access to request and session in UI init</li>
- <li>Access detected browser details in UI init</li>
- <li>Default UI class chosen based on a servlet parameter</li>
- <li>Custom UIProvider allows providing different UIs based on request parameters</li>
- <li>UI is by default reinitialized when the page is reloaded</li>
- </ul>
- </li>
- <li>Redesigned layouts
- <ul>
- <li>Minimal or no layout calculations to maximize layout speed</li>
- <li>Full control of layouts with CSS including borders and margins</li>
- <li>Redesigned lighter DOM for vertical, horizontal and css layout</li>
- <li>Client-side ComputedStyle API available</li>
- </ul>
- </li>
- <li>Split to seven jars to allow deploying only what you need</li>
- <li>Adding multiple components with varargs in addComponents and appropriate constructors</li>
- <li>Support for mixing multiple themes on the same page</li>
-
- <li>RPC for communication between the server and the browser
- <ul>
- <li>Static typing allows compile time checking</li>
- <li>Supports Java's primitive and boxed types, String, enums, arrays, List, Set, Map and Java beans</li>
- <li>Supports references to external or self served resources and references to other components</li>
- <li>Call from browser to server can be delayed to piggyback on the next XHR, optionally folding similar calls to only send the last value</li>
- <li>Calls to disabled or invisible components are ignored for security reasons</li>
- </ul>
- </li>
- <li>Server-client shared state
- <ul>
- <li>Java objects can be shared between client and server for easy component development</li>
- <li>State is automatically mirrored from server to client</li>
- <li>Support both public fields and bean properties</li>
- <li>Supports the same types as with RPC</li>
- <li>Only parts of the state that are modified are sent over the wire</li>
- <li>Allow calculating state on the fly just before state is sent to client</li>
- <li>Client-side can listen to shared state changes to simplify connectors</li>
- <li>State class can be annotated to automatically delegate state changes to corresponding properties in widgets</li>
- </ul>
- </li>
- <li>Google Web Toolkit included
- <ul>
- <li>A full copy of GWT is included in Vaadin Framework</li>
- <li>Vaadin team maintains a branch of GWT to include bug fixes and new features independent of official GWT release schedules</li>
- <li>All functionality of GWT is included to enable writing of client side UI:s, stateless applications, offline functionality and custom widgets</li>
- <li>Included Elemental library gives direct access to all cutting edge browser features</li>
- <li>Both browser plug-in based dev mode debugging as well as super dev mode are supported</li>
- </ul>
- </li>
- <li>No more need to call requestRepaint() in components</li>
- <li>High level view navigation
- <ul>
- <li>Support for URI fragment based view management</li>
- <li>Support for registering both pre-initialized view instances as well as view classes</li>
- <li>Programmatic navigation with navigateTo()</li>
- <li>Supports saving bookmarks to views</li>
- <li>Supports parameterized views</li>
- <li>Views can block navigation</li>
- </ul>
- </li>
- <li>Connectors
- <ul>
- <li>Connectors provide a flexible communication channel between client and server</li>
- <li>Separating communication code from widgets promotes reusability</li>
- <li>An explicit Connector hierarchy is maintained</li>
- <li>Mapping between server-side and client-side defined in client-side code to avoid server-side classpath issues</li>
- </ul>
- </li>
- <li>JavaScript Connectors
- <ul>
- <li>Implement connector logic using JavaScript instead of Java for easier integration with JavaScript libraries</li>
- <li>Wrap around any existing JavaScript based widget to adapt it for use in Vaadin</li>
- <li>No widgetset compilation needed</li>
- <li>Support for shared state and RPC as well as JSON-based communication based on simple JavaScript functions</li>
- </ul>
- </li>
- <li>ColorPicker component
- <ul>
- <li>Easy to use interface with clickable color gradients</li>
- <li>RGB, HSV and swatches color modes</li>
- <li>Color history</li>
- <li>Color preview</li>
- <li>CSS color code representation and handling</li>
- </ul>
- </li>
- <li>Add listeners without method overloads
- <ul>
- <li>Write addClickListener() instead of generic addListener()</li>
- <li>Supports code completion in IDE:s better</li>
- <li>Enables using Java 8 Lambda</li>
- </ul>
- </li>
- <li>Renewed Vaadin Maven Plugin including features from GWT Maven Plugin
- <ul>
- <li>New Maven architype eases creation of Vaadin 7 applications</li>
- </ul>
- </li>
- <li>Renewed Eclipse Plugin adding Apache Ivy based dependency management</li>
- <li>Page bootstrapping renewed
- <ul>
- <li>Simpler inclusion of Vaadin UIs to custom web pages</li>
- <li>Add-ons and applications can dynamically modify bootstrap page HTML</li>
- </ul>
- </li>
- <li>VaadinSession
- <ul>
- <li>Full control over session lifecycle</li>
- <li>Abstract away from servlets and portlets</li>
- </ul>
- </li>
- <li>VaadinService
- <ul>
- <li>Easily access deployment information and HTTP requests</li>
- <li>Abstract away from servlets and portlets</li>
- </ul>
- </li>
- <li>Component extension API
- <ul>
- <li>Allow adding functionality and customizations to any component</li>
- <li>Modify DOM and hook event listeners</li>
- </ul>
- </li>
- <li>JavaScript callbacks
- <ul>
- <li>Declare client-side JavaScript API from server</li>
- <li>Eases integration with parts of the page not controlled with Vaadin</li>
- </ul>
- </li>
- <li>Relative paths used for all requests
- <ul>
- <li>More flexible deployment</li>
- <li>Adds support for Apache ProxyPass and other similar proxies</li>
- </ul>
- </li>
- <li>HTML5
- <ul>
- <li>Vaadin 7 uses HTML5 doctype</li>
- <li>Use any parts of HTML5 in your application</li>
- </ul>
- </li>
- <li>Page
- <ul>
- <li>Abstraction for one browser window</li>
- <li>Run JavaScript</li>
- <li>Listen to page resizes</li>
- <li>Control navigation</li>
- </ul>
- </li>
- <li>Loading custom JavaScript
- <ul>
- <li>Annotate server-side classes with @JavaScript to request loading of JavaScript files</li>
- <li>Automated control of loading order and ensuring that files are loaded only once</li>
- </ul>
- </li>
- <li>API cleanup
- <ul>
- <li>API deprecated in Vaadin 6 or before removed</li>
- <li>Use enums instead of integer constants</li>
- </ul>
- </li>
- <li>Embedded split up to different components for different purposes
- <ul>
- <li>Image for showing images</li>
- <li>BrowserFrame for embedding web pages with iframes</li>
- <li>Flash for embedding Flash content</li>
- <li>Embedded now only intended for embedding using &lt;object&gt;
- </ul>
- </li>
- <li>Support for Firefox 17 extended support release in addition to latest stable Firefox release</li>
- <li>Sass Compiler
- <ul>
- <li>Allows modularization of themes for better reuse and easier maintenance</li>
- <li>Support the most important features of SCSS</li>
- <li>Pure Java implementation without Ruby dependency</li>
- <li>Supports all of CSS</li>
- <li>On the fly conversion of SCSS to CSS during development</li>
- <li>Built in themes are now based on Sass</li>
- <li>Can be used in client-side projects as well</li>
- </ul>
- </li>
- <li>@StyleSheet for automatic injection of css files</li>
- <li>ConnectorResource replaces ApplicationResource to reduce memory consumption</li>
- <li>Hierarchical error handling</li>
- <li>Open popups and start downloads in a way not stopped by popup blockers</li>
- <li>ThreadLocal access to VaadinService, VaadinRequest, VaadinResponse, VaadinSession and the current UI instance</li>
- <li>Component id replaces debug ids to allow wider use possibilities for identifying corresponding widget elements in DOM</li>
- <li>Range retrieval for indexed containers to enable optimize performance</li>
- <li>Native support for percent sizes to let the browser do the percent to pixel calculation speeds up rendering</li>
- <li>Custom class loader
- <ul>
- <li>Allow specifying custom class loaders to better support Java EE, CDI and Spring</li>
- <li>Supports both servlets and portlets</li>
- </ul>
- </li>
- <li>Updated data model
- <ul>
- <li>Property getValue() uses generics to return the expected type</li>
- <li>Two phase commit support for commit/rollback</li>
- <li>BeanItem supports nested properties to allow flattening complex datatypes</li>
- </ul>
- </li>
- <li>Bean Validation - Annotate beans with JSR-303 standard annotations to automatically create validators for the fields</li>
- <li>Field group
- <ul>
- <li>Allow data binding of multiple fields together to item data source</li>
- <li>Supports buffering</li>
- <li>Supports two phase commit</li>
- <li>Annotation based and field name based property mapping</li>
- </ul>
- </li>
- <li>Explicit data model converters
- <ul>
- <li>All fields support explicit conversion from presentation format to data source format</li>
- <li>Conversions are bidirectional</li>
- <li>Allow defining a default converter for a specific type and override for specific fields</li>
- <li>Converters can be set per Table column to customize column formatting</li>
- </ul>
- </li>
- <li>Built-in default converters
- <ul>
- <li>automated conversions beween String, Boolean, Long, Date, Double, Float, Integer and Number</li>
- <li>Built in converters support internationalization</li>
- </ul>
- </li>
- <li>Custom field component for building new fields as composition of existing components</li>
- <li>Simplified validation API
- <ul>
- <li>No need to implement isValid() in validators any more</li>
- </ul>
- </li>
- <li>Unsupported browser detection with customizable information page</li>
- <li>Vaadin 6 compatibility layer to ease migration from Vaadin 6</li>
- <li>Explicit layouts for Window and Panel</li>
- <ul>
- <li>Window and Panel components now require setting layout explicitly</li>
- <li>Distinction between Window or Panel and it's layout</li>
- </ul>
- </li>
- <li>Layout manager
- <ul>
- <li>Allows building custom layout calculations for widgets when browser based layouts are not powerful enough</li>
- <li>Optimizes number of reflows by batching layout calculations from multiple widgets together</li>
- </ul>
- </li>
- </ul>
-
- <p>
- There are many other enhancements. Most of them are described in more detail in
- the <a href="https://vaadin.com/wiki/-/wiki/Main/Vaadin+7">mini-tutorials</a> in
- the Vaadin Wiki. Also see the <a
- href="https://vaadin.com/wiki/-/wiki/Main/Migrating+from+Vaadin+6+to+Vaadin+7">Vaadin
- 6 to 7 Migration Guide</a>. See also the <a
- href="http://vaadin.com/download/release/@version-minor@/@version-minor@.0/release-notes.html">Release
- Notes for Vaadin @version-minor@.0</a>.
- </p>
-
- <h3 id="limitations">Limitations</h3>
-
- <ul>
- <li>It is currently not possible to specify <tt>font-size</tt> as <tt>em</tt> or
- <tt>%</tt>, or layout component sizes with <tt>em</tt> (<a
- href="http://dev.vaadin.com/ticket/10634">#10634</a>)</li>
- </ul>
-
<h2 id="vaadin">Vaadin Installation</h2>
<p>
@@ -409,7 +145,8 @@
of this release) to create a new project</li>
<li>If using Eclipse, use the Vaadin Plugin for Eclipse, which automatically
- downloads the Vaadin libraries</li>
+ downloads the Vaadin libraries. To use this prerelease version, the plugin should be
+ installed from the experimental update site (<tt>http://vaadin.com/eclipse/experimental</tt>).</li>
</ul>
<p>
@@ -688,12 +425,12 @@
</p>
<ul>
- <li>Mozilla Firefox 18-19</li>
+ <li>Mozilla Firefox 18-20</li>
<li>Mozilla Firefox 17 ESR</li>
<li>Internet Explorer 8-10</li>
<li>Safari 6</li>
<li>Opera 12</li>
- <li>Google Chrome 23-25</li>
+ <li>Google Chrome 23-26</li>
</ul>
<p>
diff --git a/all/build.xml b/all/build.xml
index 40d82b3d47..4e1a557e53 100644
--- a/all/build.xml
+++ b/all/build.xml
@@ -113,7 +113,7 @@
<target name="checkstyle">
<!-- Checkstyle is handled by all separate modules -->
</target>
- <target name="tests" depends="checkstyle">
+ <target name="test" depends="checkstyle">
<!-- No tests for this zip.. -->
</target>
diff --git a/all/ivy.xml b/all/ivy.xml
index 103d65e812..2b212f6675 100644
--- a/all/ivy.xml
+++ b/all/ivy.xml
@@ -32,6 +32,8 @@
rev="${vaadin.version}"/>
<dependency org="com.vaadin" name="vaadin-client-compiled"
rev="${vaadin.version}"/>
+ <dependency org="com.vaadin" name="vaadin-push"
+ rev="${vaadin.version}"/>
</dependencies>
diff --git a/build.xml b/build.xml
index 306b169bc7..37e4afd03b 100644
--- a/build.xml
+++ b/build.xml
@@ -40,7 +40,10 @@
<target name="checkstyle" depends="buildorder">
<subant buildpathref="build-path" target="checkstyle"/>
</target>
- <target name="tests" depends="buildorder">
+ <target name="test" depends="buildorder">
+ <subant buildpathref="build-path" target="test" />
+ </target>
+ <target name="test-all" depends="buildorder">
<property name="war.file" location="result/artifacts/${vaadin.version}/vaadin-uitest/vaadin-uitest-${vaadin.version}.war" />
<parallel>
<sequential>
@@ -50,7 +53,7 @@
<property name="demo.war" value="${war.file}" />
</ant>
</sequential>
- <subant buildpathref="build-path" target="tests" />
+ <subant buildpathref="build-path" target="test" />
<ant antfile="uitest/test.xml" target="test-package">
<property name="war.file" location="${war.file}" />
</ant>
diff --git a/build/ide.xml b/build/ide.xml
index a095e9265c..b1845020f3 100755
--- a/build/ide.xml
+++ b/build/ide.xml
@@ -1,31 +1,55 @@
<?xml version="1.0"?>
<project xmlns:antcontrib="antlib:net.sf.antcontrib" xmlns:artifact="antlib:org.apache.maven.artifact.ant" xmlns:ivy="antlib:org.apache.ivy.ant" name="Build script for IDE users" basedir=".." default="theme-and-default-widgetset">
- <!-- FIXME, should use 7.0-SNAPSHOT of client compiler -->
+ <include file="${basedir}/gwt-files.xml" />
+
+ <property name="gwt.dev.classes" location="${gwt.eclipse.basedir}/dev/bin" />
+ <property name="gwt.user.classes" location="${gwt.eclipse.basedir}/user/bin" />
+ <property name="gwt.dev.src" location="${gwt.basedir}/dev/core/src" />
+ <property name="gwt.dev.super.src" location="${gwt.basedir}/dev/core/super" />
+ <property name="gwt.user.src" location="${gwt.basedir}/user/src" />
+ <property name="gwt.user.super.src" location="${gwt.basedir}/user/super" />
+
<property name="work.dir" location="work" />
- <property name="gwt.root" location="${basedir}/../trunk" />
- <property name="gwt.lib.dir" location="${gwt.root}/build/lib" />
- <property name="gwt.user.jar" location="${gwt.lib.dir}/gwt-user.jar" />
- <property name="gwt.dev.jar" location="${gwt.lib.dir}/gwt-dev.jar" />
<property name="theme-version" location="9.9.9.INTERNAL-DEBUG-BUILD" />
- <echo>Using gwt-dev.jar from ${gwt.dev.jar}</echo>
+ <echo>Using gwt files from ${gwt.user.classes} and ${gwt.dev.classes}</echo>
- <ivy:resolve file="build/ivy-ide.xml" />
- <ivy:cachepath pathid="ivy.deps" conf="default" />
+ <ivy:resolve file="client-compiler/ivy.xml" conf="ide" />
+ <ivy:cachepath pathid="client-compiler.deps" conf="ide" />
+ <ivy:resolve file="server/ivy.xml" conf="ide" />
+ <ivy:cachepath pathid="server.deps" conf="ide" />
+ <ivy:resolve file="client/ivy.xml" conf="ide" />
+ <ivy:cachepath pathid="client.deps" conf="ide" />
+ <ivy:resolve file="shared/ivy.xml" conf="ide" />
+ <ivy:cachepath pathid="shared.deps" conf="ide" />
+ <ivy:resolve file="uitest/ivy.xml" conf="ide" />
+ <ivy:cachepath pathid="uitest.deps" conf="ide" />
+ <ivy:resolve file="theme-compiler/ivy.xml" conf="ide" />
+ <ivy:cachepath pathid="theme-compiler.deps" conf="ide" />
<path id="classpath">
<path location="bin" />
<path location="build/classes" />
- <pathelement location="${gwt.user.jar}" />
- <pathelement location="${gwt.dev.jar}" />
- <path refid="ivy.deps" />
+ <path location="${gwt.user.classes}" />
+ <path location="${gwt.user.src}" />
+ <path location="${gwt.user.super.src}" />
+ <path location="${gwt.dev.classes}" />
+ <path location="${gwt.dev.super.src}" />
+ <path location="${gwt.dev.src}" />
+ <path refid="client-compiler.deps" />
+ <path refid="theme-compiler.deps" />
+ <path refid="server.deps" />
+ <path refid="shared.deps" />
+ <path refid="uitest.deps" />
+ <path refid="client.deps" />
+ <path location="theme-compiler/src" />
<path location="server/src" />
<path location="shared/src" />
<path location="uitest/src" />
<path location="client/src" />
</path>
- <target name="theme-and-default-widgetset" depends="default-widgetset, themes">
+ <target name="theme-and-default-widgetset" depends="default-widgetset, themes, vaadinPush.js">
</target>
<target name="themes">
<antcall target="compile-theme">
@@ -58,8 +82,22 @@
</java>
</target>
+
+
<target name="default-widgetset">
- <property name="module" value="com.vaadin.DefaultWidgetSet" />
+ <antcall target="compile-widgetset">
+ <param name="widgetset" value="com.vaadin.DefaultWidgetSet" />
+ </antcall>
+ </target>
+
+ <target name="testing-widgetset">
+ <antcall target="compile-widgetset">
+ <param name="widgetset" value="com.vaadin.tests.widgetset.TestingWidgetSet" />
+ </antcall>
+ </target>
+
+ <target name="compile-widgetset">
+ <property name="module" value="${widgetset}" />
<property name="module.output.dir" location="WebContent/VAADIN/widgetsets" />
<property name="style" value="PRETTY" />
<property name="localWorkers" value="2" />
@@ -93,7 +131,22 @@
<jvmarg value="-Xss8M" />
<jvmarg value="-XX:MaxPermSize=256M" />
<jvmarg value="-Djava.awt.headless=true" />
+ <jvmarg value="-Dgwt.usearchives=false" />
</java>
+ </target>
+ <target name="vaadinPush.js">
+ <property name="vaadinPush.js.output" location="WebContent/VAADIN/vaadinPush.js" />
+ <loadfile srcfile="WebContent/VAADIN/jquery-1.7.2.js" property="jquery.js.contents" />
+ <loadfile srcfile="WebContent/VAADIN/jquery.atmosphere.js" property="jquery.atmosphere.js.contents" />
+ <loadfile srcfile="WebContent/VAADIN/vaadinPush.js.tpl" property="vaadinPush.js.contents">
+ <filterchain>
+ <replacetokens begintoken="@" endtoken="@">
+ <token key="jquery.js" value="${jquery.js.contents}" />
+ <token key="jquery.atmosphere.js" value="${jquery.atmosphere.js.contents}" />
+ </replacetokens>
+ </filterchain>
+ </loadfile>
+ <echo file="${vaadinPush.js.output}">${vaadinPush.js.contents}</echo>
</target>
</project> \ No newline at end of file
diff --git a/build/ivy-ide.xml b/build/ivy-ide.xml
deleted file mode 100755
index 85d157857a..0000000000
--- a/build/ivy-ide.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ivy-module version="2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
-
- <info organisation="com.vaadin" module="vaadin-ide"
- revision="0.0.1.ide" />
-
- <configurations>
- <conf name="default" />
- </configurations>
- <publications>
- </publications>
- <dependencies defaultconf="default" defaultconfmapping="default->default">
- <dependency org="javax.validation" name="validation-api"
- rev="1.0.0.GA" conf="default -> default,sources" />
- <dependency org="commons-cli" name="commons-cli" rev="1.2" />
- <dependency org="org.apache.commons" name="commons-jexl"
- rev="2.1.1" />
-
- </dependencies>
-
-</ivy-module>
diff --git a/buildhelpers/build.xml b/buildhelpers/build.xml
index b56209f6cc..a101bff191 100644
--- a/buildhelpers/build.xml
+++ b/buildhelpers/build.xml
@@ -43,8 +43,8 @@
</antcall>
</target>
- <target name="tests" depends="checkstyle">
- <!--<antcall target="common.tests.run" />-->
+ <target name="test" depends="checkstyle">
+ <!--<antcall target="common.test.run" />-->
<echo>WHAT? No JUnit tests for ${module.name}!</echo>
</target>
</project> \ No newline at end of file
diff --git a/buildhelpers/ivy.xml b/buildhelpers/ivy.xml
index d8e4457296..7c0a7b82a7 100644
--- a/buildhelpers/ivy.xml
+++ b/buildhelpers/ivy.xml
@@ -18,7 +18,7 @@
<conf name="build" />
<conf name="build-provided" />
<conf name="ide" visibility="private" />
- <conf name="tests" />
+ <conf name="test" />
</configurations>
<publications>
<artifact type="jar" />
@@ -28,7 +28,7 @@
</publications>
<dependencies>
- <dependency org="commons-io" name="commons-io" rev="1.4" />
+ <dependency org="commons-io" name="commons-io" rev="2.2" />
</dependencies>
</ivy-module>
diff --git a/client-compiled/build.xml b/client-compiled/build.xml
index 1a78b17a7f..c9c3244c0e 100644
--- a/client-compiled/build.xml
+++ b/client-compiled/build.xml
@@ -85,6 +85,7 @@
<arg value="-localWorkers" />
<arg value="${localWorkers}" />
<arg value="-strict" />
+ <arg value="-XenableClosureCompiler" />
<arg line="${extraParams}" />
<arg value="${module}" />
@@ -130,8 +131,8 @@
<target name="checkstyle">
<echo>No java files in module</echo>
</target>
- <target name="tests" depends="checkstyle">
- <!--<antcall target="common.tests.run" />-->
+ <target name="test" depends="checkstyle">
+ <!--<antcall target="common.test.run" />-->
<echo>WHAT? No tests for ${module.name}!</echo>
</target>
diff --git a/client-compiler/build.xml b/client-compiler/build.xml
index 64368b4957..cd8433f1cf 100644
--- a/client-compiler/build.xml
+++ b/client-compiler/build.xml
@@ -60,8 +60,8 @@ gwt.svnrev=${git.revision}</echo>
</antcall>
</target>
- <target name="tests" depends="checkstyle">
- <!--<antcall target="common.tests.run" />-->
+ <target name="test" depends="checkstyle">
+ <!--<antcall target="common.test.run" />-->
<echo>WHAT? No tests for ${module.name}!</echo>
</target>
diff --git a/client-compiler/ivy.xml b/client-compiler/ivy.xml
index ee36e4e261..b26de51aca 100644
--- a/client-compiler/ivy.xml
+++ b/client-compiler/ivy.xml
@@ -1,57 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<ivy-module version="2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"
- xmlns:m="http://ant.apache.org/ivy/maven">
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"
+ xmlns:m="http://ant.apache.org/ivy/maven">
- <info organisation="com.vaadin" module="vaadin-client-compiler"
- revision="${vaadin.version}" />
+ <info organisation="com.vaadin" module="vaadin-client-compiler"
+ revision="${vaadin.version}" />
- <configurations>
- <conf name="build" />
- <conf name="build-provided" />
- <conf name="ide" visibility="private" />
- </configurations>
- <publications>
- <artifact type="jar" ext="jar" />
- <artifact type="source" ext="jar" m:classifier="sources" />
- <artifact type="javadoc" ext="jar" m:classifier="javadoc" />
- <artifact type="pom" ext="pom" />
- </publications>
- <dependencies>
- <dependency org="com.vaadin" name="vaadin-shared"
- rev="${vaadin.version}" conf="build" />
- <dependency org="com.vaadin" name="vaadin-server"
- rev="${vaadin.version}" conf="build" />
- <dependency org="com.vaadin" name="vaadin-client"
- rev="${vaadin.version}" conf="build" />
+ <configurations>
+ <conf name="build" />
+ <conf name="build-provided" />
+ <conf name="ide" visibility="private" />
+ </configurations>
+ <publications>
+ <artifact type="jar" ext="jar" />
+ <artifact type="source" ext="jar" m:classifier="sources" />
+ <artifact type="javadoc" ext="jar" m:classifier="javadoc" />
+ <artifact type="pom" ext="pom" />
+ </publications>
+ <dependencies>
+ <dependency org="com.vaadin" name="vaadin-shared" rev="${vaadin.version}"
+ conf="build" />
+ <dependency org="com.vaadin" name="vaadin-server" rev="${vaadin.version}"
+ conf="build" />
+ <dependency org="com.vaadin" name="vaadin-client" rev="${vaadin.version}"
+ conf="build" />
<dependency org="com.vaadin" name="vaadin-theme-compiler"
rev="${vaadin.version}" conf="build" />
-
- <dependency org="commons-collections" name="commons-collections"
- rev="3.1" conf="build,ide -> default" />
- <dependency org="ant" name="ant" rev="1.6.5"
- conf="build,ide -> default" />
- <dependency org="net.sourceforge.cssparser" name="cssparser"
- rev="0.9.5" conf="build,ide -> default" />
- <dependency org="ant" name="ant" rev="1.6.5"
- conf="build,ide -> default" />
- <dependency org="ant" name="ant-launcher" rev="1.6.5"
- conf="build,ide -> default" />
- <dependency org="org.mortbay.jetty" name="jetty" rev="6.1.11"
- conf="build,ide -> default" />
- <dependency org="org.mortbay.jetty" name="jetty-util"
- rev="6.1.11" conf="build,ide -> default" />
- <dependency org="org.jdesktop" name="swing-worker"
- rev="1.1" conf="build,ide -> default" />
- <dependency org="commons-codec" name="commons-codec"
- rev="1.3" conf="build,ide -> default" />
- <dependency org="commons-io" name="commons-io" rev="1.4"
- conf="build,ide -> default" />
- <dependency org="commons-lang" name="commons-lang"
- rev="2.6" conf="build,ide -> default" />
- <dependency org="org.apache.james" name="apache-mime4j"
- rev="0.6" conf="build,ide -> default" />
- </dependencies>
+
+ <dependency org="commons-collections" name="commons-collections"
+ rev="3.1" conf="build,ide -> default" />
+ <dependency org="commons-logging" name="commons-logging"
+ rev="1.1.1" conf="build,ide -> default" />
+
+ <dependency org="ant" name="ant" rev="1.6.5" conf="build,ide -> default" />
+ <dependency org="net.sourceforge.cssparser" name="cssparser"
+ rev="0.9.5" conf="build,ide -> default" />
+ <dependency org="ant" name="ant" rev="1.6.5" conf="build,ide -> default" />
+ <dependency org="ant" name="ant-launcher" rev="1.6.5"
+ conf="build,ide -> default" />
+ <dependency org="org.mortbay.jetty" name="jetty" rev="6.1.11"
+ conf="build,ide -> default" />
+ <dependency org="org.mortbay.jetty" name="jetty-util" rev="6.1.11"
+ conf="build,ide -> default" />
+ <dependency org="org.jdesktop" name="swing-worker" rev="1.1"
+ conf="build,ide -> default" />
+ <dependency org="commons-codec" name="commons-codec" rev="1.3"
+ conf="build,ide -> default" />
+ <dependency org="commons-io" name="commons-io" rev="2.2"
+ conf="build,ide -> default" />
+ <dependency org="commons-lang" name="commons-lang" rev="2.6"
+ conf="build,ide -> default" />
+ <dependency org="org.apache.james" name="apache-mime4j"
+ rev="0.6" conf="build,ide -> default" />
+
+ <dependency org="com.vaadin" name="vaadin-client-compiler-deps"
+ rev="1.0.1" conf="build,ide -> default" />
+
+ </dependencies>
</ivy-module>
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
index 2be3bf5a16..f8aa586064 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java
@@ -334,22 +334,6 @@ public class ConnectorBundleLoaderFactory extends Generator {
writeGetters(logger, w, bundle);
writeSerializers(logger, w, bundle);
writeDelegateToWidget(logger, w, bundle);
- writeHasGetTooltip(logger, w, bundle);
- }
-
- /**
- * @deprecated As of 7.0.1. This is just a hack to avoid breaking backwards
- * compatibility and will be removed in Vaadin 7.1
- */
- @Deprecated
- private void writeHasGetTooltip(TreeLogger logger, SplittingSourceWriter w,
- ConnectorBundle bundle) {
- Set<JClassType> types = bundle.getHasGetTooltip();
- for (JClassType type : types) {
- w.println("store.setHasGetTooltipInfo(%s);",
- getClassLiteralString(type));
- w.splitIfNeeded();
- }
}
private void writeDelegateToWidget(TreeLogger logger,
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
index f6dc982f15..cbdd3e89aa 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java
@@ -63,7 +63,6 @@ public class ConnectorBundle {
private final Set<JClassType> needsGwtConstructor = new HashSet<JClassType>();
private final Set<JClassType> visitedTypes = new HashSet<JClassType>();
private final Set<JClassType> needsProxySupport = new HashSet<JClassType>();
- private final Set<JClassType> hasGetTooltip = new HashSet<JClassType>();
private final Map<JClassType, Set<String>> identifiers = new HashMap<JClassType, Set<String>>();
private final Map<JClassType, Set<JMethod>> needsReturnType = new HashMap<JClassType, Set<JMethod>>();
@@ -620,37 +619,4 @@ public class ConnectorBundle {
return Collections.unmodifiableSet(needsDelegateToWidget);
}
- /**
- * @deprecated As of 7.0.1. This is just a hack to avoid breaking backwards
- * compatibility and will be removed in Vaadin 7.1
- */
- @Deprecated
- public Set<JClassType> getHasGetTooltip() {
- return Collections.unmodifiableSet(hasGetTooltip);
- }
-
- /**
- * @deprecated As of 7.0.1. This is just a hack to avoid breaking backwards
- * compatibility and will be removed in Vaadin 7.1
- */
- @Deprecated
- public void setHasGetTooltip(JClassType type) {
- if (!isHasGetTooltip(type)) {
- hasGetTooltip.add(type);
- }
- }
-
- /**
- * @deprecated As of 7.0.1. This is just a hack to avoid breaking backwards
- * compatibility and will be removed in Vaadin 7.1
- */
- @Deprecated
- private boolean isHasGetTooltip(JClassType type) {
- if (hasGetTooltip.contains(type)) {
- return true;
- } else {
- return previousBundle != null
- && previousBundle.isHasGetTooltip(type);
- }
- }
} \ No newline at end of file
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java
index 662ecf872b..4de9d2ae99 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java
+++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/WidgetInitVisitor.java
@@ -47,25 +47,6 @@ public class WidgetInitVisitor extends TypeVisitor {
bundle.setNeedsReturnType(type, getWidget);
}
- // Hack to detect when getTooltipInfo has a custom implementation
- // #11051
- JClassType getTooltipParamType = type.getOracle().findType(
- "com.google.gwt.dom.client.Element");
- JMethod getTooltipInfoMethod = findInheritedMethod(type,
- "getTooltipInfo", getTooltipParamType);
- if (getTooltipInfoMethod == null) {
- logger.log(Type.ERROR, "Could not find getTooltipInfo in "
- + type.getQualifiedSourceName());
- throw new UnableToCompleteException();
- }
- JClassType enclosingType = getTooltipInfoMethod.getEnclosingType();
- if (!enclosingType.getQualifiedSourceName().equals(
- AbstractComponentConnector.class.getCanonicalName())) {
- logger.log(Type.WARN, type.getQualifiedSourceName()
- + " has overridden getTooltipInfo");
- bundle.setHasGetTooltip(type);
- }
-
// Check state properties for @DelegateToWidget
JMethod getState = findInheritedMethod(type, "getState");
JClassType stateType = getState.getReturnType().isClass();
diff --git a/client/build.xml b/client/build.xml
index d0dae91dfa..a2262eed7d 100644
--- a/client/build.xml
+++ b/client/build.xml
@@ -20,7 +20,7 @@
-->
<fileset file="${gwt.user.jar}" />
</path>
- <path id="classpath.tests.custom" />
+ <path id="classpath.test.custom" />
<target name="jar">
<property name="jar.file" location="${result.dir}/lib/${module.name}-${vaadin.version}.jar" />
@@ -69,8 +69,8 @@
</antcall>
</target>
- <target name="tests" depends="checkstyle">
- <antcall target="common.tests.run" />
+ <target name="test" depends="checkstyle">
+ <antcall target="common.test.run" />
</target>
</project> \ No newline at end of file
diff --git a/client/ivy.xml b/client/ivy.xml
index 4b56338c24..5d079537b9 100644
--- a/client/ivy.xml
+++ b/client/ivy.xml
@@ -11,7 +11,7 @@
<conf name="build" />
<conf name="build-provided" />
<conf name="ide" visibility="private" />
- <conf name="tests" />
+ <conf name="test" />
</configurations>
<publications>
<artifact type="jar" ext="jar" />
@@ -25,15 +25,15 @@
<!-- LIBRARY DEPENDENCIES (compile time) -->
<!-- Project modules -->
<dependency org="com.vaadin" name="vaadin-shared"
- rev="${vaadin.version}" conf="build,tests->build"></dependency>
+ rev="${vaadin.version}" conf="build,test->build"></dependency>
<dependency org="com.vaadin" name="vaadin-server"
- rev="${vaadin.version}" conf="build->build"></dependency>
+ rev="${vaadin.version}" conf="build,test->build"></dependency>
<!-- gwt-user dependencies -->
<dependency org="org.w3c.css" name="sac" rev="1.3" />
<dependency org="junit" name="junit" rev="4.5"
- conf="tests->default" />
+ conf="test->default" />
<dependency org="javax.validation" name="validation-api"
rev="1.0.0.GA" conf="build->default,sources" />
diff --git a/client/src/com/vaadin/Vaadin.gwt.xml b/client/src/com/vaadin/Vaadin.gwt.xml
index dcc5b0d294..a4eb88d9b4 100644
--- a/client/src/com/vaadin/Vaadin.gwt.xml
+++ b/client/src/com/vaadin/Vaadin.gwt.xml
@@ -12,7 +12,13 @@
<inherits name="com.google.gwt.http.HTTP" />
<inherits name="com.google.gwt.json.JSON" />
-
+
+ <inherits name="com.google.gwt.logging.Logging" />
+ <!-- Firebug handler is deprecated but for some reason still enabled by default -->
+ <set-property name="gwt.logging.firebugHandler" value="DISABLED" />
+ <!-- Disable popup logging as we have our own popup logger -->
+ <set-property name="gwt.logging.popupHandler" value="DISABLED" />
+
<inherits name="com.vaadin.VaadinBrowserSpecificOverrides" />
<source path="client" />
@@ -24,10 +30,6 @@
<when-type-is class="com.google.gwt.core.client.impl.SchedulerImpl" />
</replace-with>
- <replace-with class="com.vaadin.client.VDebugConsole">
- <when-type-is class="com.vaadin.client.Console" />
- </replace-with>
-
<generate-with
class="com.vaadin.server.widgetsetutils.AcceptCriteriaFactoryGenerator">
<when-type-is class="com.vaadin.client.ui.dd.VAcceptCriterionFactory" />
@@ -39,6 +41,10 @@
class="com.vaadin.client.metadata.ConnectorBundleLoader" />
</generate-with>
+ <replace-with class="com.vaadin.client.communication.AtmospherePushConnection">
+ <when-type-is class="com.vaadin.client.communication.PushConnection" />
+ </replace-with>
+
<!-- Set vaadin.profiler to true to include profiling support in the module -->
<define-property name="vaadin.profiler" values="true,false" />
<set-property name="vaadin.profiler" value="false" />
diff --git a/client/src/com/vaadin/client/ApplicationConfiguration.java b/client/src/com/vaadin/client/ApplicationConfiguration.java
index 2291f21361..adf5e1de9d 100644
--- a/client/src/com/vaadin/client/ApplicationConfiguration.java
+++ b/client/src/com/vaadin/client/ApplicationConfiguration.java
@@ -20,6 +20,9 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
@@ -28,8 +31,15 @@ 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.logging.client.LogConfiguration;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
+import com.vaadin.client.debug.internal.ErrorNotificationHandler;
+import com.vaadin.client.debug.internal.HierarchySection;
+import com.vaadin.client.debug.internal.LogSection;
+import com.vaadin.client.debug.internal.NetworkSection;
+import com.vaadin.client.debug.internal.Section;
+import com.vaadin.client.debug.internal.VDebugWindow;
import com.vaadin.client.metadata.BundleLoadCallback;
import com.vaadin.client.metadata.ConnectorBundleLoader;
import com.vaadin.client.metadata.NoDataException;
@@ -259,7 +269,16 @@ public class ApplicationConfiguration implements EntryPoint {
}
public String getThemeUri() {
- return vaadinDirUrl + "themes/" + getThemeName();
+ return getVaadinDirUrl() + "themes/" + getThemeName();
+ }
+
+ /**
+ * Gets the URL of the VAADIN directory on the server.
+ *
+ * @return the URL of the VAADIN directory
+ */
+ public String getVaadinDirUrl() {
+ return vaadinDirUrl;
}
public void setAppId(String appId) {
@@ -365,7 +384,6 @@ public class ApplicationConfiguration implements EntryPoint {
if (jsoConfiguration.getConfigBoolean("initPending") == Boolean.FALSE) {
setBrowserDetailsSent();
}
-
}
/**
@@ -546,32 +564,50 @@ public class ApplicationConfiguration implements EntryPoint {
enableIOS6castFix();
}
- // Prepare VConsole for debugging
+ // Prepare the debugging window
if (isDebugMode()) {
- Console console = GWT.create(Console.class);
- console.setQuietMode(isQuietDebugMode());
- console.init();
- VConsole.setImplementation(console);
- } else {
- VConsole.setImplementation((Console) GWT.create(NullConsole.class));
- }
- /*
- * Display some sort of error of exceptions in web mode to debug
- * console. After this, exceptions are reported to VConsole and possible
- * GWT hosted mode.
- */
- GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+ /*
+ * XXX Lots of implementation details here right now. This should be
+ * cleared up when an API for extending the debug window is
+ * implemented.
+ */
+ VDebugWindow window = GWT.create(VDebugWindow.class);
- @Override
- public void onUncaughtException(Throwable e) {
- /*
- * Note in case of null console (without ?debug) we eat
- * exceptions. "a1 is not an object" style errors helps nobody,
- * especially end user. It does not work tells just as much.
- */
- VConsole.getImplementation().error(e);
+ if (LogConfiguration.loggingIsEnabled()) {
+ window.addSection((Section) GWT.create(LogSection.class));
}
- });
+ window.addSection((Section) GWT.create(HierarchySection.class));
+ window.addSection((Section) GWT.create(NetworkSection.class));
+
+ if (isQuietDebugMode()) {
+ window.close();
+ } else {
+ window.init();
+ }
+
+ // Connect to the legacy API
+ VConsole.setImplementation(window);
+
+ Handler errorNotificationHandler = GWT
+ .create(ErrorNotificationHandler.class);
+ Logger.getLogger("").addHandler(errorNotificationHandler);
+ }
+
+ if (LogConfiguration.loggingIsEnabled()) {
+ GWT.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
+
+ @Override
+ public void onUncaughtException(Throwable e) {
+ /*
+ * If the debug window is not enabled (?debug), this will
+ * not show anything to normal users. "a1 is not an object"
+ * style errors helps nobody, especially end user. It does
+ * not work tells just as much.
+ */
+ getLogger().log(Level.SEVERE, e.getMessage(), e);
+ }
+ });
+ }
Profiler.leave("ApplicationConfiguration.onModuleLoad");
if (SuperDevMode.enableBasedOnParameter()) {
@@ -679,4 +715,8 @@ public class ApplicationConfiguration implements EntryPoint {
widgetsetVersionSent = true;
}
+ private static final Logger getLogger() {
+ return Logger.getLogger(ApplicationConfiguration.class.getName());
+ }
+
}
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 4ddbd7c39b..4141f9f2dc 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -27,6 +27,9 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
+import com.google.gwt.aria.client.LiveValue;
+import com.google.gwt.aria.client.RelevantValue;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Duration;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
@@ -66,6 +69,7 @@ import com.vaadin.client.communication.HasJavaScriptConnectorHelper;
import com.vaadin.client.communication.JavaScriptMethodInvocation;
import com.vaadin.client.communication.JsonDecoder;
import com.vaadin.client.communication.JsonEncoder;
+import com.vaadin.client.communication.PushConnection;
import com.vaadin.client.communication.RpcManager;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.extensions.AbstractExtensionConnector;
@@ -80,6 +84,7 @@ import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.client.ui.VContextMenu;
import com.vaadin.client.ui.VNotification;
import com.vaadin.client.ui.VNotification.HideEvent;
+import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.ui.dd.VDragAndDropManager;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.client.ui.window.WindowConnector;
@@ -94,7 +99,7 @@ import com.vaadin.shared.ui.ui.UIConstants;
/**
* This is the client side communication "engine", managing client-server
* communication with its server side counterpart
- * com.vaadin.server.AbstractCommunicationManager.
+ * com.vaadin.server.VaadinService.
*
* Client-side connectors receive updates from the corresponding server-side
* connector (typically component) as state updates or RPC calls. The connector
@@ -155,8 +160,8 @@ public class ApplicationConnection {
*/
public static final String UIDL_REFRESH_TOKEN = "Vaadin-Refresh";
- // will hold the UIDL security key (for XSS protection) once received
- private String uidlSecurityKey = "init";
+ // will hold the CSRF token once received
+ private String csrfToken = "init";
private final HashMap<String, String> resourcesMap = new HashMap<String, String>();
@@ -177,11 +182,6 @@ public class ApplicationConnection {
private VContextMenu contextMenu = null;
- private Timer loadTimer;
- private Timer loadTimer2;
- private Timer loadTimer3;
- private Element loadElement;
-
private final UIConnector uIConnector;
protected boolean applicationRunning = false;
@@ -227,6 +227,8 @@ public class ApplicationConnection {
private final RpcManager rpcManager;
+ private PushConnection push;
+
/**
* If responseHandlingLocks contains any objects, response handling is
* suspended until the collection is empty or a timeout has occurred.
@@ -378,6 +380,8 @@ public class ApplicationConnection {
private CommunicationErrorHandler communicationErrorDelegate = null;
+ private VLoadingIndicator loadingIndicator;
+
public static class MultiStepDuration extends Duration {
private int previousStep = elapsedMillis();
@@ -404,6 +408,8 @@ public class ApplicationConnection {
layoutManager = GWT.create(LayoutManager.class);
layoutManager.setConnection(this);
tooltip = GWT.create(VTooltip.class);
+ loadingIndicator = GWT.create(VLoadingIndicator.class);
+ loadingIndicator.setConnection(this);
}
public void init(WidgetSet widgetSet, ApplicationConfiguration cnf) {
@@ -436,7 +442,7 @@ public class ApplicationConnection {
tooltip.setOwner(uIConnector.getWidget());
- showLoadingIndicator();
+ getLoadingIndicator().show();
scheduleHeartbeat();
@@ -454,6 +460,15 @@ public class ApplicationConnection {
webkitMaybeIgnoringRequests = true;
}
});
+
+ // Ensure the overlay container is added to the dom and set as a live
+ // area for assistive devices
+ Element overlayContainer = VOverlay.getOverlayContainer(this);
+ Roles.getAlertRole().setAriaLiveProperty(overlayContainer,
+ LiveValue.ASSERTIVE);
+ setOverlayContainerLabel(getUIConnector().getState().overlayContainerLabel);
+ Roles.getAlertRole().setAriaRelevantProperty(overlayContainer,
+ RelevantValue.ADDITIONS);
}
/**
@@ -656,8 +671,7 @@ public class ApplicationConnection {
}-*/;
protected void repaintAll() {
- String repainAllParameters = getRepaintAllParameters();
- makeUidlRequest("", repainAllParameters, false);
+ makeUidlRequest("", getRepaintAllParameters());
}
/**
@@ -667,7 +681,7 @@ public class ApplicationConnection {
public void analyzeLayouts() {
String params = getRepaintAllParameters() + "&"
+ ApplicationConstants.PARAM_ANALYZE_LAYOUTS + "=1";
- makeUidlRequest("", params, false);
+ makeUidlRequest("", params);
}
/**
@@ -681,7 +695,7 @@ public class ApplicationConnection {
String params = getRepaintAllParameters() + "&"
+ ApplicationConstants.PARAM_HIGHLIGHT_CONNECTOR + "="
+ serverConnector.getConnectorId();
- makeUidlRequest("", params, false);
+ makeUidlRequest("", params);
}
/**
@@ -694,14 +708,12 @@ public class ApplicationConnection {
* Contains key=value pairs joined by & characters or is empty if
* no parameters should be added. Should not start with any
* special character.
- * @param forceSync
- * true if the request should be synchronous, false otherwise
*/
protected void makeUidlRequest(final String requestData,
- final String extraParams, final boolean forceSync) {
+ final String extraParams) {
startRequest();
// Security: double cookie submission pattern
- final String payload = uidlSecurityKey + VAR_BURST_SEPARATOR
+ final String payload = getCsrfToken() + VAR_BURST_SEPARATOR
+ requestData;
VConsole.log("Making UIDL Request with params: " + payload);
String uri = translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX
@@ -713,7 +725,7 @@ public class ApplicationConnection {
uri = addGetParameters(uri, UIConstants.UI_ID_PARAMETER + "="
+ configuration.getUIId());
- doUidlRequest(uri, payload, forceSync);
+ doUidlRequest(uri, payload);
}
@@ -725,143 +737,127 @@ public class ApplicationConnection {
* The URI to use for the request. May includes GET parameters
* @param payload
* The contents of the request to send
- * @param synchronous
- * true if the request should be synchronous, false otherwise
*/
- protected void doUidlRequest(final String uri, final String payload,
- final boolean synchronous) {
- if (!synchronous) {
- RequestCallback requestCallback = new RequestCallback() {
- @Override
- public void onError(Request request, Throwable exception) {
- handleCommunicationError(exception.getMessage(), -1);
- }
+ protected void doUidlRequest(final String uri, final String payload) {
+ RequestCallback requestCallback = new RequestCallback() {
+ @Override
+ public void onError(Request request, Throwable exception) {
+ handleCommunicationError(exception.getMessage(), -1);
+ }
- private void handleCommunicationError(String details,
- int statusCode) {
- if (!handleErrorInDelegate(details, statusCode)) {
- showCommunicationError(details, statusCode);
- }
- endRequest();
+ private void handleCommunicationError(String details, int statusCode) {
+ if (!handleErrorInDelegate(details, statusCode)) {
+ showCommunicationError(details, statusCode);
}
+ endRequest();
+ }
- @Override
- public void onResponseReceived(Request request,
- Response response) {
- VConsole.log("Server visit took "
- + String.valueOf((new Date()).getTime()
- - requestStartTime.getTime()) + "ms");
-
- int statusCode = response.getStatusCode();
-
- switch (statusCode) {
- case 0:
- if (retryCanceledActiveRequest) {
- /*
- * Request was most likely canceled because the
- * browser is maybe navigating away from the page.
- * Just send the request again without displaying
- * any error in case the navigation isn't carried
- * through.
- */
- retryCanceledActiveRequest = false;
- doUidlRequest(uri, payload, synchronous);
- } else {
- handleCommunicationError(
- "Invalid status code 0 (server down?)",
- statusCode);
- }
- return;
+ @Override
+ public void onResponseReceived(Request request, Response response) {
+ VConsole.log("Server visit took "
+ + String.valueOf((new Date()).getTime()
+ - requestStartTime.getTime()) + "ms");
- case 401:
- /*
- * Authorization has failed. Could be that the session
- * has timed out and the container is redirecting to a
- * login page.
- */
- showAuthenticationError("");
- endRequest();
- return;
+ int statusCode = response.getStatusCode();
- case 503:
+ switch (statusCode) {
+ case 0:
+ if (retryCanceledActiveRequest) {
/*
- * We'll assume msec instead of the usual seconds. If
- * there's no Retry-After header, handle the error like
- * a 500, as per RFC 2616 section 10.5.4.
+ * Request was most likely canceled because the browser
+ * is maybe navigating away from the page. Just send the
+ * request again without displaying any error in case
+ * the navigation isn't carried through.
*/
- String delay = response.getHeader("Retry-After");
- if (delay != null) {
- VConsole.log("503, retrying in " + delay + "msec");
- (new Timer() {
- @Override
- public void run() {
- doUidlRequest(uri, payload, synchronous);
- }
- }).schedule(Integer.parseInt(delay));
- return;
- }
+ retryCanceledActiveRequest = false;
+ doUidlRequest(uri, payload);
+ } else {
+ handleCommunicationError(
+ "Invalid status code 0 (server down?)",
+ statusCode);
}
+ return;
- if ((statusCode / 100) == 4) {
- // Handle all 4xx errors the same way as (they are
- // all permanent errors)
- showCommunicationError(
- "UIDL could not be read from server. Check servlets mappings. Error code: "
- + statusCode, statusCode);
- endRequest();
- return;
- } else if ((statusCode / 100) == 5) {
- // Something's wrong on the server, there's nothing the
- // client can do except maybe try again.
- handleCommunicationError("Server error. Error code: "
- + statusCode, statusCode);
+ case 401:
+ /*
+ * Authorization has failed. Could be that the session has
+ * timed out and the container is redirecting to a login
+ * page.
+ */
+ showAuthenticationError("");
+ endRequest();
+ return;
+
+ case 503:
+ /*
+ * We'll assume msec instead of the usual seconds. If
+ * there's no Retry-After header, handle the error like a
+ * 500, as per RFC 2616 section 10.5.4.
+ */
+ String delay = response.getHeader("Retry-After");
+ if (delay != null) {
+ VConsole.log("503, retrying in " + delay + "msec");
+ (new Timer() {
+ @Override
+ public void run() {
+ doUidlRequest(uri, payload);
+ }
+ }).schedule(Integer.parseInt(delay));
return;
}
+ }
- String contentType = response.getHeader("Content-Type");
- if (contentType == null
- || !contentType.startsWith("application/json")) {
- /*
- * A servlet filter or equivalent may have intercepted
- * the request and served non-UIDL content (for
- * instance, a login page if the session has expired.)
- * If the response contains a magic substring, do a
- * synchronous refresh. See #8241.
- */
- MatchResult refreshToken = RegExp.compile(
- UIDL_REFRESH_TOKEN + "(:\\s*(.*?))?(\\s|$)")
- .exec(response.getText());
- if (refreshToken != null) {
- redirect(refreshToken.getGroup(2));
- return;
- }
- }
+ if ((statusCode / 100) == 4) {
+ // Handle all 4xx errors the same way as (they are
+ // all permanent errors)
+ showCommunicationError(
+ "UIDL could not be read from server. Check servlets mappings. Error code: "
+ + statusCode, statusCode);
+ endRequest();
+ return;
+ } else if ((statusCode / 100) == 5) {
+ // Something's wrong on the server, there's nothing the
+ // client can do except maybe try again.
+ handleCommunicationError("Server error. Error code: "
+ + statusCode, statusCode);
+ return;
+ }
- // for(;;);[realjson]
- final String jsonText = response.getText().substring(9,
- response.getText().length() - 1);
- handleJSONText(jsonText, statusCode);
+ String contentType = response.getHeader("Content-Type");
+ if (contentType == null
+ || !contentType.startsWith("application/json")) {
+ /*
+ * A servlet filter or equivalent may have intercepted the
+ * request and served non-UIDL content (for instance, a
+ * login page if the session has expired.) If the response
+ * contains a magic substring, do a synchronous refresh. See
+ * #8241.
+ */
+ MatchResult refreshToken = RegExp.compile(
+ UIDL_REFRESH_TOKEN + "(:\\s*(.*?))?(\\s|$)").exec(
+ response.getText());
+ if (refreshToken != null) {
+ redirect(refreshToken.getGroup(2));
+ return;
+ }
}
- };
+ // for(;;);[realjson]
+ final String jsonText = response.getText().substring(9,
+ response.getText().length() - 1);
+ handleJSONText(jsonText, statusCode);
+ }
+ };
+ if (push != null) {
+ push.push(payload);
+ } else {
try {
- doAsyncUIDLRequest(uri, payload, requestCallback);
+ doAjaxRequest(uri, payload, requestCallback);
} catch (RequestException e) {
VConsole.error(e);
endRequest();
}
- } else {
- // Synchronized call, discarded response (leaving the page)
- SynchronousXHR syncXHR = (SynchronousXHR) SynchronousXHR.create();
- syncXHR.synchronousPost(uri + "&"
- + ApplicationConstants.PARAM_UNLOADBURST + "=1", payload);
- /*
- * Although we are in theory leaving the page, the page may still
- * stay open. End request properly here too. See #3289
- */
- endRequest();
}
-
}
/**
@@ -905,11 +901,12 @@ public class ApplicationConnection {
* @throws RequestException
* if the request could not be sent
*/
- protected void doAsyncUIDLRequest(String uri, String payload,
+ protected void doAjaxRequest(String uri, String payload,
RequestCallback requestCallback) throws RequestException {
RequestBuilder rb = new RequestBuilder(RequestBuilder.POST, uri);
// TODO enable timeout
// rb.setTimeoutMillis(timeoutMillis);
+ // TODO this should be configurable
rb.setHeader("Content-Type", "text/plain;charset=utf-8");
rb.setRequestData(payload);
rb.setCallback(requestCallback);
@@ -1008,7 +1005,7 @@ public class ApplicationConnection {
*/
protected boolean isCSSLoaded() {
return cssLoaded
- || DOM.getElementPropertyInt(loadElement, "offsetHeight") != 0;
+ || getLoadingIndicator().getElement().getOffsetHeight() != 0;
}
/**
@@ -1042,7 +1039,7 @@ public class ApplicationConnection {
* @param details
* Optional details for debugging.
*/
- protected void showSessionExpiredError(String details) {
+ public void showSessionExpiredError(String details) {
VConsole.error("Session expired: " + details);
showError(details, configuration.getSessionExpiredError());
}
@@ -1106,25 +1103,7 @@ public class ApplicationConnection {
}
hasActiveRequest = true;
requestStartTime = new Date();
- // show initial throbber
- if (loadTimer == null) {
- loadTimer = new Timer() {
- @Override
- public void run() {
- /*
- * IE7 does not properly cancel the event with
- * loadTimer.cancel() so we have to check that we really
- * should make it visible
- */
- if (loadTimer != null) {
- showLoadingIndicator();
- }
-
- }
- };
- // First one kicks in at 300ms
- }
- loadTimer.schedule(300);
+ loadingIndicator.trigger();
eventBus.fireEvent(new RequestStartingEvent(this));
}
@@ -1145,12 +1124,13 @@ public class ApplicationConnection {
checkForPendingVariableBursts();
runPostRequestHooks(configuration.getRootPanelId());
}
+
// deferring to avoid flickering
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
if (!hasActiveRequest()) {
- hideLoadingIndicator();
+ getLoadingIndicator().hide();
// If on Liferay and session expiration management is in
// use, extend session duration on each request.
@@ -1179,7 +1159,7 @@ public class ApplicationConnection {
}
LinkedHashMap<String, MethodInvocation> nextBurst = pendingBursts
.remove(0);
- buildAndSendVariableBurst(nextBurst, false);
+ buildAndSendVariableBurst(nextBurst);
}
}
@@ -1203,54 +1183,6 @@ public class ApplicationConnection {
}
}
- private void showLoadingIndicator() {
- // show initial throbber
- if (loadElement == null) {
- loadElement = DOM.createDiv();
- DOM.setStyleAttribute(loadElement, "position", "absolute");
- DOM.appendChild(uIConnector.getWidget().getElement(), loadElement);
- VConsole.log("inserting load indicator");
- }
- DOM.setElementProperty(loadElement, "className", "v-loading-indicator");
- DOM.setStyleAttribute(loadElement, "display", "block");
- // Initialize other timers
- loadTimer2 = new Timer() {
- @Override
- public void run() {
- DOM.setElementProperty(loadElement, "className",
- "v-loading-indicator-delay");
- }
- };
- // Second one kicks in at 1500ms from request start
- loadTimer2.schedule(1200);
-
- loadTimer3 = new Timer() {
- @Override
- public void run() {
- DOM.setElementProperty(loadElement, "className",
- "v-loading-indicator-wait");
- }
- };
- // Third one kicks in at 5000ms from request start
- loadTimer3.schedule(4700);
- }
-
- private void hideLoadingIndicator() {
- if (loadTimer != null) {
- loadTimer.cancel();
- loadTimer = null;
- }
- if (loadTimer2 != null) {
- loadTimer2.cancel();
- loadTimer3.cancel();
- loadTimer2 = null;
- loadTimer3 = null;
- }
- if (loadElement != null) {
- DOM.setStyleAttribute(loadElement, "display", "none");
- }
- }
-
/**
* Checks if deferred commands are (potentially) still being executed as a
* result of an update from the server. Returns true if a deferred command
@@ -1273,19 +1205,24 @@ public class ApplicationConnection {
}
/**
+ * Returns the loading indicator used by this ApplicationConnection
+ *
+ * @return The loading indicator for this ApplicationConnection
+ */
+ public VLoadingIndicator getLoadingIndicator() {
+ return loadingIndicator;
+ }
+
+ /**
* Determines whether or not the loading indicator is showing.
*
* @return true if the loading indicator is visible
+ * @deprecated As of 7.1. Use {@link #getLoadingIndicator()} and
+ * {@link VLoadingIndicator#isVisible()}.isVisible() instead.
*/
+ @Deprecated
public boolean isLoadingIndicatorVisible() {
- if (loadElement == null) {
- return false;
- }
- if (loadElement.getStyle().getProperty("display").equals("none")) {
- return false;
- }
-
- return true;
+ return getLoadingIndicator().isVisible();
}
private static native ValueMap parseJSONResponse(String jsonText)
@@ -1332,6 +1269,14 @@ public class ApplicationConnection {
return;
}
+ /*
+ * Lock response handling to avoid a situation where something pushed
+ * from the server gets processed while waiting for e.g. lazily loaded
+ * connectors that are needed for processing the current message.
+ */
+ final Object lock = new Object();
+ suspendReponseHandling(lock);
+
VConsole.log("Handling message from server");
eventBus.fireEvent(new ResponseHandlingStartedEvent(this));
@@ -1349,7 +1294,7 @@ public class ApplicationConnection {
// Get security key
if (json.containsKey(ApplicationConstants.UIDL_SECURITY_TOKEN_ID)) {
- uidlSecurityKey = json
+ csrfToken = json
.getString(ApplicationConstants.UIDL_SECURITY_TOKEN_ID);
}
VConsole.log(" * Handling resources from server");
@@ -1545,7 +1490,12 @@ public class ApplicationConnection {
+ jsonText.length() + " characters of JSON");
VConsole.log("Referenced paintables: " + connectorMap.size());
- endRequest();
+ if (meta == null || !meta.containsKey("async")) {
+ // End the request if the received message was a response,
+ // not sent asynchronously
+ endRequest();
+ }
+ resumeResponseHandling(lock);
if (Profiler.isEnabled()) {
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@@ -1556,7 +1506,6 @@ public class ApplicationConnection {
}
});
}
-
}
/**
@@ -2417,6 +2366,23 @@ public class ApplicationConnection {
}
/**
+ * Removes any pending invocation of the given method from the queue
+ *
+ * @param invocation
+ * The invocation to remove
+ */
+ public void removePendingInvocations(MethodInvocation invocation) {
+ Iterator<MethodInvocation> iter = pendingInvocations.values()
+ .iterator();
+ while (iter.hasNext()) {
+ MethodInvocation mi = iter.next();
+ if (mi.equals(invocation)) {
+ iter.remove();
+ }
+ }
+ }
+
+ /**
* This method sends currently queued variable changes to server. It is
* called when immediate variable update must happen.
*
@@ -2429,7 +2395,7 @@ public class ApplicationConnection {
public void sendPendingVariableChanges() {
if (!deferedSendPending) {
deferedSendPending = true;
- Scheduler.get().scheduleDeferred(sendPendingCommand);
+ Scheduler.get().scheduleFinally(sendPendingCommand);
}
}
@@ -2444,7 +2410,7 @@ public class ApplicationConnection {
private void doSendPendingVariableChanges() {
if (applicationRunning) {
- if (hasActiveRequest()) {
+ if (hasActiveRequest() || (push != null && !push.isActive())) {
// skip empty queues if there are pending bursts to be sent
if (pendingInvocations.size() > 0 || pendingBursts.size() == 0) {
pendingBursts.add(pendingInvocations);
@@ -2453,7 +2419,7 @@ public class ApplicationConnection {
lastInvocationTag = 0;
}
} else {
- buildAndSendVariableBurst(pendingInvocations, false);
+ buildAndSendVariableBurst(pendingInvocations);
}
}
}
@@ -2467,12 +2433,9 @@ public class ApplicationConnection {
*
* @param pendingInvocations
* List of RPC method invocations to send
- * @param forceSync
- * Should we use synchronous request?
*/
private void buildAndSendVariableBurst(
- LinkedHashMap<String, MethodInvocation> pendingInvocations,
- boolean forceSync) {
+ LinkedHashMap<String, MethodInvocation> pendingInvocations) {
final StringBuffer req = new StringBuffer();
while (!pendingInvocations.isEmpty()) {
@@ -2526,12 +2489,6 @@ public class ApplicationConnection {
pendingInvocations.clear();
// Keep tag string short
lastInvocationTag = 0;
- // Append all the bursts to this synchronous request
- if (forceSync && !pendingBursts.isEmpty()) {
- pendingInvocations = pendingBursts.get(0);
- pendingBursts.remove(0);
- req.append(VAR_BURST_SEPARATOR);
- }
}
// Include the browser detail parameters if they aren't already sent
@@ -2552,7 +2509,7 @@ public class ApplicationConnection {
getConfiguration().setWidgetsetVersionSent();
}
- makeUidlRequest(req.toString(), extraParams, forceSync);
+ makeUidlRequest(req.toString(), extraParams);
}
private boolean isJavascriptRpc(MethodInvocation invocation) {
@@ -3056,7 +3013,17 @@ public class ApplicationConnection {
private ConnectorMap connectorMap = GWT.create(ConnectorMap.class);
protected String getUidlSecurityKey() {
- return uidlSecurityKey;
+ return getCsrfToken();
+ }
+
+ /**
+ * Gets the token (aka double submit cookie) that the server uses to protect
+ * against Cross Site Request Forgery attacks.
+ *
+ * @return the CSRF token string
+ */
+ public String getCsrfToken() {
+ return csrfToken;
}
/**
@@ -3309,6 +3276,14 @@ public class ApplicationConnection {
Timer forceHandleMessage = new Timer() {
@Override
public void run() {
+ if (responseHandlingLocks.isEmpty()) {
+ /*
+ * Timer fired but there's nothing to clear. This can happen
+ * with IE8 as Timer.cancel is not always effective (see GWT
+ * issue 8101).
+ */
+ return;
+ }
VConsole.log("WARNING: reponse handling was never resumed, forcibly removing locks...");
responseHandlingLocks.clear();
handlePendingMessages();
@@ -3333,9 +3308,13 @@ public class ApplicationConnection {
public void resumeResponseHandling(Object lock) {
responseHandlingLocks.remove(lock);
if (responseHandlingLocks.isEmpty()) {
- VConsole.log("No more response handling locks, handling pending requests.");
+ // Cancel timer that breaks the lock
forceHandleMessage.cancel();
- handlePendingMessages();
+
+ if (!pendingUIDLMessages.isEmpty()) {
+ VConsole.log("No more response handling locks, handling pending requests.");
+ handlePendingMessages();
+ }
}
}
@@ -3344,11 +3323,19 @@ public class ApplicationConnection {
* suspended.
*/
private void handlePendingMessages() {
- for (PendingUIDLMessage pending : pendingUIDLMessages) {
- handleUIDLMessage(pending.getStart(), pending.getJsonText(),
- pending.getJson());
+ if (!pendingUIDLMessages.isEmpty()) {
+ /*
+ * Clear the list before processing enqueued messages to support
+ * reentrancy
+ */
+ List<PendingUIDLMessage> pendingMessages = pendingUIDLMessages;
+ pendingUIDLMessages = new ArrayList<PendingUIDLMessage>();
+
+ for (PendingUIDLMessage pending : pendingMessages) {
+ handleReceivedJSONMessage(pending.getStart(),
+ pending.getJsonText(), pending.getJson());
+ }
}
- pendingUIDLMessages.clear();
}
private boolean handleErrorInDelegate(String details, int statusCode) {
@@ -3406,4 +3393,58 @@ public class ApplicationConnection {
return Util.getConnectorForElement(this, getUIConnector().getWidget(),
focusedElement);
}
+
+ /**
+ * Sets the status for the push connection.
+ *
+ * @param enabled
+ * <code>true</code> to enable the push connection;
+ * <code>false</code> to disable the push connection.
+ */
+ public void setPushEnabled(boolean enabled) {
+ if (enabled && push == null) {
+ push = GWT.create(PushConnection.class);
+ push.init(this);
+ } else if (!enabled && push != null && push.isActive()) {
+ push.disconnect(new Command() {
+ @Override
+ public void execute() {
+ push = null;
+ /*
+ * If push has been enabled again while we were waiting for
+ * the old connection to disconnect, now is the right time
+ * to open a new connection
+ */
+ if (uIConnector.getState().pushMode.isEnabled()) {
+ setPushEnabled(true);
+ }
+
+ /*
+ * Send anything that was enqueued while we waited for the
+ * connection to close
+ */
+ if (pendingInvocations.size() > 0) {
+ sendPendingVariableChanges();
+ }
+ }
+ });
+ }
+ }
+
+ public void handlePushMessage(String message) {
+ handleJSONText(message, 200);
+ }
+
+ /**
+ * Set the label of the container element, where tooltip, notification and
+ * dialgs are added to.
+ *
+ * @param overlayContainerLabel
+ * label for the container
+ */
+ public void setOverlayContainerLabel(String overlayContainerLabel) {
+ Roles.getAlertRole().setAriaLabelProperty(
+ VOverlay.getOverlayContainer(this),
+ getUIConnector().getState().overlayContainerLabel);
+ }
}
diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java
index f0a4ccde0a..73f3a68193 100644
--- a/client/src/com/vaadin/client/BrowserInfo.java
+++ b/client/src/com/vaadin/client/BrowserInfo.java
@@ -85,6 +85,8 @@ public class BrowserInfo {
if (browserDetails.isChrome()) {
touchDevice = detectChromeTouchDevice();
+ } else if (browserDetails.isIE()) {
+ touchDevice = detectIETouchDevice();
} else {
touchDevice = detectTouchDevice();
}
@@ -100,6 +102,11 @@ public class BrowserInfo {
return ("ontouchstart" in window);
}-*/;
+ private native boolean detectIETouchDevice()
+ /*-{
+ return !!navigator.msMaxTouchPoints;
+ }-*/;
+
private native int getIEDocumentMode()
/*-{
var mode = $wnd.document.documentMode;
@@ -331,7 +338,8 @@ public class BrowserInfo {
* otherwise <code>false</code>
*/
public boolean requiresOverflowAutoFix() {
- return (getWebkitVersion() > 0 || getOperaVersion() >= 11 || isFirefox())
+ return (getWebkitVersion() > 0 || getOperaVersion() >= 11
+ || getIEVersion() >= 10 || isFirefox())
&& Util.getNativeScrollbarSize() > 0;
}
diff --git a/client/src/com/vaadin/client/ComponentConnector.java b/client/src/com/vaadin/client/ComponentConnector.java
index eecc3fda0c..f923a9dade 100644
--- a/client/src/com/vaadin/client/ComponentConnector.java
+++ b/client/src/com/vaadin/client/ComponentConnector.java
@@ -119,6 +119,11 @@ public interface ComponentConnector extends ServerConnector {
/**
* Gets the tooltip info for the given element.
+ * <p>
+ * When overriding this method, {@link #hasTooltip()} should also be
+ * overridden to return <code>true</code> in all situations where this
+ * method might return a non-empty result.
+ * </p>
*
* @param element
* The element to lookup a tooltip for
@@ -128,6 +133,20 @@ public interface ComponentConnector extends ServerConnector {
public TooltipInfo getTooltipInfo(Element element);
/**
+ * Check whether there might be a tooltip for this component. The framework
+ * will only add event listeners for automatically handling tooltips (using
+ * {@link #getTooltipInfo(Element)}) if this method returns true.
+ * <p>
+ * This is only done to optimize performance, so in cases where the status
+ * is not known, it's safer to return <code>true</code> so that there will
+ * be a tooltip handler even though it might not be needed in all cases.
+ *
+ * @return <code>true</code> if some part of the component might have a
+ * tooltip, otherwise <code>false</code>
+ */
+ public boolean hasTooltip();
+
+ /**
* Called for the active (focused) connector when a situation occurs that
* the focused connector might have buffered changes which need to be
* processed before other activity takes place.
diff --git a/client/src/com/vaadin/client/ComponentLocator.java b/client/src/com/vaadin/client/ComponentLocator.java
index 05603e8abe..af934470c2 100644
--- a/client/src/com/vaadin/client/ComponentLocator.java
+++ b/client/src/com/vaadin/client/ComponentLocator.java
@@ -28,6 +28,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ui.SubPartAware;
import com.vaadin.client.ui.VCssLayout;
import com.vaadin.client.ui.VGridLayout;
+import com.vaadin.client.ui.VOverlay;
import com.vaadin.client.ui.VTabsheetPanel;
import com.vaadin.client.ui.VUI;
import com.vaadin.client.ui.VWindow;
@@ -446,7 +447,10 @@ public class ComponentLocator {
return null;
}
String elementId = w.getElement().getId();
- if (elementId != null && !elementId.isEmpty()) {
+ if (elementId != null && !elementId.isEmpty()
+ && !elementId.startsWith("gwt-uid-")) {
+ // Use PID_S+id if the user has set an id but do not use it for auto
+ // generated id:s as these might not be consistent
return "PID_S" + elementId;
} else if (w instanceof VUI) {
return "";
@@ -575,7 +579,12 @@ public class ComponentLocator {
// is always 0 which indicates the widget in the active tab
widgetPosition = 0;
}
-
+ if (w instanceof VOverlay
+ && "VCalendarPanel".equals(widgetClassName)) {
+ // Vaadin 7.1 adds a wrapper for datefield popups
+ parent = (Iterable<?>) ((Iterable) parent).iterator()
+ .next();
+ }
/*
* The new grid and ordered layotus do not contain
* ChildComponentContainer widgets. This is instead simulated by
diff --git a/client/src/com/vaadin/client/ConnectorHierarchyChangeEvent.java b/client/src/com/vaadin/client/ConnectorHierarchyChangeEvent.java
index 56ae7c44ac..2896386933 100644
--- a/client/src/com/vaadin/client/ConnectorHierarchyChangeEvent.java
+++ b/client/src/com/vaadin/client/ConnectorHierarchyChangeEvent.java
@@ -67,19 +67,17 @@ public class ConnectorHierarchyChangeEvent extends
}
/**
- * Returns the {@link HasComponentsConnector} for which this event
- * occurred.
+ * Returns the {@link HasComponentsConnector} for which this event occurred.
*
- * @return The {@link HasComponentsConnector} whose child collection
- * has changed. Never returns null.
+ * @return The {@link HasComponentsConnector} whose child collection has
+ * changed. Never returns null.
*/
public HasComponentsConnector getParent() {
return parent;
}
/**
- * Sets the {@link HasComponentsConnector} for which this event
- * occurred.
+ * Sets the {@link HasComponentsConnector} for which this event occurred.
*
* @param The
* {@link HasComponentsConnector} whose child collection has
diff --git a/client/src/com/vaadin/client/Console.java b/client/src/com/vaadin/client/Console.java
deleted file mode 100644
index aa8ef2adc5..0000000000
--- a/client/src/com/vaadin/client/Console.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.client;
-
-import java.util.Set;
-
-public interface Console {
-
- public abstract void log(String msg);
-
- public abstract void log(Throwable e);
-
- public abstract void error(Throwable e);
-
- public abstract void error(String msg);
-
- public abstract void printObject(Object msg);
-
- public abstract void dirUIDL(ValueMap u, ApplicationConnection client);
-
- public abstract void printLayoutProblems(ValueMap meta,
- ApplicationConnection applicationConnection,
- Set<ComponentConnector> zeroHeightComponents,
- Set<ComponentConnector> zeroWidthComponents);
-
- public abstract void setQuietMode(boolean quietDebugMode);
-
- public abstract void init();
-
-} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/HasComponentsConnector.java b/client/src/com/vaadin/client/HasComponentsConnector.java
index 0a1a7be97b..ebc6dbcd2a 100644
--- a/client/src/com/vaadin/client/HasComponentsConnector.java
+++ b/client/src/com/vaadin/client/HasComponentsConnector.java
@@ -21,6 +21,7 @@ import java.util.List;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.HasWidgets;
import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
+import com.vaadin.ui.HasComponents;
/**
* An interface used by client-side connectors whose widget is a component
diff --git a/client/src/com/vaadin/client/NullConsole.java b/client/src/com/vaadin/client/NullConsole.java
deleted file mode 100644
index 2b70454b9d..0000000000
--- a/client/src/com/vaadin/client/NullConsole.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.client;
-
-import java.util.Set;
-
-import com.google.gwt.core.client.GWT;
-
-/**
- * Client side console implementation for non-debug mode that discards all
- * messages.
- *
- */
-public class NullConsole implements Console {
-
- @Override
- public void dirUIDL(ValueMap u, ApplicationConnection conn) {
- }
-
- @Override
- public void error(String msg) {
- GWT.log(msg);
- }
-
- @Override
- public void log(String msg) {
- GWT.log(msg);
- }
-
- @Override
- public void printObject(Object msg) {
- GWT.log(msg.toString());
- }
-
- @Override
- public void printLayoutProblems(ValueMap meta,
- ApplicationConnection applicationConnection,
- Set<ComponentConnector> zeroHeightComponents,
- Set<ComponentConnector> zeroWidthComponents) {
- }
-
- @Override
- public void log(Throwable e) {
- GWT.log(e.getMessage(), e);
- }
-
- @Override
- public void error(Throwable e) {
- GWT.log(e.getMessage(), e);
- }
-
- @Override
- public void setQuietMode(boolean quietDebugMode) {
- }
-
- @Override
- public void init() {
- }
-
-}
diff --git a/client/src/com/vaadin/client/Profiler.java b/client/src/com/vaadin/client/Profiler.java
index 6e8f2f5f9a..95b3232723 100644
--- a/client/src/com/vaadin/client/Profiler.java
+++ b/client/src/com/vaadin/client/Profiler.java
@@ -387,17 +387,12 @@ public class Profiler {
StringBuilder stringBuilder = new StringBuilder();
rootNode.buildRecursiveString(stringBuilder, "");
- Console implementation = VConsole.getImplementation();
- if (implementation instanceof VDebugConsole) {
- VDebugConsole console = (VDebugConsole) implementation;
- SimpleTree tree = (SimpleTree) stack.getFirst().buildTree();
- tree.setText("Profiler data");
-
- console.showTree(tree, stringBuilder.toString());
- } else {
- VConsole.log(stringBuilder.toString());
- }
+ /*
+ * Should really output to a separate section in the debug window, but
+ * just dump it to the log for now.
+ */
+ VConsole.log(stringBuilder.toString());
Map<String, Node> totals = new HashMap<String, Node>();
rootNode.sumUpTotals(totals);
@@ -482,13 +477,11 @@ public class Profiler {
return;
}
- Console implementation = VConsole.getImplementation();
- if (implementation instanceof VDebugConsole) {
- VDebugConsole console = (VDebugConsole) implementation;
- console.showTree(tree, stringBuilder.toString());
- } else {
- VConsole.log(stringBuilder.toString());
- }
+ /*
+ * Should really output to a separate section in the debug window,
+ * but just dump it to the log for now.
+ */
+ VConsole.log(stringBuilder.toString());
}
}
diff --git a/client/src/com/vaadin/client/SimpleTree.java b/client/src/com/vaadin/client/SimpleTree.java
index d4aef4e4f7..23bdc4828f 100644
--- a/client/src/com/vaadin/client/SimpleTree.java
+++ b/client/src/com/vaadin/client/SimpleTree.java
@@ -25,16 +25,30 @@ import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DoubleClickEvent;
+import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
+import com.google.gwt.event.shared.HandlerManager;
+import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
-public class SimpleTree extends ComplexPanel {
+/**
+ * @author Vaadin Ltd
+ *
+ * @deprecated as of 7.1. This class was mainly used by the old debug console
+ * but is retained for now for backwards compatibility.
+ */
+@Deprecated
+public class SimpleTree extends ComplexPanel implements HasDoubleClickHandlers {
private Element children = Document.get().createDivElement().cast();
private SpanElement handle = Document.get().createSpanElement();
private SpanElement text = Document.get().createSpanElement();
+ private HandlerManager textDoubleClickHandlerManager;
+
public SimpleTree() {
setElement(Document.get().createDivElement());
Style style = getElement().getStyle();
@@ -126,4 +140,24 @@ public class SimpleTree extends ComplexPanel {
getElement().getStyle().setPaddingLeft(3, Unit.PX);
}
+ /**
+ * {@inheritDoc} Events are not fired when double clicking child widgets.
+ */
+ @Override
+ public HandlerRegistration addDoubleClickHandler(DoubleClickHandler handler) {
+ if (textDoubleClickHandlerManager == null) {
+ textDoubleClickHandlerManager = new HandlerManager(this);
+ addDomHandler(new DoubleClickHandler() {
+ @Override
+ public void onDoubleClick(DoubleClickEvent event) {
+ if (event.getNativeEvent().getEventTarget().cast() == text) {
+ textDoubleClickHandlerManager.fireEvent(event);
+ }
+ }
+ }, DoubleClickEvent.getType());
+ }
+ return textDoubleClickHandlerManager.addHandler(
+ DoubleClickEvent.getType(), handler);
+ }
+
}
diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java
index 2cd01b2dd8..8972670232 100644
--- a/client/src/com/vaadin/client/Util.java
+++ b/client/src/com/vaadin/client/Util.java
@@ -48,6 +48,7 @@ import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.ui.ComponentStateUtil;
+import com.vaadin.shared.util.SharedUtil;
public class Util {
@@ -550,12 +551,21 @@ public class Util {
}
}
+ /**
+ * Checks if a and b are equals using {@link #equals(Object)}. Handles null
+ * values as well. Does not ensure that objects are of the same type.
+ * Assumes that the first object's equals method handle equals properly.
+ *
+ * @param a
+ * The first value to compare
+ * @param b
+ * The second value to compare
+ * @return
+ * @deprecated As of 7.1 use {@link SharedUtil#equals(Object)} instead
+ */
+ @Deprecated
public static boolean equals(Object a, Object b) {
- if (a == null) {
- return b == null;
- }
-
- return a.equals(b);
+ return SharedUtil.equals(a, b);
}
public static void updateRelativeChildrenAndSendSizeUpdateEvent(
@@ -630,6 +640,10 @@ public class Util {
/*-{
var cs = element.ownerDocument.defaultView.getComputedStyle(element);
var heightPx = cs.height;
+ if(heightPx == 'auto'){
+ // Fallback for when IE reports auto
+ heightPx = @com.vaadin.client.Util::getRequiredHeightBoundingClientRect(Lcom/google/gwt/dom/client/Element;)(element) + 'px';
+ }
var borderTopPx = cs.borderTop;
var borderBottomPx = cs.borderBottom;
var paddingTopPx = cs.paddingTop;
@@ -646,6 +660,10 @@ public class Util {
/*-{
var cs = element.ownerDocument.defaultView.getComputedStyle(element);
var widthPx = cs.width;
+ if(widthPx == 'auto'){
+ // Fallback for when IE reports auto
+ widthPx = @com.vaadin.client.Util::getRequiredWidthBoundingClientRect(Lcom/google/gwt/dom/client/Element;)(element) + 'px';
+ }
var borderLeftPx = cs.borderLeft;
var borderRightPx = cs.borderRight;
var paddingLeftPx = cs.paddingLeft;
@@ -1339,5 +1357,4 @@ public class Util {
}
}
-
}
diff --git a/client/src/com/vaadin/client/VCaption.java b/client/src/com/vaadin/client/VCaption.java
index 47287636c4..d033c2b4fe 100644
--- a/client/src/com/vaadin/client/VCaption.java
+++ b/client/src/com/vaadin/client/VCaption.java
@@ -16,6 +16,7 @@
package com.vaadin.client;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -23,6 +24,7 @@ import com.google.gwt.user.client.ui.HTML;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.Icon;
+import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.AbstractFieldState;
import com.vaadin.shared.ComponentConstants;
@@ -95,6 +97,24 @@ public class VCaption extends HTML {
setStyleName(CLASSNAME);
}
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+
+ if (null != owner) {
+ AriaHelper.bindCaption(owner.getWidget(), getElement());
+ }
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+
+ if (null != owner) {
+ AriaHelper.bindCaption(owner.getWidget(), null);
+ }
+ }
+
/**
* Updates the caption from UIDL.
*
@@ -200,6 +220,8 @@ public class VCaption extends HTML {
removeStyleDependentName("hasdescription");
}
+ AriaHelper.handleInputRequired(owner.getWidget(), showRequired);
+
if (showRequired) {
if (requiredFieldIndicator == null) {
requiredFieldIndicator = DOM.createDiv();
@@ -209,6 +231,10 @@ public class VCaption extends HTML {
DOM.insertChild(getElement(), requiredFieldIndicator,
getInsertPosition(InsertPosition.REQUIRED));
+
+ // Hide the required indicator from assistive device
+ Roles.getTextboxRole().setAriaHiddenState(
+ requiredFieldIndicator, true);
}
} else if (requiredFieldIndicator != null) {
// Remove existing
@@ -216,6 +242,8 @@ public class VCaption extends HTML {
requiredFieldIndicator = null;
}
+ AriaHelper.handleInputInvalid(owner.getWidget(), showError);
+
if (showError) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createDiv();
@@ -225,6 +253,10 @@ public class VCaption extends HTML {
DOM.insertChild(getElement(), errorIndicatorElement,
getInsertPosition(InsertPosition.ERROR));
+
+ // Hide error indicator from assistive devices
+ Roles.getTextboxRole().setAriaHiddenState(
+ errorIndicatorElement, true);
}
} else if (errorIndicatorElement != null) {
// Remove existing
diff --git a/client/src/com/vaadin/client/VConsole.java b/client/src/com/vaadin/client/VConsole.java
index db19d1a9fd..f7a7554e34 100644
--- a/client/src/com/vaadin/client/VConsole.java
+++ b/client/src/com/vaadin/client/VConsole.java
@@ -16,91 +16,67 @@
package com.vaadin.client;
import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
-import com.google.gwt.core.client.GWT;
+import com.google.gwt.logging.client.LogConfiguration;
+import com.vaadin.client.debug.internal.VDebugWindow;
/**
* A helper class to do some client side logging.
- * <p>
- * This class replaces previously used loggin style:
- * ApplicationConnection.getConsole().log("foo").
- * <p>
- * The default widgetset provides three modes for debugging:
- * <ul>
- * <li>NullConsole (Default, displays no errors at all)
- * <li>VDebugConsole ( Enabled by appending ?debug to url. Displays a floating
- * console in the browser and also prints to browsers internal console (builtin
- * or Firebug) and GWT's development mode console if available.)
- * <li>VDebugConsole in quiet mode (Enabled by appending ?debug=quiet. Same as
- * previous but without the console floating over application).
- * </ul>
- * <p>
- * Implementations can be customized with GWT deferred binding by overriding
- * NullConsole.class or VDebugConsole.class. This way developer can for example
- * build mechanism to send client side logging data to a server.
- * <p>
- * Note that logging in client side is not fully optimized away even in
- * production mode. Use logging moderately in production code to keep the size
- * of client side engine small. An exception is {@link GWT#log(String)} style
- * logging, which is available only in GWT development mode, but optimized away
- * when compiled to web mode.
- *
- *
- * TODO improve javadocs of individual methods
*
+ * @deprecated as of 7.1, use {@link Logger} from java.util.logging instead.
*/
+@Deprecated
public class VConsole {
- private static Console impl;
+ private static VDebugWindow impl;
/**
* Used by ApplicationConfiguration to initialize VConsole.
*
* @param console
*/
- static void setImplementation(Console console) {
+ static void setImplementation(VDebugWindow console) {
impl = console;
}
- /**
- * Used by ApplicationConnection to support deprecated getConsole() api.
- */
- static Console getImplementation() {
- return impl;
- }
-
public static void log(String msg) {
- if (impl != null) {
- impl.log(msg);
+ if (LogConfiguration.loggingIsEnabled(Level.INFO)) {
+ getLogger().log(Level.INFO, msg);
}
}
public static void log(Throwable e) {
- if (impl != null) {
- impl.log(e);
+ if (LogConfiguration.loggingIsEnabled(Level.INFO)) {
+ getLogger().log(Level.INFO, e.getMessage(), e);
}
}
public static void error(Throwable e) {
- if (impl != null) {
- impl.error(e);
+ if (LogConfiguration.loggingIsEnabled(Level.SEVERE)) {
+ getLogger().log(Level.SEVERE, e.getMessage(), e);
}
}
public static void error(String msg) {
- if (impl != null) {
- impl.error(msg);
+ if (LogConfiguration.loggingIsEnabled(Level.SEVERE)) {
+ getLogger().log(Level.SEVERE, msg);
}
}
public static void printObject(Object msg) {
- if (impl != null) {
- impl.printObject(msg);
+ String str;
+ if (msg == null) {
+ str = "null";
+ } else {
+ str = msg.toString();
}
+ log(str);
}
public static void dirUIDL(ValueMap u, ApplicationConnection client) {
if (impl != null) {
- impl.dirUIDL(u, client);
+ impl.uidl(client, u);
}
}
@@ -109,9 +85,12 @@ public class VConsole {
Set<ComponentConnector> zeroHeightComponents,
Set<ComponentConnector> zeroWidthComponents) {
if (impl != null) {
- impl.printLayoutProblems(meta, applicationConnection,
- zeroHeightComponents, zeroWidthComponents);
+ impl.meta(applicationConnection, meta);
}
}
+ private static Logger getLogger() {
+ return Logger.getLogger(VConsole.class.getName());
+ }
+
}
diff --git a/client/src/com/vaadin/client/VDebugConsole.java b/client/src/com/vaadin/client/VDebugConsole.java
deleted file mode 100644
index ee7505876d..0000000000
--- a/client/src/com/vaadin/client/VDebugConsole.java
+++ /dev/null
@@ -1,1041 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.client;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.core.client.JsArray;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.FontWeight;
-import com.google.gwt.dom.client.Style.Overflow;
-import com.google.gwt.dom.client.Style.Position;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.KeyCodes;
-import com.google.gwt.event.dom.client.MouseOutEvent;
-import com.google.gwt.event.dom.client.MouseOutHandler;
-import com.google.gwt.event.logical.shared.ValueChangeEvent;
-import com.google.gwt.event.logical.shared.ValueChangeHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.event.shared.UmbrellaException;
-import com.google.gwt.http.client.Request;
-import com.google.gwt.http.client.RequestBuilder;
-import com.google.gwt.http.client.RequestCallback;
-import com.google.gwt.http.client.RequestException;
-import com.google.gwt.http.client.Response;
-import com.google.gwt.http.client.UrlBuilder;
-import com.google.gwt.i18n.client.DateTimeFormat;
-import com.google.gwt.storage.client.Storage;
-import com.google.gwt.user.client.Cookies;
-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.Event.NativePreviewEvent;
-import com.google.gwt.user.client.Event.NativePreviewHandler;
-import com.google.gwt.user.client.EventPreview;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.Window.Location;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.FlowPanel;
-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.Panel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.client.ui.VLazyExecutor;
-import com.vaadin.client.ui.VNotification;
-import com.vaadin.client.ui.VOverlay;
-import com.vaadin.client.ui.ui.UIConnector;
-import com.vaadin.client.ui.window.WindowConnector;
-import com.vaadin.shared.Version;
-
-/**
- * A helper console for client side development. The debug console can also be
- * used to resolve layout issues, inspect the communication between browser and
- * the server, start GWT dev mode and restart application.
- *
- * <p>
- * This implementation is used vaadin is in debug mode (see manual) and
- * developer appends "?debug" query parameter to url. Debug information can also
- * be shown on browsers internal console only, by appending "?debug=quiet" query
- * parameter.
- * <p>
- * This implementation can be overridden with GWT deferred binding.
- *
- */
-public class VDebugConsole extends VOverlay implements Console {
-
- private final class HighlightModeHandler implements NativePreviewHandler {
- private final Label label;
-
- private HighlightModeHandler(Label label) {
- this.label = label;
- }
-
- @Override
- public void onPreviewNativeEvent(NativePreviewEvent event) {
- if (event.getTypeInt() == Event.ONKEYDOWN
- && event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
- highlightModeRegistration.removeHandler();
- VUIDLBrowser.deHiglight();
- return;
- }
- if (event.getTypeInt() == Event.ONMOUSEMOVE) {
- VUIDLBrowser.deHiglight();
- Element eventTarget = Util.getElementFromPoint(event
- .getNativeEvent().getClientX(), event.getNativeEvent()
- .getClientY());
- if (getElement().isOrHasChild(eventTarget)) {
- return;
- }
-
- for (ApplicationConnection a : ApplicationConfiguration
- .getRunningApplications()) {
- ComponentConnector connector = Util.getConnectorForElement(
- a, a.getUIConnector().getWidget(), eventTarget);
- if (connector == null) {
- connector = Util.getConnectorForElement(a,
- RootPanel.get(), eventTarget);
- }
- if (connector != null) {
- String pid = connector.getConnectorId();
- VUIDLBrowser.highlight(connector);
- label.setText("Currently focused :"
- + connector.getClass() + " ID:" + pid);
- event.cancel();
- event.consume();
- event.getNativeEvent().stopPropagation();
- return;
- }
- }
- }
- if (event.getTypeInt() == Event.ONCLICK) {
- VUIDLBrowser.deHiglight();
- event.cancel();
- event.consume();
- event.getNativeEvent().stopPropagation();
- highlightModeRegistration.removeHandler();
- Element eventTarget = Util.getElementFromPoint(event
- .getNativeEvent().getClientX(), event.getNativeEvent()
- .getClientY());
- for (ApplicationConnection a : ApplicationConfiguration
- .getRunningApplications()) {
- ComponentConnector paintable = Util.getConnectorForElement(
- a, a.getUIConnector().getWidget(), eventTarget);
- if (paintable == null) {
- paintable = Util.getConnectorForElement(a,
- RootPanel.get(), eventTarget);
- }
-
- if (paintable != null) {
- a.highlightConnector(paintable);
- return;
- }
- }
- }
- event.cancel();
- }
- }
-
- private static final String POS_COOKIE_NAME = "VDebugConsolePos";
-
- private HandlerRegistration highlightModeRegistration;
-
- Element caption = DOM.createDiv();
-
- private Panel panel;
-
- private Button clear = new Button("C");
- private Button restart = new Button("R");
- private Button forceLayout = new Button("FL");
- private Button analyzeLayout = new Button("AL");
- private Button savePosition = new Button("S");
- private Button highlight = new Button("H");
- private Button connectorStats = new Button("CS");
- private CheckBox devMode = new CheckBox("Dev");
- private CheckBox superDevMode = new CheckBox("SDev");
- private CheckBox autoScroll = new CheckBox("Autoscroll ");
- private HorizontalPanel actions;
- private boolean collapsed = false;
-
- private boolean resizing;
- private int startX;
- private int startY;
- private int initialW;
- private int initialH;
-
- private boolean moving = false;
-
- private int origTop;
-
- private int origLeft;
-
- private static final String help = "Drag title=move, shift-drag=resize, doubleclick title=min/max."
- + "Use debug=quiet to log only to browser console.";
-
- private static final int DEFAULT_WIDTH = 650;
- private static final int DEFAULT_HEIGHT = 400;
-
- public VDebugConsole() {
- super(false, false);
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
- clear.setTitle("Clear console");
- restart.setTitle("Restart app");
- forceLayout.setTitle("Force layout");
- analyzeLayout.setTitle("Analyze layouts");
- savePosition.setTitle("Save pos");
- }
-
- private EventPreview dragpreview = new EventPreview() {
-
- @Override
- public boolean onEventPreview(Event event) {
- onBrowserEvent(event);
- return false;
- }
- };
-
- private boolean quietMode;
-
- @Override
- public void onBrowserEvent(Event event) {
- super.onBrowserEvent(event);
- switch (DOM.eventGetType(event)) {
- case Event.ONMOUSEDOWN:
- if (DOM.eventGetShiftKey(event)) {
- resizing = true;
- DOM.setCapture(getElement());
- startX = DOM.eventGetScreenX(event);
- startY = DOM.eventGetScreenY(event);
- initialW = VDebugConsole.this.getOffsetWidth();
- initialH = VDebugConsole.this.getOffsetHeight();
- DOM.eventCancelBubble(event, true);
- DOM.eventPreventDefault(event);
- DOM.addEventPreview(dragpreview);
- } else if (DOM.eventGetTarget(event) == caption) {
- moving = true;
- startX = DOM.eventGetScreenX(event);
- startY = DOM.eventGetScreenY(event);
- origTop = getAbsoluteTop();
- origLeft = getAbsoluteLeft();
- DOM.eventCancelBubble(event, true);
- DOM.eventPreventDefault(event);
- DOM.addEventPreview(dragpreview);
- }
-
- break;
- case Event.ONMOUSEMOVE:
- if (resizing) {
- int deltaX = startX - DOM.eventGetScreenX(event);
- int detalY = startY - DOM.eventGetScreenY(event);
- int w = initialW - deltaX;
- if (w < 30) {
- w = 30;
- }
- int h = initialH - detalY;
- if (h < 40) {
- h = 40;
- }
- VDebugConsole.this.setPixelSize(w, h);
- DOM.eventCancelBubble(event, true);
- DOM.eventPreventDefault(event);
- } else if (moving) {
- int deltaX = startX - DOM.eventGetScreenX(event);
- int detalY = startY - DOM.eventGetScreenY(event);
- int left = origLeft - deltaX;
- if (left < 0) {
- left = 0;
- }
- int top = origTop - detalY;
- if (top < 0) {
- top = 0;
- }
- VDebugConsole.this.setPopupPosition(left, top);
- DOM.eventCancelBubble(event, true);
- DOM.eventPreventDefault(event);
- }
- break;
- case Event.ONLOSECAPTURE:
- case Event.ONMOUSEUP:
- if (resizing) {
- DOM.releaseCapture(getElement());
- resizing = false;
- } else if (moving) {
- DOM.releaseCapture(getElement());
- moving = false;
- }
- DOM.removeEventPreview(dragpreview);
- break;
- case Event.ONDBLCLICK:
- if (DOM.eventGetTarget(event) == caption) {
- if (collapsed) {
- panel.setVisible(true);
- setToDefaultSizeAndPos();
- } else {
- panel.setVisible(false);
- setPixelSize(120, 20);
- setPopupPosition(Window.getClientWidth() - 125,
- Window.getClientHeight() - 25);
- }
- collapsed = !collapsed;
- }
- break;
- default:
- break;
- }
-
- }
-
- private void setToDefaultSizeAndPos() {
- String cookie = Cookies.getCookie(POS_COOKIE_NAME);
- int width, height, top, left;
- boolean autoScrollValue = false;
- if (cookie != null) {
- String[] split = cookie.split(",");
- left = Integer.parseInt(split[0]);
- top = Integer.parseInt(split[1]);
- width = Integer.parseInt(split[2]);
- height = Integer.parseInt(split[3]);
- autoScrollValue = Boolean.valueOf(split[4]);
- } else {
- int windowHeight = Window.getClientHeight();
- int windowWidth = Window.getClientWidth();
- width = DEFAULT_WIDTH;
- height = DEFAULT_HEIGHT;
-
- if (height > windowHeight / 2) {
- height = windowHeight / 2;
- }
- if (width > windowWidth / 2) {
- width = windowWidth / 2;
- }
-
- top = windowHeight - (height + 10);
- left = windowWidth - (width + 10);
- }
- setPixelSize(width, height);
- setPopupPosition(left, top);
- autoScroll.setValue(autoScrollValue);
- }
-
- @Override
- public void setPixelSize(int width, int height) {
- if (height < 20) {
- height = 20;
- }
- if (width < 2) {
- width = 2;
- }
- panel.setHeight((height - 20) + "px");
- panel.setWidth((width - 2) + "px");
- getElement().getStyle().setWidth(width, Unit.PX);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.client.Console#log(java.lang.String)
- */
- @Override
- public void log(String msg) {
- if (msg == null) {
- msg = "null";
- }
- msg = addTimestamp(msg);
- // remoteLog(msg);
-
- logToDebugWindow(msg, false);
- GWT.log(msg);
- consoleLog(msg);
- System.out.println(msg);
- }
-
- private List<String> msgQueue = new LinkedList<String>();
-
- private ScheduledCommand doSend = new ScheduledCommand() {
- @Override
- public void execute() {
- if (!msgQueue.isEmpty()) {
- RequestBuilder requestBuilder = new RequestBuilder(
- RequestBuilder.POST, getRemoteLogUrl());
- try {
- String requestData = "";
- for (String str : msgQueue) {
- requestData += str;
- requestData += "\n";
- }
- requestBuilder.sendRequest(requestData,
- new RequestCallback() {
-
- @Override
- public void onResponseReceived(Request request,
- Response response) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void onError(Request request,
- Throwable exception) {
- // TODO Auto-generated method stub
-
- }
- });
- } catch (RequestException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- msgQueue.clear();
- }
- }
-
- };
- private VLazyExecutor sendToRemoteLog = new VLazyExecutor(350, doSend);
-
- protected String getRemoteLogUrl() {
- return "http://sun-vehje.local:8080/remotelog/";
- }
-
- protected void remoteLog(String msg) {
- msgQueue.add(msg);
- sendToRemoteLog.trigger();
- }
-
- /**
- * Logs the given message to the debug window.
- *
- * @param msg
- * The message to log. Must not be null.
- */
- private void logToDebugWindow(String msg, boolean error) {
- Widget row;
- if (error) {
- row = createErrorHtml(msg);
- } else {
- row = new HTML(msg);
- }
- panel.add(row);
- if (autoScroll.getValue()) {
- row.getElement().scrollIntoView();
- }
- }
-
- private HTML createErrorHtml(String msg) {
- HTML html = new HTML(msg);
- html.getElement().getStyle().setColor("#f00");
- html.getElement().getStyle().setFontWeight(FontWeight.BOLD);
- return html;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.client.Console#error(java.lang.String)
- */
- @Override
- public void error(String msg) {
- if (msg == null) {
- msg = "null";
- }
- msg = addTimestamp(msg);
- logToDebugWindow(msg, true);
-
- GWT.log(msg);
- consoleErr(msg);
- System.out.println(msg);
-
- }
-
- DateTimeFormat timestampFormat = DateTimeFormat.getFormat("HH:mm:ss:SSS");
-
- @SuppressWarnings("deprecation")
- private String addTimestamp(String msg) {
- Date date = new Date();
- String timestamp = timestampFormat.format(date);
- return timestamp + " " + msg;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.client.Console#printObject(java.lang. Object)
- */
- @Override
- public void printObject(Object msg) {
- String str;
- if (msg == null) {
- str = "null";
- } else {
- str = msg.toString();
- }
- panel.add((new Label(str)));
- consoleLog(str);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see com.vaadin.client.Console#dirUIDL(com.vaadin.client.UIDL)
- */
- @Override
- public void dirUIDL(ValueMap u, ApplicationConnection client) {
- if (panel.isAttached()) {
- VUIDLBrowser vuidlBrowser = new VUIDLBrowser(u, client);
- vuidlBrowser.setText("Response:");
- panel.add(vuidlBrowser);
- }
- consoleDir(u);
- // consoleLog(u.getChildrenAsXML());
- }
-
- /**
- * Adds a {@link SimpleTree} to the console and prints a string
- * representation of the tree structure to the text console.
- *
- * @param tree
- * the simple tree to display in the console window
- * @param stringRepresentation
- * the string representation of the tree to output to the text
- * console
- */
- public void showTree(SimpleTree tree, String stringRepresentation) {
- if (panel.isAttached()) {
- panel.add(tree);
- }
- consoleLog(stringRepresentation);
- }
-
- private static native void consoleDir(ValueMap u)
- /*-{
- if($wnd.console && $wnd.console.log) {
- if($wnd.console.dir) {
- $wnd.console.dir(u);
- } else {
- $wnd.console.log(u);
- }
- }
-
- }-*/;
-
- private static native void consoleLog(String msg)
- /*-{
- if($wnd.console && $wnd.console.log) {
- $wnd.console.log(msg);
- }
- }-*/;
-
- private static native void consoleErr(String msg)
- /*-{
- if($wnd.console) {
- if ($wnd.console.error)
- $wnd.console.error(msg);
- else if ($wnd.console.log)
- $wnd.console.log(msg);
- }
- }-*/;
-
- @Override
- public void printLayoutProblems(ValueMap meta, ApplicationConnection ac,
- Set<ComponentConnector> zeroHeightComponents,
- Set<ComponentConnector> zeroWidthComponents) {
- JsArray<ValueMap> valueMapArray = meta
- .getJSValueMapArray("invalidLayouts");
- int size = valueMapArray.length();
- panel.add(new HTML("<div>************************</di>"
- + "<h4>Layouts analyzed on server, total top level problems: "
- + size + " </h4>"));
- if (size > 0) {
- SimpleTree root = new SimpleTree("Root problems");
-
- for (int i = 0; i < size; i++) {
- printLayoutError(valueMapArray.get(i), root, ac);
- }
- panel.add(root);
-
- }
- if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
- panel.add(new HTML("<h4> Client side notifications</h4>"
- + " <em>The following relative sized components were "
- + "rendered to a zero size container on the client side."
- + " Note that these are not necessarily invalid "
- + "states, but reported here as they might be.</em>"));
- if (zeroHeightComponents.size() > 0) {
- panel.add(new HTML(
- "<p><strong>Vertically zero size:</strong><p>"));
- printClientSideDetectedIssues(zeroHeightComponents, ac);
- }
- if (zeroWidthComponents.size() > 0) {
- panel.add(new HTML(
- "<p><strong>Horizontally zero size:</strong><p>"));
- printClientSideDetectedIssues(zeroWidthComponents, ac);
- }
- }
- log("************************");
- }
-
- private void printClientSideDetectedIssues(
- Set<ComponentConnector> zeroHeightComponents,
- ApplicationConnection ac) {
- for (final ComponentConnector paintable : zeroHeightComponents) {
- final ServerConnector parent = paintable.getParent();
-
- VerticalPanel errorDetails = new VerticalPanel();
- errorDetails.add(new Label("" + Util.getSimpleName(paintable)
- + " inside " + Util.getSimpleName(parent)));
- if (parent instanceof ComponentConnector) {
- ComponentConnector parentComponent = (ComponentConnector) parent;
- final Widget layout = parentComponent.getWidget();
-
- final CheckBox emphasisInUi = new CheckBox(
- "Emphasize components parent in UI (the actual component is not visible)");
- emphasisInUi.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- Element element2 = layout.getElement();
- Widget.setStyleName(element2, "invalidlayout",
- emphasisInUi.getValue().booleanValue());
- }
- });
-
- errorDetails.add(emphasisInUi);
- }
- panel.add(errorDetails);
- }
- }
-
- private void printLayoutError(ValueMap valueMap, SimpleTree root,
- final ApplicationConnection ac) {
- final String pid = valueMap.getString("id");
- final ComponentConnector paintable = (ComponentConnector) ConnectorMap
- .get(ac).getConnector(pid);
-
- SimpleTree errorNode = new SimpleTree();
- VerticalPanel errorDetails = new VerticalPanel();
- errorDetails.add(new Label(Util.getSimpleName(paintable) + " id: "
- + pid));
- if (valueMap.containsKey("heightMsg")) {
- errorDetails.add(new Label("Height problem: "
- + valueMap.getString("heightMsg")));
- }
- if (valueMap.containsKey("widthMsg")) {
- errorDetails.add(new Label("Width problem: "
- + valueMap.getString("widthMsg")));
- }
- final CheckBox emphasisInUi = new CheckBox("Emphasize component in UI");
- emphasisInUi.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- if (paintable != null) {
- Element element2 = paintable.getWidget().getElement();
- Widget.setStyleName(element2, "invalidlayout",
- emphasisInUi.getValue());
- }
- }
- });
- errorDetails.add(emphasisInUi);
- errorNode.add(errorDetails);
- if (valueMap.containsKey("subErrors")) {
- HTML l = new HTML(
- "<em>Expand this node to show problems that may be dependent on this problem.</em>");
- errorDetails.add(l);
- JsArray<ValueMap> suberrors = valueMap
- .getJSValueMapArray("subErrors");
- for (int i = 0; i < suberrors.length(); i++) {
- ValueMap value = suberrors.get(i);
- printLayoutError(value, errorNode, ac);
- }
-
- }
- root.add(errorNode);
- }
-
- @Override
- public void log(Throwable e) {
- if (e instanceof UmbrellaException) {
- UmbrellaException ue = (UmbrellaException) e;
- for (Throwable t : ue.getCauses()) {
- log(t);
- }
- return;
- }
- log(Util.getSimpleName(e) + ": " + e.getMessage());
- GWT.log(e.getMessage(), e);
- }
-
- @Override
- public void error(Throwable e) {
- handleError(e, this);
- }
-
- static void handleError(Throwable e, Console target) {
- if (e instanceof UmbrellaException) {
- UmbrellaException ue = (UmbrellaException) e;
- for (Throwable t : ue.getCauses()) {
- target.error(t);
- }
- return;
- }
- String exceptionText = Util.getSimpleName(e);
- String message = e.getMessage();
- if (message != null && message.length() != 0) {
- exceptionText += ": " + e.getMessage();
- }
- target.error(exceptionText);
- GWT.log(e.getMessage(), e);
- if (!GWT.isProdMode()) {
- e.printStackTrace();
- }
- try {
- Widget owner = null;
-
- if (!ApplicationConfiguration.getRunningApplications().isEmpty()) {
- // Make a wild guess and use the first available
- // ApplicationConnection. This is better than than leaving the
- // exception completely unstyled...
- ApplicationConnection connection = ApplicationConfiguration
- .getRunningApplications().get(0);
- owner = connection.getUIConnector().getWidget();
- }
- VNotification
- .createNotification(VNotification.DELAY_FOREVER, owner)
- .show("<h1>Uncaught client side exception</h1><br />"
- + exceptionText, VNotification.CENTERED, "error");
- } catch (Exception e2) {
- // Just swallow this exception
- }
- }
-
- @Override
- public void init() {
- panel = new FlowPanel();
- if (!quietMode) {
- DOM.appendChild(getContainerElement(), caption);
- setWidget(panel);
- caption.setClassName("v-debug-console-caption");
- setStyleName("v-debug-console");
- getElement().getStyle().setZIndex(20000);
- getElement().getStyle().setOverflow(Overflow.HIDDEN);
-
- sinkEvents(Event.ONDBLCLICK);
-
- sinkEvents(Event.MOUSEEVENTS);
-
- panel.setStyleName("v-debug-console-content");
-
- caption.setInnerHTML("Debug window");
- caption.getStyle().setHeight(25, Unit.PX);
- caption.setTitle(help);
-
- show();
- setToDefaultSizeAndPos();
-
- actions = new HorizontalPanel();
- Style style = actions.getElement().getStyle();
- style.setPosition(Position.ABSOLUTE);
- style.setBackgroundColor("#666");
- style.setLeft(135, Unit.PX);
- style.setHeight(25, Unit.PX);
- style.setTop(0, Unit.PX);
-
- actions.add(clear);
- actions.add(restart);
- actions.add(forceLayout);
- actions.add(analyzeLayout);
- actions.add(highlight);
- actions.add(connectorStats);
- connectorStats.setTitle("Show connector statistics for client");
- highlight
- .setTitle("Select a component and print details about it to the server log and client side console.");
- actions.add(savePosition);
- savePosition
- .setTitle("Saves the position and size of debug console to a cookie");
- actions.add(autoScroll);
- addDevMode();
- addSuperDevMode();
-
- autoScroll
- .setTitle("Automatically scroll so that new messages are visible");
-
- panel.add(actions);
-
- panel.add(new HTML("<i>" + help + "</i>"));
-
- clear.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- int width = panel.getOffsetWidth();
- int height = panel.getOffsetHeight();
- panel = new FlowPanel();
- panel.setPixelSize(width, height);
- panel.setStyleName("v-debug-console-content");
- panel.add(actions);
- setWidget(panel);
- }
- });
-
- restart.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
-
- String queryString = Window.Location.getQueryString();
- if (queryString != null
- && queryString.contains("restartApplications")) {
- Window.Location.reload();
- } else {
- String url = Location.getHref();
- String separator = "?";
- if (url.contains("?")) {
- separator = "&";
- }
- if (!url.contains("restartApplication")) {
- url += separator;
- url += "restartApplication";
- }
- if (!"".equals(Location.getHash())) {
- String hash = Location.getHash();
- url = url.replace(hash, "") + hash;
- }
- Window.Location.replace(url);
- }
-
- }
- });
-
- forceLayout.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- for (ApplicationConnection applicationConnection : ApplicationConfiguration
- .getRunningApplications()) {
- applicationConnection.forceLayout();
- }
- }
- });
-
- analyzeLayout.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- List<ApplicationConnection> runningApplications = ApplicationConfiguration
- .getRunningApplications();
- for (ApplicationConnection applicationConnection : runningApplications) {
- applicationConnection.analyzeLayouts();
- }
- }
- });
- analyzeLayout
- .setTitle("Analyzes currently rendered view and "
- + "reports possible common problems in usage of relative sizes."
- + "Will cause server visit/rendering of whole screen and loss of"
- + " all non committed variables form client side.");
-
- savePosition.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- String pos = getAbsoluteLeft() + "," + getAbsoluteTop()
- + "," + getOffsetWidth() + "," + getOffsetHeight()
- + "," + autoScroll.getValue();
- Cookies.setCookie(POS_COOKIE_NAME, pos);
- }
- });
-
- highlight.addClickHandler(new ClickHandler() {
-
- @Override
- public void onClick(ClickEvent event) {
- final Label label = new Label("--");
- log("<i>Use mouse to select a component or click ESC to exit highlight mode.</i>");
- panel.add(label);
- highlightModeRegistration = Event
- .addNativePreviewHandler(new HighlightModeHandler(
- label));
-
- }
- });
-
- }
- connectorStats.addClickHandler(new ClickHandler() {
-
- @Override
- public void onClick(ClickEvent event) {
- for (ApplicationConnection a : ApplicationConfiguration
- .getRunningApplications()) {
- dumpConnectorInfo(a);
- }
- }
- });
- log("Starting Vaadin client side engine. Widgetset: "
- + GWT.getModuleName());
-
- log("Widget set is built on version: " + Version.getFullVersion());
-
- logToDebugWindow("<div class=\"v-theme-version v-theme-version-"
- + Version.getFullVersion().replaceAll("\\.", "_")
- + "\">Warning: widgetset version " + Version.getFullVersion()
- + " does not seem to match theme version </div>", true);
-
- }
-
- private void addSuperDevMode() {
- final Storage sessionStorage = Storage.getSessionStorageIfSupported();
- if (sessionStorage == null) {
- return;
- }
- actions.add(superDevMode);
- if (Location.getParameter("superdevmode") != null) {
- superDevMode.setValue(true);
- }
- superDevMode.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
-
- @Override
- public void onValueChange(ValueChangeEvent<Boolean> event) {
- SuperDevMode.redirect(event.getValue());
- }
-
- });
-
- }
-
- private void addDevMode() {
- actions.add(devMode);
- if (Location.getParameter("gwt.codesvr") != null) {
- devMode.setValue(true);
- }
- devMode.addClickHandler(new ClickHandler() {
- @Override
- public void onClick(ClickEvent event) {
- if (devMode.getValue()) {
- addHMParameter();
- } else {
- removeHMParameter();
- }
- }
-
- private void addHMParameter() {
- UrlBuilder createUrlBuilder = Location.createUrlBuilder();
- createUrlBuilder.setParameter("gwt.codesvr", "localhost:9997");
- Location.assign(createUrlBuilder.buildString());
- }
-
- private void removeHMParameter() {
- UrlBuilder createUrlBuilder = Location.createUrlBuilder();
- createUrlBuilder.removeParameter("gwt.codesvr");
- Location.assign(createUrlBuilder.buildString());
-
- }
- });
- }
-
- protected void dumpConnectorInfo(ApplicationConnection a) {
- UIConnector root = a.getUIConnector();
- log("================");
- log("Connector hierarchy for Root: " + root.getState().caption + " ("
- + root.getConnectorId() + ")");
- Set<ServerConnector> connectorsInHierarchy = new HashSet<ServerConnector>();
- SimpleTree rootHierachy = dumpConnectorHierarchy(root, "",
- connectorsInHierarchy);
- if (panel.isAttached()) {
- rootHierachy.open(true);
- panel.add(rootHierachy);
- }
-
- ConnectorMap connectorMap = a.getConnectorMap();
- Collection<? extends ServerConnector> registeredConnectors = connectorMap
- .getConnectors();
- log("Sub windows:");
- Set<ServerConnector> subWindowHierarchyConnectors = new HashSet<ServerConnector>();
- for (WindowConnector wc : root.getSubWindows()) {
- SimpleTree windowHierachy = dumpConnectorHierarchy(wc, "",
- subWindowHierarchyConnectors);
- if (panel.isAttached()) {
- windowHierachy.open(true);
- panel.add(windowHierachy);
- }
- }
- log("Registered connectors not in hierarchy (should be empty):");
- for (ServerConnector registeredConnector : registeredConnectors) {
-
- if (connectorsInHierarchy.contains(registeredConnector)) {
- continue;
- }
-
- if (subWindowHierarchyConnectors.contains(registeredConnector)) {
- continue;
- }
- error(getConnectorString(registeredConnector));
-
- }
- log("Unregistered connectors in hierarchy (should be empty):");
- for (ServerConnector hierarchyConnector : connectorsInHierarchy) {
- if (!connectorMap.hasConnector(hierarchyConnector.getConnectorId())) {
- error(getConnectorString(hierarchyConnector));
- }
-
- }
-
- log("================");
-
- }
-
- private SimpleTree dumpConnectorHierarchy(final ServerConnector connector,
- String indent, Set<ServerConnector> connectors) {
- SimpleTree simpleTree = new SimpleTree(getConnectorString(connector)) {
- @Override
- protected void select(ClickEvent event) {
- super.select(event);
- if (connector instanceof ComponentConnector) {
- VUIDLBrowser.highlight((ComponentConnector) connector);
- }
- }
- };
- simpleTree.addDomHandler(new MouseOutHandler() {
- @Override
- public void onMouseOut(MouseOutEvent event) {
- VUIDLBrowser.deHiglight();
- }
- }, MouseOutEvent.getType());
- connectors.add(connector);
-
- String msg = indent + "* " + getConnectorString(connector);
- GWT.log(msg);
- consoleLog(msg);
- System.out.println(msg);
-
- for (ServerConnector c : connector.getChildren()) {
- simpleTree.add(dumpConnectorHierarchy(c, indent + " ", connectors));
- }
- return simpleTree;
- }
-
- private static String getConnectorString(ServerConnector connector) {
- return Util.getConnectorString(connector);
- }
-
- @Override
- public void setQuietMode(boolean quietDebugMode) {
- quietMode = quietDebugMode;
- }
-}
diff --git a/client/src/com/vaadin/client/VErrorMessage.java b/client/src/com/vaadin/client/VErrorMessage.java
index a384b451dd..2e42b98a05 100644
--- a/client/src/com/vaadin/client/VErrorMessage.java
+++ b/client/src/com/vaadin/client/VErrorMessage.java
@@ -31,6 +31,9 @@ public class VErrorMessage extends FlowPanel {
public VErrorMessage() {
super();
setStyleName(CLASSNAME);
+
+ // Needed for binding with WAI-ARIA attributes
+ getElement().setId(DOM.createUniqueId());
}
/**
diff --git a/client/src/com/vaadin/client/VLoadingIndicator.java b/client/src/com/vaadin/client/VLoadingIndicator.java
new file mode 100644
index 0000000000..fcce35781d
--- /dev/null
+++ b/client/src/com/vaadin/client/VLoadingIndicator.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client;
+
+import com.google.gwt.dom.client.Style.Display;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Timer;
+
+/**
+ * Class representing the loading indicator for Vaadin applications. The loading
+ * indicator has four states: "triggered", "first", "second" and "third". When
+ * {@link #trigger()} is called the indicator moves to its "triggered" state and
+ * then transitions from one state to the next when the timeouts specified using
+ * the set*StateDelay methods occur.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class VLoadingIndicator {
+
+ private static final String PRIMARY_STYLE_NAME = "v-loading-indicator";
+
+ private ApplicationConnection connection;
+
+ private int firstDelay = 300;
+ private int secondDelay = 1500;
+ private int thirdDelay = 5000;
+
+ /**
+ * Timer with method for checking if it has been cancelled. This class is a
+ * workaround for a IE8 problem which causes a timer to be fired even if it
+ * has been cancelled.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+ private abstract static class LoadingIndicatorTimer extends Timer {
+ private boolean cancelled = false;
+
+ @Override
+ public void cancel() {
+ super.cancel();
+ cancelled = true;
+ }
+
+ @Override
+ public void schedule(int delayMillis) {
+ super.schedule(delayMillis);
+ cancelled = false;
+ }
+
+ @Override
+ public void scheduleRepeating(int periodMillis) {
+ super.scheduleRepeating(periodMillis);
+ cancelled = false;
+ }
+
+ /**
+ * Checks if this timer has been cancelled.
+ *
+ * @return true if the timer has been cancelled, false otherwise
+ */
+ public boolean isCancelled() {
+ return cancelled;
+ }
+ }
+
+ private Timer firstTimer = new LoadingIndicatorTimer() {
+ @Override
+ public void run() {
+ if (isCancelled()) {
+ // IE8 does not properly cancel the timer in all cases.
+ return;
+ }
+ show();
+ }
+ };
+ private Timer secondTimer = new LoadingIndicatorTimer() {
+ @Override
+ public void run() {
+ if (isCancelled()) {
+ // IE8 does not properly cancel the timer in all cases.
+ return;
+ }
+ getElement().setClassName(PRIMARY_STYLE_NAME);
+ getElement().addClassName("second");
+ // For backwards compatibility only
+ getElement().addClassName(PRIMARY_STYLE_NAME + "-delay");
+ }
+ };
+ private Timer thirdTimer = new LoadingIndicatorTimer() {
+ @Override
+ public void run() {
+ if (isCancelled()) {
+ // IE8 does not properly cancel the timer in all cases.
+ return;
+ }
+ getElement().setClassName(PRIMARY_STYLE_NAME);
+ getElement().addClassName("third");
+ // For backwards compatibility only
+ getElement().addClassName(PRIMARY_STYLE_NAME + "-wait");
+ }
+ };
+
+ private Element element;
+
+ /**
+ * Returns the delay (in ms) which must pass before the loading indicator
+ * moves into the "first" state and is shown to the user
+ *
+ * @return The delay (in ms) until moving into the "first" state. Counted
+ * from when {@link #trigger()} is called.
+ */
+ public int getFirstDelay() {
+ return firstDelay;
+ }
+
+ /**
+ * Sets the delay (in ms) which must pass before the loading indicator moves
+ * into the "first" state and is shown to the user
+ *
+ * @param firstDelay
+ * The delay (in ms) until moving into the "first" state. Counted
+ * from when {@link #trigger()} is called.
+ */
+ public void setFirstDelay(int firstDelay) {
+ this.firstDelay = firstDelay;
+ }
+
+ /**
+ * Returns the delay (in ms) which must pass before the loading indicator
+ * moves to its "second" state.
+ *
+ * @return The delay (in ms) until the loading indicator moves into its
+ * "second" state. Counted from when {@link #trigger()} is called.
+ */
+ public int getSecondDelay() {
+ return secondDelay;
+ }
+
+ /**
+ * Sets the delay (in ms) which must pass before the loading indicator moves
+ * to its "second" state.
+ *
+ * @param secondDelay
+ * The delay (in ms) until the loading indicator moves into its
+ * "second" state. Counted from when {@link #trigger()} is
+ * called.
+ */
+ public void setSecondDelay(int secondDelay) {
+ this.secondDelay = secondDelay;
+ }
+
+ /**
+ * Returns the delay (in ms) which must pass before the loading indicator
+ * moves to its "third" state.
+ *
+ * @return The delay (in ms) until the loading indicator moves into its
+ * "third" state. Counted from when {@link #trigger()} is called.
+ */
+ public int getThirdDelay() {
+ return thirdDelay;
+ }
+
+ /**
+ * Sets the delay (in ms) which must pass before the loading indicator moves
+ * to its "third" state.
+ *
+ * @param thirdDelay
+ * The delay (in ms) from the event until changing the loading
+ * indicator into its "third" state. Counted from when
+ * {@link #trigger()} is called.
+ */
+ public void setThirdDelay(int thirdDelay) {
+ this.thirdDelay = thirdDelay;
+ }
+
+ /**
+ * Triggers displaying of this loading indicator. The loading indicator will
+ * actually be shown by {@link #show()} when the "first" delay (as specified
+ * by {@link #getFirstDelay()}) has passed.
+ * <p>
+ * The loading indicator will be hidden if shown when calling this method.
+ * </p>
+ */
+ public void trigger() {
+ hide();
+ firstTimer.schedule(getFirstDelay());
+ }
+
+ /**
+ * Shows the loading indicator in its standard state and triggers timers for
+ * transitioning into the "second" and "third" states.
+ */
+ public void show() {
+ // Reset possible style name and display mode
+ getElement().setClassName(PRIMARY_STYLE_NAME);
+ getElement().addClassName("first");
+ getElement().getStyle().setDisplay(Display.BLOCK);
+
+ // Schedule the "second" loading indicator
+ int secondTimerDelay = getSecondDelay() - getFirstDelay();
+ if (secondTimerDelay >= 0) {
+ secondTimer.schedule(secondTimerDelay);
+ }
+
+ // Schedule the "third" loading indicator
+ int thirdTimerDelay = getThirdDelay() - getFirstDelay();
+ if (thirdTimerDelay >= 0) {
+ thirdTimer.schedule(thirdTimerDelay);
+ }
+ }
+
+ /**
+ * Returns the {@link ApplicationConnection} which uses this loading
+ * indicator
+ *
+ * @return The ApplicationConnection for this loading indicator
+ */
+ public ApplicationConnection getConnection() {
+ return connection;
+ }
+
+ /**
+ * Sets the {@link ApplicationConnection} which uses this loading indicator.
+ * Only used internally.
+ *
+ * @param connection
+ * The ApplicationConnection for this loading indicator
+ */
+ void setConnection(ApplicationConnection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * Hides the loading indicator (if visible). Cancels any possibly running
+ * timers.
+ */
+ public void hide() {
+ firstTimer.cancel();
+ secondTimer.cancel();
+ thirdTimer.cancel();
+
+ getElement().getStyle().setDisplay(Display.NONE);
+ }
+
+ /**
+ * Returns whether or not the loading indicator is showing.
+ *
+ * @return true if the loading indicator is visible, false otherwise
+ */
+ public boolean isVisible() {
+ if (getElement().getStyle().getDisplay()
+ .equals(Display.NONE.getCssName())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Returns the root element of the loading indicator
+ *
+ * @return The loading indicator DOM element
+ */
+ public Element getElement() {
+ if (element == null) {
+ element = DOM.createDiv();
+ element.getStyle().setPosition(Position.ABSOLUTE);
+ getConnection().getUIConnector().getWidget().getElement()
+ .appendChild(element);
+ }
+ return element;
+ }
+
+}
diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java
index 759b90a8cd..6191821988 100644
--- a/client/src/com/vaadin/client/VTooltip.java
+++ b/client/src/com/vaadin/client/VTooltip.java
@@ -15,8 +15,15 @@
*/
package com.vaadin.client;
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.Roles;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DomEvent;
+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.MouseMoveEvent;
@@ -40,11 +47,6 @@ public class VTooltip extends VOverlay {
public static final int TOOLTIP_EVENTS = Event.ONKEYDOWN
| Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEMOVE
| Event.ONCLICK;
- protected static final int MAX_WIDTH = 500;
- private static final int QUICK_OPEN_TIMEOUT = 1000;
- private static final int CLOSE_TIMEOUT = 300;
- private static final int OPEN_DELAY = 750;
- private static final int QUICK_OPEN_DELAY = 100;
VErrorMessage em = new VErrorMessage();
Element description = DOM.createDiv();
@@ -54,6 +56,16 @@ public class VTooltip extends VOverlay {
// Open next tooltip faster. Disabled after 2 sec of showTooltip-silence.
private boolean justClosed = false;
+ private String uniqueId = DOM.createUniqueId();
+ private Element layoutElement;
+ private int maxWidth;
+
+ // Delays for the tooltip, configurable on the server side
+ private int openDelay;
+ private int quickOpenDelay;
+ private int quickOpenTimeout;
+ private int closeTimeout;
+
/**
* Used to show tooltips; usually used via the singleton in
* {@link ApplicationConnection}. NOTE that #setOwner(Widget)} should be
@@ -68,8 +80,17 @@ public class VTooltip extends VOverlay {
setWidget(layout);
layout.add(em);
DOM.setElementProperty(description, "className", CLASSNAME + "-text");
- DOM.appendChild(layout.getElement(), description);
+
+ layoutElement = layout.getElement();
+ DOM.appendChild(layoutElement, description);
setSinkShadowEvents(true);
+
+ // Used to bind the tooltip to the owner for assistive devices
+ layoutElement.setId(uniqueId);
+
+ description.setId(DOM.createUniqueId());
+ Roles.getTooltipRole().set(layoutElement);
+ Roles.getTooltipRole().setAriaHiddenState(layoutElement, true);
}
/**
@@ -104,8 +125,8 @@ public class VTooltip extends VOverlay {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
- if (offsetWidth > MAX_WIDTH) {
- setWidth(MAX_WIDTH + "px");
+ if (offsetWidth > getMaxWidth()) {
+ setWidth(getMaxWidth() + "px");
// Check new height and width with reflowed content
offsetWidth = getOffsetWidth();
@@ -150,7 +171,7 @@ public class VTooltip extends VOverlay {
// Schedule timer for showing the tooltip according to if it was
// recently closed or not.
- int timeout = justClosed ? QUICK_OPEN_DELAY : OPEN_DELAY;
+ int timeout = justClosed ? getQuickOpenDelay() : getOpenDelay();
showTimer.schedule(timeout);
opening = true;
}
@@ -200,19 +221,31 @@ public class VTooltip extends VOverlay {
// already about to close
return;
}
- closeTimer.schedule(CLOSE_TIMEOUT);
+ closeTimer.schedule(getCloseTimeout());
closing = true;
justClosed = true;
- justClosedTimer.schedule(QUICK_OPEN_TIMEOUT);
+ justClosedTimer.schedule(getQuickOpenTimeout());
+ }
+ @Override
+ public void hide() {
+ super.hide();
+ Roles.getTooltipRole().setAriaHiddenState(layoutElement, true);
+ Roles.getTooltipRole().removeAriaDescribedbyProperty(
+ tooltipEventHandler.currentElement);
}
private int tooltipEventMouseX;
private int tooltipEventMouseY;
- public void updatePosition(Event event) {
- tooltipEventMouseX = DOM.eventGetClientX(event);
- tooltipEventMouseY = DOM.eventGetClientY(event);
+ public void updatePosition(Event event, boolean isFocused) {
+ if (isFocused) {
+ tooltipEventMouseX = -1000;
+ tooltipEventMouseY = -1000;
+ } else {
+ tooltipEventMouseX = DOM.eventGetClientX(event);
+ tooltipEventMouseY = DOM.eventGetClientY(event);
+ }
}
@Override
@@ -246,7 +279,7 @@ public class VTooltip extends VOverlay {
}
private class TooltipEventHandler implements MouseMoveHandler,
- ClickHandler, KeyDownHandler {
+ ClickHandler, KeyDownHandler, FocusHandler, BlurHandler {
/**
* Current element hovered
@@ -254,6 +287,11 @@ public class VTooltip extends VOverlay {
private com.google.gwt.dom.client.Element currentElement = null;
/**
+ * Current element focused
+ */
+ private boolean currentIsFocused;
+
+ /**
* Current tooltip active
*/
private TooltipInfo currentTooltipInfo = null;
@@ -299,6 +337,9 @@ public class VTooltip extends VOverlay {
}
if (connector != null && info != null) {
+ assert connector.hasTooltip() : "getTooltipInfo for "
+ + Util.getConnectorString(connector)
+ + " returned a tooltip even though hasTooltip claims there are no tooltips for the connector.";
currentTooltipInfo = info;
return true;
}
@@ -319,41 +360,77 @@ public class VTooltip extends VOverlay {
@Override
public void onMouseMove(MouseMoveEvent mme) {
- Event event = Event.as(mme.getNativeEvent());
+ handleShowHide(mme, false);
+ }
+
+ @Override
+ public void onClick(ClickEvent event) {
+ handleHideEvent();
+ }
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ handleHideEvent();
+ }
+
+ /**
+ * Displays Tooltip when page is navigated with the keyboard.
+ *
+ * Tooltip is not visible. This makes it possible for assistive devices
+ * to recognize the tooltip.
+ */
+ @Override
+ public void onFocus(FocusEvent fe) {
+ handleShowHide(fe, true);
+ }
+
+ /**
+ * Hides Tooltip when the page is navigated with the keyboard.
+ *
+ * Removes the Tooltip from page to make sure assistive devices don't
+ * recognize it by accident.
+ */
+ @Override
+ public void onBlur(BlurEvent be) {
+ handleHideEvent();
+ }
+
+ private void handleShowHide(DomEvent domEvent, boolean isFocused) {
+ Event event = Event.as(domEvent.getNativeEvent());
com.google.gwt.dom.client.Element element = Element.as(event
.getEventTarget());
// We can ignore move event if it's handled by move or over already
- if (currentElement == element) {
+ if (currentElement == element && currentIsFocused == isFocused) {
return;
}
- currentElement = element;
boolean connectorAndTooltipFound = resolveConnector((com.google.gwt.user.client.Element) element);
if (!connectorAndTooltipFound) {
if (isShowing()) {
handleHideEvent();
+ Roles.getButtonRole()
+ .removeAriaDescribedbyProperty(element);
} else {
currentTooltipInfo = null;
}
} else {
- updatePosition(event);
+ updatePosition(event, isFocused);
+
if (isShowing()) {
replaceCurrentTooltip();
+ Roles.getTooltipRole().removeAriaDescribedbyProperty(
+ currentElement);
} else {
showTooltip();
}
- }
- }
- @Override
- public void onClick(ClickEvent event) {
- handleHideEvent();
- }
+ Roles.getTooltipRole().setAriaDescribedbyProperty(element,
+ Id.of(uniqueId));
+ }
- @Override
- public void onKeyDown(KeyDownEvent event) {
- handleHideEvent();
+ currentIsFocused = isFocused;
+ currentElement = element;
}
}
@@ -370,6 +447,141 @@ public class VTooltip extends VOverlay {
widget.addDomHandler(tooltipEventHandler, MouseMoveEvent.getType());
widget.addDomHandler(tooltipEventHandler, ClickEvent.getType());
widget.addDomHandler(tooltipEventHandler, KeyDownEvent.getType());
+ widget.addDomHandler(tooltipEventHandler, FocusEvent.getType());
+ widget.addDomHandler(tooltipEventHandler, BlurEvent.getType());
Profiler.leave("VTooltip.connectHandlersToWidget");
}
+
+ /**
+ * Returns the unique id of the tooltip element.
+ *
+ * @return String containing the unique id of the tooltip, which always has
+ * a value
+ */
+ public String getUniqueId() {
+ return uniqueId;
+ }
+
+ @Override
+ public void setPopupPositionAndShow(PositionCallback callback) {
+ super.setPopupPositionAndShow(callback);
+
+ Roles.getTooltipRole().setAriaHiddenState(layoutElement, false);
+ }
+
+ /**
+ * Returns the time (in ms) the tooltip should be displayed after an event
+ * that will cause it to be closed (e.g. mouse click outside the component,
+ * key down).
+ *
+ * @return The close timeout (in ms)
+ */
+ public int getCloseTimeout() {
+ return closeTimeout;
+ }
+
+ /**
+ * Sets the time (in ms) the tooltip should be displayed after an event that
+ * will cause it to be closed (e.g. mouse click outside the component, key
+ * down).
+ *
+ * @param closeTimeout
+ * The close timeout (in ms)
+ */
+ public void setCloseTimeout(int closeTimeout) {
+ this.closeTimeout = closeTimeout;
+ }
+
+ /**
+ * Returns the time (in ms) during which {@link #getQuickOpenDelay()} should
+ * be used instead of {@link #getOpenDelay()}. The quick open delay is used
+ * when the tooltip has very recently been shown, is currently hidden but
+ * about to be shown again.
+ *
+ * @return The quick open timeout (in ms)
+ */
+ public int getQuickOpenTimeout() {
+ return quickOpenTimeout;
+ }
+
+ /**
+ * Sets the time (in ms) that determines when {@link #getQuickOpenDelay()}
+ * should be used instead of {@link #getOpenDelay()}. The quick open delay
+ * is used when the tooltip has very recently been shown, is currently
+ * hidden but about to be shown again.
+ *
+ * @param quickOpenTimeout
+ * The quick open timeout (in ms)
+ */
+ public void setQuickOpenTimeout(int quickOpenTimeout) {
+ this.quickOpenTimeout = quickOpenTimeout;
+ }
+
+ /**
+ * Returns the time (in ms) that should elapse before a tooltip will be
+ * shown, in the situation when a tooltip has very recently been shown
+ * (within {@link #getQuickOpenDelay()} ms).
+ *
+ * @return The quick open delay (in ms)
+ */
+ public int getQuickOpenDelay() {
+ return quickOpenDelay;
+ }
+
+ /**
+ * Sets the time (in ms) that should elapse before a tooltip will be shown,
+ * in the situation when a tooltip has very recently been shown (within
+ * {@link #getQuickOpenDelay()} ms).
+ *
+ * @param quickOpenDelay
+ * The quick open delay (in ms)
+ */
+ public void setQuickOpenDelay(int quickOpenDelay) {
+ this.quickOpenDelay = quickOpenDelay;
+ }
+
+ /**
+ * Returns the time (in ms) that should elapse after an event triggering
+ * tooltip showing has occurred (e.g. mouse over) before the tooltip is
+ * shown. If a tooltip has recently been shown, then
+ * {@link #getQuickOpenDelay()} is used instead of this.
+ *
+ * @return The open delay (in ms)
+ */
+ public int getOpenDelay() {
+ return openDelay;
+ }
+
+ /**
+ * Sets the time (in ms) that should elapse after an event triggering
+ * tooltip showing has occurred (e.g. mouse over) before the tooltip is
+ * shown. If a tooltip has recently been shown, then
+ * {@link #getQuickOpenDelay()} is used instead of this.
+ *
+ * @param openDelay
+ * The open delay (in ms)
+ */
+ public void setOpenDelay(int openDelay) {
+ this.openDelay = openDelay;
+ }
+
+ /**
+ * Sets the maximum width of the tooltip popup.
+ *
+ * @param maxWidth
+ * The maximum width the tooltip popup (in pixels)
+ */
+ public void setMaxWidth(int maxWidth) {
+ this.maxWidth = maxWidth;
+ }
+
+ /**
+ * Returns the maximum width of the tooltip popup.
+ *
+ * @return The maximum width the tooltip popup (in pixels)
+ */
+ public int getMaxWidth() {
+ return maxWidth;
+ }
+
}
diff --git a/client/src/com/vaadin/client/VUIDLBrowser.java b/client/src/com/vaadin/client/VUIDLBrowser.java
index fded37ec5c..e6f38fb167 100644
--- a/client/src/com/vaadin/client/VUIDLBrowser.java
+++ b/client/src/com/vaadin/client/VUIDLBrowser.java
@@ -42,8 +42,12 @@ import com.vaadin.client.ui.UnknownComponentConnector;
import com.vaadin.client.ui.VWindow;
/**
- * TODO Rename to something more Vaadin7-ish?
+ * @author Vaadin Ltd
+ *
+ * @deprecated as of 7.1. This class was mainly used by the old debug console
+ * but is retained for now for backwards compatibility.
*/
+@Deprecated
public class VUIDLBrowser extends SimpleTree {
private static final String HELP = "Shift click handle to open recursively. "
+ " Click components to highlight them on client side."
diff --git a/client/src/com/vaadin/client/ValueMap.java b/client/src/com/vaadin/client/ValueMap.java
index 5157bc91f5..4141eaa9d6 100644
--- a/client/src/com/vaadin/client/ValueMap.java
+++ b/client/src/com/vaadin/client/ValueMap.java
@@ -70,12 +70,12 @@ public final class ValueMap extends JavaScriptObject {
return attrs;
}
- native JsArrayString getJSStringArray(String name)
+ public native JsArrayString getJSStringArray(String name)
/*-{
return this[name];
}-*/;
- native JsArray<ValueMap> getJSValueMapArray(String name)
+ public native JsArray<ValueMap> getJSValueMapArray(String name)
/*-{
return this[name];
}-*/;
diff --git a/client/src/com/vaadin/client/communication/AtmospherePushConnection.java b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java
new file mode 100644
index 0000000000..bc7e0b3fd2
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/AtmospherePushConnection.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.communication;
+
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.user.client.Command;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ResourceLoader;
+import com.vaadin.client.ResourceLoader.ResourceLoadEvent;
+import com.vaadin.client.ResourceLoader.ResourceLoadListener;
+import com.vaadin.client.VConsole;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.ui.ui.UIConstants;
+
+/**
+ * The default {@link PushConnection} implementation that uses Atmosphere for
+ * handling the communication channel.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class AtmospherePushConnection implements PushConnection {
+
+ protected enum State {
+ /**
+ * Opening request has been sent, but still waiting for confirmation
+ */
+ CONNECT_PENDING,
+
+ /**
+ * Connection is open and ready to use.
+ */
+ CONNECTED,
+
+ /**
+ * Connection was disconnected while the connection was pending. Wait
+ * for the connection to get established before closing it. No new
+ * messages are accepted, but pending messages will still be delivered.
+ */
+ DISCONNECT_PENDING,
+
+ /**
+ * Connection has been disconnected and should not be used any more.
+ */
+ DISCONNECTED;
+ }
+
+ /**
+ * Represents a message that should be sent as multiple fragments.
+ */
+ protected static class FragmentedMessage {
+
+ // Jetty requires length less than buffer size
+ private int FRAGMENT_LENGTH = ApplicationConstants.WEBSOCKET_BUFFER_SIZE - 1;
+
+ private String message;
+ private int index = 0;
+
+ public FragmentedMessage(String message) {
+ this.message = message;
+ }
+
+ public boolean hasNextFragment() {
+ return index < message.length();
+ }
+
+ public String getNextFragment() {
+ String result;
+ if (index == 0) {
+ String header = "" + message.length()
+ + ApplicationConstants.WEBSOCKET_MESSAGE_DELIMITER;
+ int fragmentLen = FRAGMENT_LENGTH - header.length();
+ result = header + getFragment(0, fragmentLen);
+ index += fragmentLen;
+ } else {
+ result = getFragment(index, index + FRAGMENT_LENGTH);
+ index += FRAGMENT_LENGTH;
+ }
+ return result;
+ }
+
+ private String getFragment(int begin, int end) {
+ return message.substring(begin, Math.min(message.length(), end));
+ }
+ }
+
+ private ApplicationConnection connection;
+
+ private JavaScriptObject socket;
+
+ private ArrayList<String> messageQueue = new ArrayList<String>();
+
+ private State state = State.CONNECT_PENDING;
+
+ private AtmosphereConfiguration config;
+
+ private String uri;
+
+ private String transport;
+
+ /**
+ * Keeps track of the disconnect confirmation command for cases where
+ * pending messages should be pushed before actually disconnecting.
+ */
+ private Command pendingDisconnectCommand;
+
+ public AtmospherePushConnection() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.client.communication.PushConenction#init(com.vaadin.client
+ * .ApplicationConnection)
+ */
+ @Override
+ public void init(final ApplicationConnection connection) {
+ this.connection = connection;
+
+ runWhenAtmosphereLoaded(new Command() {
+ @Override
+ public void execute() {
+ Scheduler.get().scheduleDeferred(new Command() {
+ @Override
+ public void execute() {
+ connect();
+ }
+ });
+ }
+ });
+ }
+
+ private void connect() {
+ String baseUrl = connection
+ .translateVaadinUri(ApplicationConstants.APP_PROTOCOL_PREFIX
+ + ApplicationConstants.PUSH_PATH + '/');
+ String extraParams = UIConstants.UI_ID_PARAMETER + "="
+ + connection.getConfiguration().getUIId();
+ extraParams += "&" + ApplicationConstants.CSRF_TOKEN_PARAMETER + "="
+ + connection.getCsrfToken();
+
+ // uri is needed to identify the right connection when closing
+ uri = ApplicationConnection.addGetParameters(baseUrl, extraParams);
+
+ VConsole.log("Establishing push connection");
+ socket = doConnect(uri, getConfig());
+ }
+
+ @Override
+ public boolean isActive() {
+ switch (state) {
+ case CONNECT_PENDING:
+ case CONNECTED:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.client.communication.PushConenction#push(java.lang.String)
+ */
+ @Override
+ public void push(String message) {
+ switch (state) {
+ case CONNECT_PENDING:
+ assert isActive();
+ VConsole.log("Queuing push message: " + message);
+ messageQueue.add(message);
+ break;
+ case CONNECTED:
+ assert isActive();
+ VConsole.log("Sending push message: " + message);
+
+ if (transport.equals("websocket")) {
+ FragmentedMessage fragmented = new FragmentedMessage(message);
+ while (fragmented.hasNextFragment()) {
+ doPush(socket, fragmented.getNextFragment());
+ }
+ } else {
+ doPush(socket, message);
+ }
+ break;
+ case DISCONNECT_PENDING:
+ case DISCONNECTED:
+ throw new IllegalStateException("Can not push after disconnecting");
+ }
+ }
+
+ protected AtmosphereConfiguration getConfig() {
+ if (config == null) {
+ config = createConfig();
+ }
+ return config;
+ }
+
+ protected void onOpen(AtmosphereResponse response) {
+ transport = response.getTransport();
+
+ VConsole.log("Push connection established using " + transport);
+
+ switch (state) {
+ case CONNECT_PENDING:
+ state = State.CONNECTED;
+ for (String message : messageQueue) {
+ push(message);
+ }
+ messageQueue.clear();
+ break;
+ case DISCONNECT_PENDING:
+ // Set state to connected to make disconnect close the connection
+ state = State.CONNECTED;
+ assert pendingDisconnectCommand != null;
+ disconnect(pendingDisconnectCommand);
+ break;
+ case CONNECTED:
+ // IE likes to open the same connection multiple times, just ignore
+ break;
+ default:
+ throw new IllegalStateException(
+ "Got onOpen event when conncetion state is " + state
+ + ". This should never happen.");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.client.communication.PushConenction#disconnect()
+ */
+ @Override
+ public void disconnect(Command command) {
+ assert command != null;
+
+ switch (state) {
+ case CONNECT_PENDING:
+ // Make the connection callback initiate the disconnection again
+ state = State.DISCONNECT_PENDING;
+ pendingDisconnectCommand = command;
+ break;
+ case CONNECTED:
+ // Normal disconnect
+ VConsole.log("Closing push connection");
+ doDisconnect(uri);
+ state = State.DISCONNECTED;
+ command.execute();
+ break;
+ case DISCONNECT_PENDING:
+ case DISCONNECTED:
+ throw new IllegalStateException("Can not disconnect more than once");
+ }
+ }
+
+ protected void onMessage(AtmosphereResponse response) {
+ String message = response.getResponseBody();
+ if (message.startsWith("for(;;);")) {
+ VConsole.log("Received push message: " + message);
+ // "for(;;);[{json}]" -> "{json}"
+ message = message.substring(9, message.length() - 1);
+ connection.handlePushMessage(message);
+ }
+ }
+
+ /**
+ * Called if the transport mechanism cannot be used and the fallback will be
+ * tried
+ */
+ protected void onTransportFailure() {
+ VConsole.log("Push connection using primary method ("
+ + getConfig().getTransport() + ") failed. Trying with "
+ + getConfig().getFallbackTransport());
+ }
+
+ /**
+ * Called if the push connection fails. Atmosphere will automatically retry
+ * the connection until successful.
+ *
+ */
+ protected void onError() {
+ VConsole.error("Push connection using " + getConfig().getTransport()
+ + " failed!");
+ }
+
+ public static abstract class AbstractJSO extends JavaScriptObject {
+ protected AbstractJSO() {
+
+ }
+
+ protected final native String getStringValue(String key)
+ /*-{
+ return this[key];
+ }-*/;
+
+ protected final native void setStringValue(String key, String value)
+ /*-{
+ this[key] = value;
+ }-*/;
+
+ protected final native int getIntValue(String key)
+ /*-{
+ return this[key];
+ }-*/;
+
+ protected final native void setIntValue(String key, int value)
+ /*-{
+ this[key] = value;
+ }-*/;
+
+ }
+
+ public static class AtmosphereConfiguration extends AbstractJSO {
+
+ protected AtmosphereConfiguration() {
+ super();
+ }
+
+ public final String getTransport() {
+ return getStringValue("transport");
+ }
+
+ public final String getFallbackTransport() {
+ return getStringValue("fallbackTransport");
+ }
+
+ public final void setTransport(String transport) {
+ setStringValue("transport", transport);
+ }
+
+ public final void setFallbackTransport(String fallbackTransport) {
+ setStringValue("fallbackTransport", fallbackTransport);
+ }
+ }
+
+ public static class AtmosphereResponse extends AbstractJSO {
+
+ protected AtmosphereResponse() {
+
+ }
+
+ public final String getResponseBody() {
+ return getStringValue("responseBody");
+ }
+
+ public final String getState() {
+ return getStringValue("state");
+ }
+
+ public final String getError() {
+ return getStringValue("error");
+ }
+
+ public final String getTransport() {
+ return getStringValue("transport");
+ }
+
+ }
+
+ protected native AtmosphereConfiguration createConfig()
+ /*-{
+ return {
+ transport: 'websocket',
+ fallbackTransport: 'streaming',
+ contentType: 'application/json; charset=UTF-8',
+ reconnectInterval: '5000',
+ maxReconnectOnClose: 10000000,
+ trackMessageLength: true
+ };
+ }-*/;
+
+ private native JavaScriptObject doConnect(String uri,
+ JavaScriptObject config)
+ /*-{
+ var self = this;
+
+ config.url = uri;
+ config.onOpen = $entry(function(response) {
+ self.@com.vaadin.client.communication.AtmospherePushConnection::onOpen(*)(response);
+ });
+ config.onMessage = $entry(function(response) {
+ self.@com.vaadin.client.communication.AtmospherePushConnection::onMessage(*)(response);
+ });
+ config.onError = $entry(function(response) {
+ self.@com.vaadin.client.communication.AtmospherePushConnection::onError()(response);
+ });
+ config.onTransportFailure = $entry(function(reason,request) {
+ self.@com.vaadin.client.communication.AtmospherePushConnection::onTransportFailure(*)(reason);
+ });
+
+ return $wnd.jQueryVaadin.atmosphere.subscribe(config);
+ }-*/;
+
+ private native void doPush(JavaScriptObject socket, String message)
+ /*-{
+ socket.push(message);
+ }-*/;
+
+ private static native void doDisconnect(String url)
+ /*-{
+ $wnd.jQueryVaadin.atmosphere.unsubscribeUrl(url);
+ }-*/;
+
+ private static native boolean isAtmosphereLoaded()
+ /*-{
+ return $wnd.jQueryVaadin != undefined;
+ }-*/;
+
+ private void runWhenAtmosphereLoaded(final Command command) {
+
+ if (isAtmosphereLoaded()) {
+ command.execute();
+ } else {
+ VConsole.log("Loading " + ApplicationConstants.VAADIN_PUSH_JS);
+ ResourceLoader.get().loadScript(
+ connection.getConfiguration().getVaadinDirUrl()
+ + ApplicationConstants.VAADIN_PUSH_JS,
+ new ResourceLoadListener() {
+ @Override
+ public void onLoad(ResourceLoadEvent event) {
+ VConsole.log(ApplicationConstants.VAADIN_PUSH_JS
+ + " loaded");
+ command.execute();
+ }
+
+ @Override
+ public void onError(ResourceLoadEvent event) {
+ VConsole.error(event.getResourceUrl()
+ + " could not be loaded. Push will not work.");
+ }
+ });
+ }
+ }
+}
diff --git a/client/src/com/vaadin/client/communication/PushConnection.java b/client/src/com/vaadin/client/communication/PushConnection.java
new file mode 100644
index 0000000000..61656242bd
--- /dev/null
+++ b/client/src/com/vaadin/client/communication/PushConnection.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.communication;
+
+import com.google.gwt.user.client.Command;
+import com.vaadin.client.ApplicationConnection;
+
+/**
+ * Represents the client-side endpoint of a bidirectional ("push") communication
+ * channel. Can be used to send UIDL request messages to the server and to
+ * receive UIDL messages from the server (either asynchronously or as a response
+ * to a UIDL request.) Delegates the UIDL handling to the
+ * {@link ApplicationConnection}.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public interface PushConnection {
+
+ /**
+ * Two-phase construction to allow using GWT.create().
+ *
+ * @param connection
+ * The ApplicationConnection
+ */
+ public void init(ApplicationConnection connection);
+
+ /**
+ * Pushes a message to the server. Will throw an exception if the connection
+ * is not active (see {@link #isActive()}).
+ * <p>
+ * Implementation detail: The implementation is responsible for queuing
+ * messages that are pushed after {@link #init(ApplicationConnection)} has
+ * been called but before the connection has internally been set up and then
+ * replay those messages in the original order when the connection has been
+ * established.
+ *
+ * @param message
+ * the message to push
+ * @throws IllegalStateException
+ * if this connection is not active
+ *
+ * @see #isActive()
+ */
+ public void push(String message);
+
+ /**
+ * Checks whether this push connection is in a state where it can push
+ * messages to the server. A connection is active until
+ * {@link #disconnect(Command)} has been called.
+ *
+ * @return <code>true</code> if this connection can accept new messages;
+ * <code>false</code> if this connection is disconnected or
+ * disconnecting.
+ */
+ public boolean isActive();
+
+ /**
+ * Closes the push connection. To ensure correct message delivery order, new
+ * messages should not be sent using any other channel until it has been
+ * confirmed that all messages pending for this connection have been
+ * delivered. The provided command callback is invoked when messages can be
+ * passed using some other communication channel.
+ * <p>
+ * After this method has been called, {@link #isActive()} returns
+ * <code>false</code>. Calling this method for a connection that is no
+ * longer active will throw an exception.
+ *
+ * @param command
+ * callback command invoked when the connection has been properly
+ * disconnected
+ * @throws IllegalStateException
+ * if this connection is not active
+ */
+ public void disconnect(Command command);
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/debug/internal/DebugButton.java b/client/src/com/vaadin/client/debug/internal/DebugButton.java
new file mode 100644
index 0000000000..a49a392fbe
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/DebugButton.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import com.google.gwt.user.client.ui.Button;
+
+/**
+ * Simple extension of {@link Button} that is preconfigured with for use in
+ * {@link VDebugWindow}. Uses icon-font for icons, and allows title to be
+ * specified in the constructor.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public class DebugButton extends Button {
+
+ protected boolean active = false;
+
+ /**
+ * Creates a {@link Button} with the given icon-font icon. The icon id will
+ * be used in the <i>data-icon</i> attribute of an <i>&lt;i&gt;</i> -tag.
+ *
+ * @param icon
+ * Identifier for the desired icon in an icon-font
+ */
+ public DebugButton(Icon icon) {
+ this(icon, null, null);
+ }
+
+ /*-
+ public DebugButton(String caption) {
+ this(null, null, caption);
+ }
+
+ public DebugButton(String caption, String title) {
+ this(null, title, caption);
+ }
+ -*/
+
+ /**
+ * Creates a {@link Button} with the given icon-font icon and title
+ * (tooltip). The icon id will be used in the <i>data-icon</i> attribute of
+ * an <i>&lt;i&gt;</i> -tag.
+ *
+ * @param icon
+ * Identifier for the desired icon in an icon-font
+ * @param title
+ * Button title (tooltip)
+ *
+ */
+ public DebugButton(Icon icon, String title) {
+ this(icon, title, null);
+ }
+
+ /**
+ * Creates a {@link Button} with the given icon-font icon, title (tooltip),
+ * and caption. The icon id will be used in the <i>data-icon</i> attribute
+ * of an <i>&lt;i&gt;</i> -tag.
+ *
+ * @param icon
+ * Identifier for the desired icon in an icon-font
+ * @param title
+ * Title (tooltip)
+ * @param caption
+ * Button baption
+ */
+ public DebugButton(Icon icon, String title, String caption) {
+ super((icon != null ? icon : "") + (caption != null ? caption : ""));
+ if (title != null) {
+ setTitle(title);
+ }
+
+ setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ }
+
+ /**
+ * Adds or removes a stylename, indicating whether or not the button is in
+ * it's active state.
+ *
+ * @param active
+ */
+ public void setActive(boolean active) {
+ this.active = active;
+ setStyleDependentName(VDebugWindow.STYLENAME_ACTIVE, active);
+ }
+
+ /**
+ * Indicates wheter the Button is currently in its active state or not
+ *
+ * @return true if the Button is active, false otherwise
+ */
+ public boolean isActive() {
+ return active;
+ }
+
+}
diff --git a/client/src/com/vaadin/client/debug/internal/ErrorNotificationHandler.java b/client/src/com/vaadin/client/debug/internal/ErrorNotificationHandler.java
new file mode 100644
index 0000000000..0e4c57494b
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/ErrorNotificationHandler.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.debug.internal;
+
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+
+import com.google.gwt.logging.client.TextLogFormatter;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConfiguration;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ui.VNotification;
+
+/**
+ * Log message handler that shows big red notification for {@link Level#SEVERE}
+ * messages that have a throwable.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public class ErrorNotificationHandler extends Handler {
+ public ErrorNotificationHandler() {
+ setLevel(Level.SEVERE);
+ setFormatter(new TextLogFormatter(true) {
+ @Override
+ protected String getRecordInfo(LogRecord event, String newline) {
+ return "";
+ }
+ });
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ if (!isLoggable(record) || record.getThrown() == null) {
+ return;
+ }
+
+ try {
+ String exceptionText = getFormatter().format(record);
+
+ Widget owner = null;
+
+ if (!ApplicationConfiguration.getRunningApplications().isEmpty()) {
+ /*
+ * Make a wild guess and use the first available
+ * ApplicationConnection. This is better than than leaving the
+ * exception completely unstyled...
+ */
+ ApplicationConnection connection = ApplicationConfiguration
+ .getRunningApplications().get(0);
+ owner = connection.getUIConnector().getWidget();
+ }
+ VNotification
+ .createNotification(VNotification.DELAY_FOREVER, owner)
+ .show("<h1>Uncaught client side exception</h1><br />"
+ + exceptionText, VNotification.CENTERED, "error");
+ } catch (Exception e2) {
+ // Just swallow this exception
+ }
+ }
+
+ @Override
+ public void close() {
+ // Nothing to do
+ }
+
+ @Override
+ public void flush() {
+ // Nothing todo
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/debug/internal/HierarchySection.java b/client/src/com/vaadin/client/debug/internal/HierarchySection.java
new file mode 100644
index 0000000000..e4f3e2dcb1
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/HierarchySection.java
@@ -0,0 +1,676 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.dom.client.Style.TextDecoration;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DoubleClickEvent;
+import com.google.gwt.event.dom.client.DoubleClickHandler;
+import com.google.gwt.event.dom.client.HasDoubleClickHandlers;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.MouseOutEvent;
+import com.google.gwt.event.dom.client.MouseOutHandler;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+import com.google.gwt.event.dom.client.MouseOverHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.RootPanel;
+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.client.ApplicationConfiguration;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ComputedStyle;
+import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.JsArrayObject;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.SimpleTree;
+import com.vaadin.client.Util;
+import com.vaadin.client.VConsole;
+import com.vaadin.client.ValueMap;
+import com.vaadin.client.metadata.NoDataException;
+import com.vaadin.client.metadata.Property;
+import com.vaadin.client.ui.AbstractConnector;
+import com.vaadin.client.ui.UnknownComponentConnector;
+import com.vaadin.shared.AbstractComponentState;
+import com.vaadin.shared.communication.SharedState;
+
+/**
+ * Provides functionality for examining the UI component hierarchy.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public class HierarchySection implements Section {
+ private final DebugButton tabButton = new DebugButton(Icon.HIERARCHY,
+ "Examine component hierarchy");
+
+ private final FlowPanel content = new FlowPanel();
+ private final FlowPanel controls = new FlowPanel();
+
+ private final Button find = new DebugButton(Icon.HIGHLIGHT,
+ "Select a component on the page to inspect it");
+ private final Button analyze = new DebugButton(Icon.ANALYZE,
+ "Check layouts for potential problems");
+ private final Button generateWS = new DebugButton(Icon.OPTIMIZE,
+ "Show used connectors and how to optimize widgetset");
+ private final Button showHierarchy = new DebugButton(Icon.HIERARCHY,
+ "Show the connector hierarchy tree");
+
+ private HandlerRegistration highlightModeRegistration = null;
+
+ public HierarchySection() {
+ controls.add(showHierarchy);
+ showHierarchy.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ showHierarchy.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ showHierarchy();
+ }
+ });
+
+ controls.add(find);
+ find.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ find.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ toggleFind();
+ }
+ });
+
+ controls.add(analyze);
+ analyze.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ analyze.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ stopFind();
+ analyzeLayouts();
+ }
+ });
+
+ controls.add(generateWS);
+ generateWS.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ generateWS.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ generateWidgetset();
+ }
+ });
+
+ content.setStylePrimaryName(VDebugWindow.STYLENAME + "-hierarchy");
+ }
+
+ private void showHierarchy() {
+ Highlight.hideAll();
+ content.clear();
+
+ // TODO Clearing and rebuilding the contents is not optimal for UX as
+ // any previous expansions are lost.
+ SimplePanel trees = new SimplePanel();
+
+ for (ApplicationConnection application : ApplicationConfiguration
+ .getRunningApplications()) {
+ ServerConnector uiConnector = application.getUIConnector();
+ Widget connectorTree = buildConnectorTree(uiConnector);
+
+ trees.add(connectorTree);
+ }
+
+ content.add(trees);
+ }
+
+ private Widget buildConnectorTree(final ServerConnector connector) {
+ String connectorString = Util.getConnectorString(connector);
+
+ List<ServerConnector> children = connector.getChildren();
+
+ Widget widget;
+ if (children == null || children.isEmpty()) {
+ // Leaf node, just add a label
+ Label label = new Label(connectorString);
+ label.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ Highlight.showOnly(connector);
+ }
+ });
+ widget = label;
+ } else {
+ SimpleTree tree = new SimpleTree(connectorString) {
+ @Override
+ protected void select(ClickEvent event) {
+ super.select(event);
+ Highlight.showOnly(connector);
+ }
+ };
+ for (ServerConnector child : children) {
+ tree.add(buildConnectorTree(child));
+ }
+ widget = tree;
+ }
+
+ if (widget instanceof HasDoubleClickHandlers) {
+ HasDoubleClickHandlers has = (HasDoubleClickHandlers) widget;
+ has.addDoubleClickHandler(new DoubleClickHandler() {
+ @Override
+ public void onDoubleClick(DoubleClickEvent event) {
+ printState(connector);
+ }
+ });
+ }
+
+ return widget;
+ }
+
+ @Override
+ public DebugButton getTabButton() {
+ return tabButton;
+ }
+
+ @Override
+ public Widget getControls() {
+ return controls;
+ }
+
+ @Override
+ public Widget getContent() {
+ return content;
+ }
+
+ @Override
+ public void show() {
+
+ }
+
+ @Override
+ public void hide() {
+ stopFind();
+ }
+
+ private void generateWidgetset() {
+
+ content.clear();
+ HTML h = new HTML("Getting used connectors");
+ content.add(h);
+
+ String s = "";
+ for (ApplicationConnection ac : ApplicationConfiguration
+ .getRunningApplications()) {
+ ApplicationConfiguration conf = ac.getConfiguration();
+ s += "<h1>Used connectors for " + conf.getServiceUrl() + "</h1>";
+
+ for (String connectorName : getUsedConnectorNames(conf)) {
+ s += connectorName + "<br/>";
+ }
+
+ s += "<h2>To make an optimized widgetset based on these connectors, do:</h2>";
+ s += "<h3>1. Add to your widgetset.gwt.xml file:</h2>";
+ s += "<textarea rows=\"3\" style=\"width:90%\">";
+ s += "<generate-with class=\"OptimizedConnectorBundleLoaderFactory\">\n";
+ s += " <when-type-assignable class=\"com.vaadin.client.metadata.ConnectorBundleLoader\" />\n";
+ s += "</generate-with>";
+ s += "</textarea>";
+
+ s += "<h3>2. Add the following java file to your project:</h2>";
+ s += "<textarea rows=\"5\" style=\"width:90%\">";
+ s += generateOptimizedWidgetSet(getUsedConnectorNames(conf));
+ s += "</textarea>";
+ s += "<h3>3. Recompile widgetset</h2>";
+
+ }
+
+ h.setHTML(s);
+ }
+
+ private Set<String> getUsedConnectorNames(
+ ApplicationConfiguration configuration) {
+ int tag = 0;
+ Set<String> usedConnectors = new HashSet<String>();
+ while (true) {
+ String serverSideClass = configuration
+ .getServerSideClassNameForTag(tag);
+ if (serverSideClass == null) {
+ break;
+ }
+ Class<? extends ServerConnector> connectorClass = configuration
+ .getConnectorClassByEncodedTag(tag);
+ if (connectorClass == null) {
+ break;
+ }
+
+ if (connectorClass != UnknownComponentConnector.class) {
+ usedConnectors.add(connectorClass.getName());
+ }
+ tag++;
+ if (tag > 10000) {
+ // Sanity check
+ VConsole.error("Search for used connector classes was forcefully terminated");
+ break;
+ }
+ }
+ return usedConnectors;
+ }
+
+ public String generateOptimizedWidgetSet(Set<String> usedConnectors) {
+ String s = "import java.util.HashSet;\n";
+ s += "import java.util.Set;\n";
+
+ s += "import com.google.gwt.core.ext.typeinfo.JClassType;\n";
+ s += "import com.vaadin.client.ui.ui.UIConnector;\n";
+ s += "import com.vaadin.server.widgetsetutils.ConnectorBundleLoaderFactory;\n";
+ s += "import com.vaadin.shared.ui.Connect.LoadStyle;\n\n";
+
+ s += "public class OptimizedConnectorBundleLoaderFactory extends\n";
+ s += " ConnectorBundleLoaderFactory {\n";
+ s += " private Set<String> eagerConnectors = new HashSet<String>();\n";
+ s += " {\n";
+ for (String c : usedConnectors) {
+ s += " eagerConnectors.add(" + c
+ + ".class.getName());\n";
+ }
+ s += " }\n";
+ s += "\n";
+ s += " @Override\n";
+ s += " protected LoadStyle getLoadStyle(JClassType connectorType) {\n";
+ s += " if (eagerConnectors.contains(connectorType.getQualifiedBinaryName())) {\n";
+ s += " return LoadStyle.EAGER;\n";
+ s += " } else {\n";
+ s += " // Loads all other connectors immediately after the initial view has\n";
+ s += " // been rendered\n";
+ s += " return LoadStyle.DEFERRED;\n";
+ s += " }\n";
+ s += " }\n";
+ s += "}\n";
+
+ return s;
+ }
+
+ private void analyzeLayouts() {
+ content.clear();
+ content.add(new Label("Analyzing layouts..."));
+ List<ApplicationConnection> runningApplications = ApplicationConfiguration
+ .getRunningApplications();
+ for (ApplicationConnection applicationConnection : runningApplications) {
+ applicationConnection.analyzeLayouts();
+ }
+ }
+
+ @Override
+ public void meta(ApplicationConnection ac, ValueMap meta) {
+ content.clear();
+ JsArray<ValueMap> valueMapArray = meta
+ .getJSValueMapArray("invalidLayouts");
+ int size = valueMapArray.length();
+
+ if (size > 0) {
+ SimpleTree root = new SimpleTree("Layouts analyzed, " + size
+ + " top level problems");
+ for (int i = 0; i < size; i++) {
+ printLayoutError(ac, valueMapArray.get(i), root);
+ }
+ root.open(false);
+ content.add(root);
+ } else {
+ content.add(new Label("Layouts analyzed, no top level problems"));
+ }
+
+ Set<ComponentConnector> zeroHeightComponents = new HashSet<ComponentConnector>();
+ Set<ComponentConnector> zeroWidthComponents = new HashSet<ComponentConnector>();
+ findZeroSizeComponents(zeroHeightComponents, zeroWidthComponents,
+ ac.getUIConnector());
+ if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
+ content.add(new HTML("<h4> Client side notifications</h4>"
+ + " <em>The following relative sized components were "
+ + "rendered to a zero size container on the client side."
+ + " Note that these are not necessarily invalid "
+ + "states, but reported here as they might be.</em>"));
+ if (zeroHeightComponents.size() > 0) {
+ content.add(new HTML(
+ "<p><strong>Vertically zero size:</strong></p>"));
+ printClientSideDetectedIssues(zeroHeightComponents, ac);
+ }
+ if (zeroWidthComponents.size() > 0) {
+ content.add(new HTML(
+ "<p><strong>Horizontally zero size:</strong></p>"));
+ printClientSideDetectedIssues(zeroWidthComponents, ac);
+ }
+ }
+
+ }
+
+ private void printClientSideDetectedIssues(
+ Set<ComponentConnector> zeroSized, ApplicationConnection ac) {
+
+ // keep track of already highlighted parents
+ HashSet<String> parents = new HashSet<String>();
+
+ for (final ComponentConnector connector : zeroSized) {
+ final ServerConnector parent = connector.getParent();
+ final String parentId = parent.getConnectorId();
+
+ final Label errorDetails = new Label(Util.getSimpleName(connector)
+ + "[" + connector.getConnectorId() + "]" + " inside "
+ + Util.getSimpleName(parent));
+
+ if (parent instanceof ComponentConnector) {
+ final ComponentConnector parentConnector = (ComponentConnector) parent;
+ if (!parents.contains(parentId)) {
+ parents.add(parentId);
+ Highlight.show(parentConnector, "yellow");
+ }
+
+ errorDetails.addMouseOverHandler(new MouseOverHandler() {
+ @Override
+ public void onMouseOver(MouseOverEvent event) {
+ Highlight.hideAll();
+ Highlight.show(parentConnector, "yellow");
+ Highlight.show(connector);
+ errorDetails.getElement().getStyle()
+ .setTextDecoration(TextDecoration.UNDERLINE);
+ }
+ });
+ errorDetails.addMouseOutHandler(new MouseOutHandler() {
+ @Override
+ public void onMouseOut(MouseOutEvent event) {
+ Highlight.hideAll();
+ errorDetails.getElement().getStyle()
+ .setTextDecoration(TextDecoration.NONE);
+ }
+ });
+ errorDetails.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ printState(connector);
+ Highlight.show(connector);
+ }
+ });
+
+ }
+
+ Highlight.show(connector);
+ content.add(errorDetails);
+
+ }
+ }
+
+ private void printLayoutError(ApplicationConnection ac, ValueMap valueMap,
+ SimpleTree root) {
+ final String pid = valueMap.getString("id");
+
+ // find connector
+ final ComponentConnector connector = (ComponentConnector) ConnectorMap
+ .get(ac).getConnector(pid);
+
+ if (connector == null) {
+ root.add(new SimpleTree("[" + pid + "] NOT FOUND"));
+ return;
+ }
+
+ Highlight.show(connector);
+
+ final SimpleTree errorNode = new SimpleTree(
+ Util.getSimpleName(connector) + " id: " + pid);
+ errorNode.addDomHandler(new MouseOverHandler() {
+ @Override
+ public void onMouseOver(MouseOverEvent event) {
+ Highlight.showOnly(connector);
+ ((Widget) event.getSource()).getElement().getStyle()
+ .setTextDecoration(TextDecoration.UNDERLINE);
+ }
+ }, MouseOverEvent.getType());
+ errorNode.addDomHandler(new MouseOutHandler() {
+ @Override
+ public void onMouseOut(MouseOutEvent event) {
+ Highlight.hideAll();
+ ((Widget) event.getSource()).getElement().getStyle()
+ .setTextDecoration(TextDecoration.NONE);
+ }
+ }, MouseOutEvent.getType());
+
+ errorNode.addDomHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ if (event.getNativeEvent().getEventTarget().cast() == errorNode
+ .getElement().getChild(1).cast()) {
+ printState(connector);
+ }
+ }
+ }, ClickEvent.getType());
+
+ VerticalPanel errorDetails = new VerticalPanel();
+
+ if (valueMap.containsKey("heightMsg")) {
+ errorDetails.add(new Label("Height problem: "
+ + valueMap.getString("heightMsg")));
+ }
+ if (valueMap.containsKey("widthMsg")) {
+ errorDetails.add(new Label("Width problem: "
+ + valueMap.getString("widthMsg")));
+ }
+ if (errorDetails.getWidgetCount() > 0) {
+ errorNode.add(errorDetails);
+ }
+ if (valueMap.containsKey("subErrors")) {
+ HTML l = new HTML(
+ "<em>Expand this node to show problems that may be dependent on this problem.</em>");
+ errorDetails.add(l);
+ JsArray<ValueMap> suberrors = valueMap
+ .getJSValueMapArray("subErrors");
+ for (int i = 0; i < suberrors.length(); i++) {
+ ValueMap value = suberrors.get(i);
+ printLayoutError(ac, value, errorNode);
+ }
+
+ }
+ root.add(errorNode);
+ }
+
+ private void findZeroSizeComponents(
+ Set<ComponentConnector> zeroHeightComponents,
+ Set<ComponentConnector> zeroWidthComponents,
+ ComponentConnector connector) {
+ Widget widget = connector.getWidget();
+ ComputedStyle computedStyle = new ComputedStyle(widget.getElement());
+ if (computedStyle.getIntProperty("height") == 0) {
+ zeroHeightComponents.add(connector);
+ }
+ if (computedStyle.getIntProperty("width") == 0) {
+ zeroWidthComponents.add(connector);
+ }
+ List<ServerConnector> children = connector.getChildren();
+ for (ServerConnector serverConnector : children) {
+ if (serverConnector instanceof ComponentConnector) {
+ findZeroSizeComponents(zeroHeightComponents,
+ zeroWidthComponents,
+ (ComponentConnector) serverConnector);
+ }
+ }
+ }
+
+ @Override
+ public void uidl(ApplicationConnection ac, ValueMap uidl) {
+ // NOP
+ }
+
+ private boolean isFindMode() {
+ return (highlightModeRegistration != null);
+ }
+
+ private void toggleFind() {
+ if (isFindMode()) {
+ stopFind();
+ } else {
+ startFind();
+ }
+ }
+
+ private void startFind() {
+ Highlight.hideAll();
+ if (!isFindMode()) {
+ highlightModeRegistration = Event
+ .addNativePreviewHandler(highlightModeHandler);
+ find.addStyleDependentName(VDebugWindow.STYLENAME_ACTIVE);
+ }
+ }
+
+ private void stopFind() {
+ if (isFindMode()) {
+ highlightModeRegistration.removeHandler();
+ highlightModeRegistration = null;
+ find.removeStyleDependentName(VDebugWindow.STYLENAME_ACTIVE);
+ }
+ }
+
+ private void printState(ServerConnector connector) {
+ Highlight.showOnly(connector);
+
+ SharedState state = connector.getState();
+
+ Set<String> ignoreProperties = new HashSet<String>();
+ ignoreProperties.add("id");
+
+ String html = getRowHTML("Id", connector.getConnectorId());
+ html += getRowHTML("Connector", Util.getSimpleName(connector));
+
+ if (connector instanceof ComponentConnector) {
+ ComponentConnector component = (ComponentConnector) connector;
+
+ ignoreProperties.addAll(Arrays.asList("caption", "description",
+ "width", "height"));
+
+ AbstractComponentState componentState = component.getState();
+
+ html += getRowHTML("Widget",
+ Util.getSimpleName(component.getWidget()));
+ html += getRowHTML("Caption", componentState.caption);
+ html += getRowHTML("Description", componentState.description);
+ html += getRowHTML("Width", componentState.width + " (actual: "
+ + component.getWidget().getOffsetWidth() + "px)");
+ html += getRowHTML("Height", componentState.height + " (actual: "
+ + component.getWidget().getOffsetHeight() + "px)");
+ }
+
+ try {
+ JsArrayObject<Property> properties = AbstractConnector
+ .getStateType(connector).getPropertiesAsArray();
+ for (int i = 0; i < properties.size(); i++) {
+ Property property = properties.get(i);
+ String name = property.getName();
+ if (!ignoreProperties.contains(name)) {
+ html += getRowHTML(property.getDisplayName(),
+ property.getValue(state));
+ }
+ }
+ } catch (NoDataException e) {
+ html += "<div>Could not read state, error has been logged to the console</div>";
+ VConsole.error(e);
+ }
+
+ content.clear();
+ content.add(new HTML(html));
+ }
+
+ private String getRowHTML(String caption, Object value) {
+ return "<div class=\"" + VDebugWindow.STYLENAME
+ + "-row\"><span class=\"caption\">" + caption
+ + "</span><span class=\"value\">"
+ + Util.escapeHTML(String.valueOf(value)) + "</span></div>";
+ }
+
+ private final NativePreviewHandler highlightModeHandler = new NativePreviewHandler() {
+
+ @Override
+ public void onPreviewNativeEvent(NativePreviewEvent event) {
+
+ if (event.getTypeInt() == Event.ONKEYDOWN
+ && event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE) {
+ stopFind();
+ Highlight.hideAll();
+ return;
+ }
+ if (event.getTypeInt() == Event.ONMOUSEMOVE) {
+ Highlight.hideAll();
+ Element eventTarget = Util.getElementFromPoint(event
+ .getNativeEvent().getClientX(), event.getNativeEvent()
+ .getClientY());
+ if (VDebugWindow.get().getElement().isOrHasChild(eventTarget)) {
+ content.clear();
+ return;
+ }
+
+ for (ApplicationConnection a : ApplicationConfiguration
+ .getRunningApplications()) {
+ ComponentConnector connector = Util.getConnectorForElement(
+ a, a.getUIConnector().getWidget(), eventTarget);
+ if (connector == null) {
+ connector = Util.getConnectorForElement(a,
+ RootPanel.get(), eventTarget);
+ }
+ if (connector != null) {
+ printState(connector);
+ event.cancel();
+ event.consume();
+ event.getNativeEvent().stopPropagation();
+ return;
+ }
+ }
+ content.clear();
+ }
+ if (event.getTypeInt() == Event.ONCLICK) {
+ Highlight.hideAll();
+ event.cancel();
+ event.consume();
+ event.getNativeEvent().stopPropagation();
+ stopFind();
+ Element eventTarget = Util.getElementFromPoint(event
+ .getNativeEvent().getClientX(), event.getNativeEvent()
+ .getClientY());
+ for (ApplicationConnection a : ApplicationConfiguration
+ .getRunningApplications()) {
+ ComponentConnector connector = Util.getConnectorForElement(
+ a, a.getUIConnector().getWidget(), eventTarget);
+ if (connector == null) {
+ connector = Util.getConnectorForElement(a,
+ RootPanel.get(), eventTarget);
+ }
+
+ if (connector != null) {
+ printState(connector);
+ return;
+ }
+ }
+ }
+ event.cancel();
+ }
+
+ };
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/debug/internal/Highlight.java b/client/src/com/vaadin/client/debug/internal/Highlight.java
new file mode 100644
index 0000000000..f2695f58ca
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/Highlight.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import java.util.HashSet;
+
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.BrowserInfo;
+import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ServerConnector;
+import com.vaadin.client.ui.VWindow;
+
+/**
+ * Highlights a widget in the UI by overlaying a semi-transparent colored div.
+ * <p>
+ * Multiple highlights can be added, then selectively removed with
+ * {@link #hide(Element)} or all at once with {@link #hideAll()}.
+ * </p>
+ * <p>
+ * Note that highlights are intended to be short-term; highlights do not move or
+ * disappear with the highlighted widget, and it is also fairly likely that
+ * someone else calls {@link #hideAll()} eventually.
+ * </p>
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public class Highlight {
+
+ private static final String DEFAULT_COLOR = "red";
+ private static final double DEFAULT_OPACITY = 0.3;
+ private static final int MIN_WIDTH = 3;
+ private static final int MIN_HEIGHT = 3;
+
+ static HashSet<Element> highlights;
+
+ /**
+ * Highlight the {@link Widget} for the given {@link ComponentConnector}.
+ * <p>
+ * Pass the returned {@link Element} to {@link #hide(Element)} to remove
+ * this particular highlight.
+ * </p>
+ *
+ * @param connector
+ * ComponentConnector
+ * @return Highlight element
+ */
+ static Element show(ComponentConnector connector) {
+ return show(connector, DEFAULT_COLOR);
+ }
+
+ /**
+ * Highlight the {@link Widget} for the given connector if it is a
+ * {@link ComponentConnector}. Hide any other highlight.
+ * <p>
+ * Pass the returned {@link Element} to {@link #hide(Element)} to remove
+ * this particular highlight.
+ * </p>
+ *
+ * @since 7.1
+ *
+ * @param connector
+ * the server connector to highlight
+ * @return Highlight element, or <code>null</code> if the connector isn't a
+ * component
+ */
+ static Element showOnly(ServerConnector connector) {
+ hideAll();
+ if (connector instanceof ComponentConnector) {
+ return show((ComponentConnector) connector);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Highlights the {@link Widget} for the given {@link ComponentConnector}
+ * using the given color.
+ * <p>
+ * Pass the returned {@link Element} to {@link #hide(Element)} to remove
+ * this particular highlight.
+ * </p>
+ *
+ * @param connector
+ * ComponentConnector
+ * @param color
+ * Color of highlight
+ * @return Highlight element
+ */
+ static Element show(ComponentConnector connector, String color) {
+ if (connector != null) {
+ Widget w = connector.getWidget();
+ return show(w, color);
+ }
+ return null;
+ }
+
+ /**
+ * Highlights the given {@link Widget}.
+ * <p>
+ * Pass the returned {@link Element} to {@link #hide(Element)} to remove
+ * this particular highlight.
+ * </p>
+ *
+ * @param widget
+ * Widget to highlight
+ * @return Highlight element
+ */
+ static Element show(Widget widget) {
+ return show(widget, DEFAULT_COLOR);
+ }
+
+ /**
+ * Highlight the given {@link Widget} using the given color.
+ * <p>
+ * Pass the returned {@link Element} to {@link #hide(Element)} to remove
+ * this particular highlight.
+ * </p>
+ *
+ * @param widget
+ * Widget to highlight
+ * @param color
+ * Color of highlight
+ * @return Highlight element
+ */
+ static Element show(Widget widget, String color) {
+ if (widget != null) {
+ if (highlights == null) {
+ highlights = new HashSet<Element>();
+ }
+
+ Element highlight = DOM.createDiv();
+ Style style = highlight.getStyle();
+ style.setTop(widget.getAbsoluteTop(), Unit.PX);
+ style.setLeft(widget.getAbsoluteLeft(), Unit.PX);
+ int width = widget.getOffsetWidth();
+ if (width < MIN_WIDTH) {
+ width = MIN_WIDTH;
+ }
+ style.setWidth(width, Unit.PX);
+ int height = widget.getOffsetHeight();
+ if (height < MIN_HEIGHT) {
+ height = MIN_HEIGHT;
+ }
+ style.setHeight(height, Unit.PX);
+ RootPanel.getBodyElement().appendChild(highlight);
+
+ style.setPosition(Position.ABSOLUTE);
+ style.setZIndex(VWindow.Z_INDEX + 1000);
+ style.setBackgroundColor(color);
+ style.setOpacity(DEFAULT_OPACITY);
+ if (BrowserInfo.get().isIE()) {
+ style.setProperty("filter", "alpha(opacity="
+ + (DEFAULT_OPACITY * 100) + ")");
+ }
+
+ highlights.add(highlight);
+
+ return highlight;
+ }
+ return null;
+ }
+
+ /**
+ * Hides the given highlight.
+ *
+ * @param highlight
+ * Highlight to hide
+ */
+ static void hide(Element highlight) {
+ if (highlight != null && highlight.getParentElement() != null) {
+ highlight.getParentElement().removeChild(highlight);
+ highlights.remove(highlight);
+ }
+ }
+
+ /**
+ * Hides all highlights
+ */
+ static void hideAll() {
+ if (highlights != null) {
+ for (Element highlight : highlights) {
+ if (highlight.getParentElement() != null) {
+ highlight.getParentElement().removeChild(highlight);
+ }
+ }
+ highlights = null;
+ }
+ }
+
+}
diff --git a/client/src/com/vaadin/client/debug/internal/Icon.java b/client/src/com/vaadin/client/debug/internal/Icon.java
new file mode 100644
index 0000000000..cc2ef3b348
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/Icon.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.debug.internal;
+
+public enum Icon {
+
+ SEARCH("&#xf002;"), //
+ OK("&#xf00c;"), //
+ REMOVE("&#xf00d;"), //
+ CLOSE("&#xf011;"), //
+ CLEAR("&#xf014;"), //
+ RESET_TIMER("&#xf017;"), //
+ MINIMIZE("&#xf066;"), //
+ WARNING("&#xf071;"), //
+ INFO("&#xf05a;"), //
+ ERROR("&#xf06a;"), //
+ HIGHLIGHT("&#xf05b;"), //
+ LOG("&#xf0c9;"), //
+ OPTIMIZE("&#xf0d0;"), //
+ HIERARCHY("&#xf0e8;"), //
+ MENU("&#xf013;"), //
+ NETWORK("&#xf0ec;"), //
+ ANALYZE("&#xf0f0;"), //
+ SCROLL_LOCK("&#xf023;"), //
+ DEVMODE_OFF("&#xf10c;"), //
+ DEVMODE_SUPER("&#xf111;"), //
+ DEVMODE_ON("&#xf110;"), //
+ // BAN_CIRCLE("&#xf05e;"), //
+ MAXIMIZE("&#xf065;"), //
+ RESET("&#xf021;"), //
+ PERSIST("&#xf02e"); //
+
+ private String id;
+
+ private Icon(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return "<i data-icon=\"" + id + "\"></i>";
+ }
+
+ public String getId() {
+ return id;
+ }
+
+}
diff --git a/client/src/com/vaadin/client/debug/internal/LogSection.java b/client/src/com/vaadin/client/debug/internal/LogSection.java
new file mode 100644
index 0000000000..74ac3641c2
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/LogSection.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import java.util.logging.Formatter;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.logging.client.HtmlLogFormatter;
+import com.google.gwt.storage.client.Storage;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ValueMap;
+
+/**
+ * Displays the log messages.
+ * <p>
+ * Scroll lock state is persisted.
+ * </p>
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public class LogSection implements Section {
+
+ private final class LogSectionHandler extends Handler {
+ private LogSectionHandler() {
+ setLevel(Level.ALL);
+ setFormatter(new HtmlLogFormatter(true) {
+ @Override
+ protected String getHtmlPrefix(LogRecord event) {
+ return "";
+ }
+
+ @Override
+ protected String getHtmlSuffix(LogRecord event) {
+ return "";
+ }
+
+ @Override
+ protected String getRecordInfo(LogRecord event, String newline) {
+ return "";
+ }
+ });
+ }
+
+ @Override
+ public void publish(LogRecord record) {
+ if (!isLoggable(record)) {
+ return;
+ }
+
+ Formatter formatter = getFormatter();
+ String msg = formatter.format(record);
+
+ addRow(record.getLevel(), msg);
+ }
+
+ @Override
+ public void close() {
+ // Nothing to do
+ }
+
+ @Override
+ public void flush() {
+ // Nothing todo
+ }
+ }
+
+ // If scroll is not locked, content will be scrolled after delay
+ private static final int SCROLL_DELAY = 100;
+ private Timer scrollTimer = null;
+
+ // TODO should be persisted
+ // log content limit
+ private int limit = 500;
+
+ private final DebugButton tabButton = new DebugButton(Icon.LOG,
+ "Debug message log");
+
+ private final HTML content = new HTML();
+ private final Element contentElement;
+ private final FlowPanel controls = new FlowPanel();
+
+ private final Button clear = new DebugButton(Icon.CLEAR, "Clear log");
+ private final Button reset = new DebugButton(Icon.RESET_TIMER,
+ "Reset timer");
+ private final Button scroll = new DebugButton(Icon.SCROLL_LOCK,
+ "Scroll lock");
+
+ public LogSection() {
+ contentElement = content.getElement();
+ content.setStylePrimaryName(VDebugWindow.STYLENAME + "-log");
+
+ // clear log button
+ controls.add(clear);
+ clear.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ clear.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ clear();
+ }
+ });
+
+ // reset timer button
+ controls.add(reset);
+ reset.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ reset.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ resetTimer();
+ }
+ });
+
+ // scroll lock toggle
+ controls.add(scroll);
+ scroll.setStylePrimaryName(VDebugWindow.STYLENAME_BUTTON);
+ scroll.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ toggleScrollLock();
+ }
+ });
+
+ // select message if row is clicked
+ content.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ Element el = Element
+ .as(event.getNativeEvent().getEventTarget());
+ while (!el.getClassName().contains(
+ VDebugWindow.STYLENAME + "-message")) {
+ el = el.getParentElement();
+ if (el == contentElement) {
+ // clicked something else
+ return;
+ }
+ }
+ selectText(el);
+ }
+ });
+
+ // Add handler to the root logger
+ Logger.getLogger("").addHandler(new LogSectionHandler());
+ }
+
+ /**
+ * Toggles scroll lock, writes state to persistent storage.
+ */
+ void toggleScrollLock() {
+ setScrollLock(scrollTimer != null);
+
+ Storage storage = Storage.getLocalStorageIfSupported();
+ if (storage == null) {
+ return;
+ }
+ VDebugWindow.writeState(storage, "log-scrollLock", scrollTimer == null);
+ }
+
+ /**
+ * Activates or deactivates scroll lock
+ *
+ * @param locked
+ */
+ void setScrollLock(boolean locked) {
+ if (locked && scrollTimer != null) {
+ scrollTimer.cancel();
+ scrollTimer = null;
+
+ } else if (!locked && scrollTimer == null) {
+ scrollTimer = new Timer() {
+ @Override
+ public void run() {
+ Element el = (Element) contentElement.getLastChild();
+ if (el != null) {
+ el = el.getFirstChildElement();
+ if (el != null) {
+ el.scrollIntoView();
+ }
+ }
+ }
+ };
+
+ }
+ scroll.setStyleDependentName(VDebugWindow.STYLENAME_ACTIVE, locked);
+
+ }
+
+ private native void selectText(Element el)
+ /*-{
+ if ($doc.selection && $doc.selection.createRange) {
+ var r = $doc.selection.createRange();
+ r.moveToElementText(el);
+ r.select();
+ } else if ($doc.createRange && $wnd.getSelection) {
+ var r = $doc.createRange();
+ r.selectNode(el);
+ var selection = $wnd.getSelection();
+ selection.removeAllRanges();
+ selection.addRange(r);
+ }
+ }-*/;
+
+ private void clear() {
+ contentElement.setInnerText("");
+ }
+
+ private void applyLimit() {
+ while (contentElement.getChildCount() > limit) {
+ contentElement.removeChild(contentElement.getFirstChild());
+ }
+ }
+
+ /**
+ * Sets the log row limit.
+ *
+ * @param limit
+ */
+ public void setLimit(int limit) {
+ this.limit = limit;
+ applyLimit();
+
+ // TODO shoud be persisted
+ }
+
+ /**
+ * Gets the current log row limit.
+ *
+ * @return
+ */
+ public int getLimit() {
+ // TODO should be read from persistent storage
+ return limit;
+ }
+
+ @Override
+ public DebugButton getTabButton() {
+ return tabButton;
+ }
+
+ @Override
+ public Widget getControls() {
+ return controls;
+ }
+
+ @Override
+ public Widget getContent() {
+ return content;
+ }
+
+ @Override
+ public void show() {
+ Storage storage = Storage.getLocalStorageIfSupported();
+ if (storage == null) {
+ return;
+ }
+ setScrollLock(VDebugWindow.readState(storage, "log-scrollLock", false));
+ }
+
+ @Override
+ public void hide() {
+ // remove timer
+ setScrollLock(true);
+ }
+
+ /**
+ * Schedules a scoll if scroll lock is not active.
+ */
+ private void maybeScroll() {
+ if (scrollTimer != null) {
+ scrollTimer.cancel();
+ scrollTimer.schedule(SCROLL_DELAY);
+ }
+ }
+
+ /**
+ * Resets the timer and inserts a log row indicating this.
+ */
+ private void resetTimer() {
+ int sinceStart = VDebugWindow.getMillisSinceStart();
+ int sinceReset = VDebugWindow.resetTimer();
+ Element row = DOM.createDiv();
+ row.addClassName(VDebugWindow.STYLENAME + "-reset");
+ row.setInnerHTML(Icon.RESET_TIMER + " Timer reset");
+ row.setTitle(VDebugWindow.getTimingTooltip(sinceStart, sinceReset));
+ contentElement.appendChild(row);
+ maybeScroll();
+ }
+
+ /**
+ * Adds a row to the log, applies the log row limit by removing old rows if
+ * needed, and scrolls new row into view if scroll lock is not active.
+ *
+ * @param level
+ * @param msg
+ * @return
+ */
+ private Element addRow(Level level, String msg) {
+ int sinceReset = VDebugWindow.getMillisSinceReset();
+ int sinceStart = VDebugWindow.getMillisSinceStart();
+
+ Element row = DOM.createDiv();
+ row.addClassName(VDebugWindow.STYLENAME + "-row");
+ row.addClassName(level.getName());
+
+ String inner = "<span class='" + VDebugWindow.STYLENAME + "-"
+ + "'></span><span class='" + VDebugWindow.STYLENAME
+ + "-time' title='"
+ + VDebugWindow.getTimingTooltip(sinceStart, sinceReset) + "'>"
+ + sinceReset + "ms</span><span class='"
+ + VDebugWindow.STYLENAME + "-message'>" + msg + "</span>";
+ row.setInnerHTML(inner);
+
+ contentElement.appendChild(row);
+ applyLimit();
+
+ maybeScroll();
+
+ return row;
+ }
+
+ @Override
+ public void meta(ApplicationConnection ac, ValueMap meta) {
+ addRow(Level.FINE, "Meta: " + meta.toSource());
+ }
+
+ @Override
+ public void uidl(ApplicationConnection ac, ValueMap uidl) {
+ addRow(Level.FINE, "UIDL: " + uidl.toSource());
+ }
+
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/debug/internal/NetworkSection.java b/client/src/com/vaadin/client/debug/internal/NetworkSection.java
new file mode 100644
index 0000000000..e94791ce1f
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/NetworkSection.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.VUIDLBrowser;
+import com.vaadin.client.ValueMap;
+
+/**
+ * Displays network activity; requests and responses.
+ *
+ * Currently only displays responses in a simple manner.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public class NetworkSection implements Section {
+
+ private final int maxSize = 10;
+
+ private final DebugButton tabButton = new DebugButton(Icon.NETWORK,
+ "Communication");
+
+ private final HorizontalPanel controls = new HorizontalPanel();
+ private final FlowPanel content = new FlowPanel();
+
+ @Override
+ public DebugButton getTabButton() {
+ return tabButton;
+ }
+
+ @Override
+ public Widget getControls() {
+ return controls;
+ }
+
+ @Override
+ public Widget getContent() {
+ return content;
+ }
+
+ @Override
+ public void show() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void hide() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void meta(ApplicationConnection ac, ValueMap meta) {
+ // NOP
+ }
+
+ @Override
+ public void uidl(ApplicationConnection ac, ValueMap uidl) {
+ int sinceStart = VDebugWindow.getMillisSinceStart();
+ int sinceReset = VDebugWindow.getMillisSinceReset();
+ VUIDLBrowser vuidlBrowser = new VUIDLBrowser(uidl, ac);
+ vuidlBrowser.addStyleName(VDebugWindow.STYLENAME + "-row");
+ // TODO style this
+ /*-
+ vuidlBrowser.setText("<span class=\"" + VDebugWindow.STYLENAME
+ + "-time\">" + sinceReset + "ms</span><span class=\""
+ + VDebugWindow.STYLENAME + "-message\">response</span>");
+ -*/
+ vuidlBrowser.setText("Response @ " + sinceReset + "ms");
+ vuidlBrowser.setTitle(VDebugWindow.getTimingTooltip(sinceStart,
+ sinceReset));
+ vuidlBrowser.close();
+ content.add(vuidlBrowser);
+ while (content.getWidgetCount() > maxSize) {
+ content.remove(0);
+ }
+ }
+
+}
diff --git a/client/src/com/vaadin/client/debug/internal/Section.java b/client/src/com/vaadin/client/debug/internal/Section.java
new file mode 100644
index 0000000000..c6b8af55e8
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/Section.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ValueMap;
+
+/**
+ * A Section is displayed as a tab in the {@link VDebugWindow}.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public interface Section {
+
+ /**
+ * Returns a button that will be used to activate this section, displayed as
+ * a tab in {@link VDebugWindow}.
+ * <p>
+ * <em>The same instance <b>must</b> be returned each time this method is called.</em>
+ * </p>
+ * <p>
+ * The button should preferably only have an icon (no caption), and should
+ * have a longer description as title (tooltip).
+ * </p>
+ *
+ * @return section id
+ */
+ public DebugButton getTabButton();
+
+ /**
+ * Returns a widget that is placed on top of the Section content when the
+ * Section (tab) is active in the {@link VDebugWindow}.
+ *
+ * @return section controls
+ */
+ public Widget getControls();
+
+ /**
+ * Returns a widget that is the main content of the section, displayed when
+ * the section is active in the {@link VDebugWindow}.
+ *
+ * @return
+ */
+ public Widget getContent();
+
+ /**
+ * Called when the section is activated in {@link VDebugWindow}. Provides an
+ * opportunity to e.g start timers, add listeners etc.
+ */
+ public void show();
+
+ /**
+ * Called when the section is deactivated in {@link VDebugWindow}. Provides
+ * an opportunity to e.g stop timers, remove listeners etc.
+ */
+ public void hide();
+
+ public void meta(ApplicationConnection ac, ValueMap meta);
+
+ public void uidl(ApplicationConnection ac, ValueMap uidl);
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java
new file mode 100644
index 0000000000..5aab95616a
--- /dev/null
+++ b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java
@@ -0,0 +1,1062 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.debug.internal;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import com.google.gwt.core.client.Duration;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Cursor;
+import com.google.gwt.dom.client.Style.Overflow;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseEvent;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.http.client.UrlBuilder;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.i18n.client.NumberFormat;
+import com.google.gwt.storage.client.Storage;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Event.NativePreviewEvent;
+import com.google.gwt.user.client.Event.NativePreviewHandler;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ValueMap;
+import com.vaadin.client.ui.VOverlay;
+
+/**
+ * Debug window implementation.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public final class VDebugWindow extends VOverlay {
+
+ // CSS classes
+ static final String STYLENAME = "v-debugwindow";
+ static final String STYLENAME_BUTTON = STYLENAME + "-button";
+ static final String STYLENAME_ACTIVE = "active";
+
+ protected static final String STYLENAME_HEAD = STYLENAME + "-head";
+ protected static final String STYLENAME_TABS = STYLENAME + "-tabs";
+ protected static final String STYLENAME_TAB = STYLENAME + "-tab";
+ protected static final String STYLENAME_CONTROLS = STYLENAME + "-controls";
+ protected static final String STYLENAME_SECTION_HEAD = STYLENAME
+ + "-section-head";
+ protected static final String STYLENAME_CONTENT = STYLENAME + "-content";
+ protected static final String STYLENAME_SELECTED = "selected";
+
+ // drag this far before actually moving window
+ protected static final int MOVE_TRESHOLD = 5;
+
+ // window minimum sizes
+ protected static final int MIN_HEIGHT = 40;
+ protected static final int HANDLE_SIZE = 5;
+
+ // identifiers for localStorage
+ private static final String STORAGE_PREFIX = "v-debug-";
+ private static final String STORAGE_FULL_X = "x";
+ private static final String STORAGE_FULL_Y = "y";
+ private static final String STORAGE_FULL_W = "w";
+ private static final String STORAGE_FULL_H = "h";
+ private static final String STORAGE_MIN_X = "mx";
+ private static final String STORAGE_MIN_Y = "my";
+ private static final String STORAGE_ACTIVE_SECTION = "t";
+ private static final String STORAGE_IS_MINIMIZED = "m";
+ private static final String STORAGE_FONT_SIZE = "s";
+
+ // state, these are persisted
+ protected Section activeSection;
+ protected boolean minimized = false;
+ protected int fullX = -10;
+ protected int fullY = -10;
+ protected int fullW = 300;
+ protected int fullH = 150;
+ protected int minX = -10;
+ protected int minY = 10;
+ protected int fontSize = 1; // 0-2
+
+ // Timers since application start, and last timer reset
+ private static final Duration start = new Duration();
+ private static Duration lastReset = start;
+
+ // outer panel
+ protected FlowPanel window = new FlowPanel();
+ // top (tabs + controls)
+ protected FlowPanel head = new FlowPanel();
+ protected FlowPanel tabs = new FlowPanel();
+ protected FlowPanel controls = new FlowPanel();
+ protected Button minimize = new DebugButton(Icon.MINIMIZE, "Minimize");
+ protected Button menu = new DebugButton(Icon.MENU, "Menu");
+ protected Button close = new DebugButton(Icon.CLOSE, "Close");
+
+ // menu
+ protected Menu menuPopup = new Menu();
+
+ // section specific area
+ protected FlowPanel sectionHead = new FlowPanel();
+ // content wrapper
+ protected SimplePanel content = new SimplePanel();
+
+ // sections
+ protected ArrayList<Section> sections = new ArrayList<Section>();
+
+ // handles resizing (mouse)
+ protected ResizeHandler resizeHandler = new ResizeHandler();
+ protected HandlerRegistration resizeReg = null;
+ protected HandlerRegistration resizeReg2 = null;
+
+ // handles window movement (mouse)
+ protected MoveHandler moveHandler = new MoveHandler();
+ protected HandlerRegistration moveReg = null;
+
+ // TODO this class should really be a singleton.
+ static VDebugWindow instance;
+
+ /**
+ * This class should only be instantiated by the framework, use
+ * {@link #get()} instead to get the singleton instance.
+ * <p>
+ * {@link VDebugWindow} provides windowing functionality and shows
+ * {@link Section}s added with {@link #addSection(Section)} as tabs.
+ * </p>
+ * <p>
+ * {@link Section#getTabButton()} is called to obtain a unique id for the
+ * Sections; the id should actually be an identifier for an icon in the
+ * icon-font in use.
+ * </p>
+ * <p>
+ * {@link Section#getControls()} and {@link Section#getContent()} is called
+ * when the Section is activated (displayed). Additionally
+ * {@link Section#show()} is called to allow the Section to initialize
+ * itself as needed when shown. Conversely {@link Section#hide()} is called
+ * when the Section is deactivated.
+ * </p>
+ * <p>
+ * Sections should take care to prefix CSS classnames used with
+ * {@link VDebugWindow}.{@link #STYLENAME} to avoid that application theme
+ * interferes with the debug window content.
+ * </p>
+ * <p>
+ * Some of the window state, such as position and size, is persisted to
+ * localStorage. Sections can use
+ * {@link #writeState(Storage, String, Object)} and
+ * {@link #readState(Storage, String, String)} (and relatives) to write and
+ * read own persisted settings, keys will automatically be prefixed with
+ * {@value #STORAGE_PREFIX}.
+ * </p>
+ */
+ public VDebugWindow() {
+ super(false, false);
+ instance = this;
+ getElement().getStyle().setOverflow(Overflow.HIDDEN);
+ setStylePrimaryName(STYLENAME);
+
+ setWidget(window);
+ window.add(head);
+ head.add(tabs);
+ head.add(controls);
+ head.add(sectionHead);
+ window.add(content);
+
+ head.setStylePrimaryName(STYLENAME_HEAD);
+ tabs.setStylePrimaryName(STYLENAME_TABS);
+ controls.setStylePrimaryName(STYLENAME_CONTROLS);
+ sectionHead.setStylePrimaryName(STYLENAME_SECTION_HEAD);
+ content.setStylePrimaryName(STYLENAME_CONTENT);
+
+ // add controls TODO move these
+ controls.add(menu);
+ menu.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ menuPopup.showRelativeTo(menu);
+ }
+ });
+
+ controls.add(minimize);
+ minimize.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ toggleMinimized();
+ writeStoredState();
+ }
+ });
+ controls.add(close);
+ close.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ close();
+ }
+ });
+
+ Style s = content.getElement().getStyle();
+ s.setOverflow(Overflow.AUTO);
+
+ // window can be moved by dragging header
+ moveReg = head.addDomHandler(moveHandler, MouseDownEvent.getType());
+ // resize from all sides and corners
+ resizeReg = content.addDomHandler(resizeHandler,
+ MouseDownEvent.getType());
+ // changes mouse pointer when hovering sides / corners
+ resizeReg2 = content.addDomHandler(resizeHandler,
+ MouseMoveEvent.getType());
+ }
+
+ /**
+ * Gets the {@link #VDebugWindow()} singleton instance.
+ *
+ * @return
+ */
+ public static VDebugWindow get() {
+ if (instance == null) {
+ instance = new VDebugWindow();
+ }
+ return instance;
+ }
+
+ /**
+ * Closes the window and stops visual logging.
+ */
+ public void close() {
+ // TODO disable even more
+ if (resizeReg != null) {
+ resizeReg.removeHandler();
+ resizeReg2.removeHandler();
+ moveReg.removeHandler();
+ }
+ Highlight.hideAll();
+ hide();
+
+ }
+
+ boolean isClosed() {
+ return !isShowing();
+ }
+
+ /**
+ * Reads the stored state from localStorage.
+ */
+ private void readStoredState() {
+ Storage storage = Storage.getLocalStorageIfSupported();
+ if (storage == null) {
+ return;
+ }
+
+ fullX = readState(storage, STORAGE_FULL_X, -510);
+ fullY = readState(storage, STORAGE_FULL_Y, -230);
+ fullW = readState(storage, STORAGE_FULL_W, 500);
+ fullH = readState(storage, STORAGE_FULL_H, 150);
+ minX = readState(storage, STORAGE_MIN_X, -40);
+ minY = readState(storage, STORAGE_MIN_Y, -70);
+ setFontSize(readState(storage, STORAGE_FONT_SIZE, 1));
+
+ activateSection(readState(storage, STORAGE_ACTIVE_SECTION, 0));
+
+ setMinimized(readState(storage, STORAGE_IS_MINIMIZED, false));
+
+ applyPositionAndSize();
+ }
+
+ /**
+ * Writes the persistent state to localStorage.
+ */
+ private void writeStoredState() {
+ if (isClosed()) {
+ return;
+ }
+ Storage storage = Storage.getLocalStorageIfSupported();
+ if (storage == null) {
+ return;
+ }
+
+ writeState(storage, STORAGE_FULL_X, fullX);
+ writeState(storage, STORAGE_FULL_Y, fullY);
+ writeState(storage, STORAGE_FULL_W, fullW);
+ writeState(storage, STORAGE_FULL_H, fullH);
+ writeState(storage, STORAGE_MIN_X, minX);
+ writeState(storage, STORAGE_MIN_Y, minY);
+ writeState(storage, STORAGE_FONT_SIZE, fontSize);
+
+ if (activeSection != null) {
+ writeState(storage, STORAGE_ACTIVE_SECTION,
+ activeSection.getTabButton());
+ }
+
+ writeState(storage, STORAGE_IS_MINIMIZED, minimized);
+ }
+
+ /**
+ * Writes the given value to the given {@link Storage} using the given key
+ * (automatically prefixed with {@value #STORAGE_PREFIX}).
+ *
+ * @param storage
+ * @param key
+ * @param value
+ */
+ static void writeState(Storage storage, String key, Object value) {
+ storage.setItem(STORAGE_PREFIX + key, String.valueOf(value));
+ }
+
+ /**
+ * Returns the item with the given key (automatically prefixed with
+ * {@value #STORAGE_PREFIX}) as an int from the given {@link Storage},
+ * returning the given default value instead if not successful (e.g missing
+ * item).
+ *
+ * @param storage
+ * @param key
+ * @param def
+ * @return stored or default value
+ */
+ static int readState(Storage storage, String key, int def) {
+ try {
+ return Integer.parseInt(storage.getItem(STORAGE_PREFIX + key));
+ } catch (Exception e) {
+ return def;
+ }
+ }
+
+ /**
+ * Returns the item with the given key (automatically prefixed with
+ * {@value #STORAGE_PREFIX}) as a boolean from the given {@link Storage},
+ * returning the given default value instead if not successful (e.g missing
+ * item).
+ *
+ * @param storage
+ * @param key
+ * @param def
+ * @return stored or default value
+ */
+ static boolean readState(Storage storage, String key, boolean def) {
+ try {
+ return Boolean.parseBoolean(storage.getItem(STORAGE_PREFIX + key));
+ } catch (Exception e) {
+ return def;
+ }
+ }
+
+ /**
+ * Returns the item with the given key (automatically prefixed with
+ * {@value #STORAGE_PREFIX}) as a String from the given {@link Storage},
+ * returning the given default value instead if not successful (e.g missing
+ * item).
+ *
+ * @param storage
+ * @param key
+ * @param def
+ * @return stored or default value
+ */
+ static String readState(Storage storage, String key, String def) {
+ String val = storage.getItem(STORAGE_PREFIX + key);
+ return val != null ? val : def;
+ }
+
+ /**
+ * Resets (clears) the stored state from localStorage.
+ */
+ private void resetStoredState() {
+ Storage storage = Storage.getLocalStorageIfSupported();
+ if (storage == null) {
+ return;
+ }
+ // note: length is live
+ for (int i = 0; i < storage.getLength();) {
+ String key = storage.key(i);
+ if (key.startsWith(STORAGE_PREFIX)) {
+ removeState(storage, key.substring(STORAGE_PREFIX.length()));
+ } else {
+ i++;
+ }
+ }
+ }
+
+ /**
+ * Removes the item with the given key (automatically prefixed with
+ * {@value #STORAGE_PREFIX}) from the given {@link Storage}.
+ *
+ * @param storage
+ * @param key
+ */
+ private void removeState(Storage storage, String key) {
+ storage.removeItem(STORAGE_PREFIX + key);
+ }
+
+ /**
+ * Applies the appropriate instance variables for width, height, x, y
+ * depending on if the window is minimized or not.
+ *
+ * If the value is negative, the window is positioned that amount of pixels
+ * from the right/bottom instead of left/top.
+ *
+ * Finally, the position is bounds-checked so that the window is not moved
+ * off-screen (the adjusted values are not saved).
+ */
+ private void applyPositionAndSize() {
+ int x = 0;
+ int y = 0;
+ if (minimized) {
+ x = minX;
+ if (minX < 0) {
+ x = Window.getClientWidth() + minX;
+ }
+ y = minY;
+ if (minY < 0) {
+ y = Window.getClientHeight() + minY;
+ }
+
+ } else {
+ x = fullX;
+ if (fullX < 0) {
+ x = Window.getClientWidth() + fullX;
+ }
+ y = fullY;
+ if (y < 0) {
+ y = Window.getClientHeight() + fullY;
+ }
+ content.setWidth(fullW + "px");
+ content.setHeight(fullH + "px");
+ }
+
+ // bounds check
+ if (x < 0) {
+ x = 0;
+ }
+ if (x > Window.getClientWidth() - getOffsetWidth()) {
+ // not allowed off-screen to the right
+ x = Window.getClientWidth() - getOffsetWidth();
+ }
+ if (y > Window.getClientHeight() - getOffsetHeight()) {
+ y = Window.getClientHeight() - getOffsetHeight();
+ }
+ if (y < 0) {
+ y = 0;
+ }
+
+ setPopupPosition(x, y);
+ }
+
+ /**
+ * Reads position and size from the DOM to local variables (which in turn
+ * can be stored to localStorage)
+ */
+ private void readPositionAndSize() {
+ int x = getPopupLeft();
+ int fromRight = Window.getClientWidth() - x - getOffsetWidth();
+ if (fromRight < x) {
+ x -= Window.getClientWidth();
+ }
+
+ int y = getPopupTop();
+ int fromBottom = Window.getClientHeight() - y - getOffsetHeight();
+ if (fromBottom < y) {
+ y -= Window.getClientHeight();
+ }
+
+ if (minimized) {
+ minY = y;
+ minX = x;
+ } else {
+ fullY = y;
+ fullX = x;
+ fullW = content.getOffsetWidth();
+ fullH = content.getOffsetHeight();
+ }
+
+ }
+
+ /**
+ * Adds the given {@link Section} as a tab in the {@link VDebugWindow} UI.
+ * {@link Section#getTabButton()} is called to obtain a button which is used
+ * tab.
+ *
+ * @param section
+ */
+ public void addSection(final Section section) {
+ Button b = section.getTabButton();
+ b.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ activateSection(section);
+ writeStoredState();
+ }
+ });
+ b.setStylePrimaryName(STYLENAME_TAB);
+ tabs.add(b);
+ sections.add(section);
+
+ if (activeSection == null) {
+ activateSection(section);
+ }
+ }
+
+ /**
+ * Activates the given {@link Section}
+ *
+ * @param section
+ */
+ void activateSection(Section section) {
+ if (section != null && section != activeSection) {
+ Highlight.hideAll();
+ // remove old stuff
+ if (activeSection != null) {
+ activeSection.hide();
+ content.remove(activeSection.getContent());
+ sectionHead.remove(activeSection.getControls());
+ }
+ // update tab styles
+ for (int i = 0; i < tabs.getWidgetCount(); i++) {
+ Widget tab = tabs.getWidget(i);
+ tab.setStyleDependentName(STYLENAME_SELECTED,
+ tab == section.getTabButton());
+ }
+ // add new stuff
+ content.add(section.getContent());
+ sectionHead.add(section.getControls());
+ activeSection = section;
+ activeSection.show();
+ }
+ }
+
+ void activateSection(int n) {
+ if (n < sections.size()) {
+ activateSection(sections.get(n));
+ }
+ }
+
+ /**
+ * Toggles the window between minimized and full states.
+ */
+ private void toggleMinimized() {
+ setMinimized(!minimized);
+ writeStoredState();
+ }
+
+ /**
+ * Sets whether or not the window is minimized.
+ *
+ * @param minimized
+ */
+ private void setMinimized(boolean minimized) {
+ this.minimized = minimized;
+
+ tabs.setVisible(!minimized);
+ content.setVisible(!minimized);
+ sectionHead.setVisible(!minimized);
+ menu.setVisible(!minimized);
+
+ applyPositionAndSize();
+ }
+
+ /**
+ * Sets the font size in use.
+ *
+ * @param size
+ */
+ private void setFontSize(int size) {
+ removeStyleDependentName("size" + fontSize);
+ fontSize = size;
+ addStyleDependentName("size" + size);
+ }
+
+ /**
+ * Gets the font size currently in use.
+ *
+ * @return
+ */
+ private int getFontSize() {
+ return fontSize;
+ }
+
+ /**
+ * Gets the milliseconds since application start.
+ *
+ * @return
+ */
+ static int getMillisSinceStart() {
+ return start.elapsedMillis();
+ }
+
+ /**
+ * Gets the milliseconds since last {@link #resetTimer()} call.
+ *
+ * @return
+ */
+ static int getMillisSinceReset() {
+ return lastReset.elapsedMillis();
+ }
+
+ /**
+ * Resets the timer.
+ *
+ * @return Milliseconds elapsed since the timer was last reset.
+ */
+ static int resetTimer() {
+ int sinceLast = lastReset.elapsedMillis();
+ lastReset = new Duration();
+ return sinceLast;
+ }
+
+ /**
+ * Gets a nicely formatted string with timing information suitable for
+ * display in tooltips.
+ *
+ * @param sinceStart
+ * @param sinceReset
+ * @return
+ */
+ static String getTimingTooltip(int sinceStart, int sinceReset) {
+ String title = formatDuration(sinceStart) + " since start";
+ title += ", &#10;" + formatDuration(sinceReset) + " since timer reset";
+ title += " &#10;@ "
+ + DateTimeFormat.getFormat("HH:mm:ss.SSS").format(new Date());
+ return title;
+ }
+
+ /**
+ * Formats the given milliseconds as hours, minutes, seconds and
+ * milliseconds.
+ *
+ * @param ms
+ * @return
+ */
+ static String formatDuration(int ms) {
+ NumberFormat fmt = NumberFormat.getFormat("00");
+ String seconds = fmt.format((ms / 1000) % 60);
+ String minutes = fmt.format((ms / (1000 * 60)) % 60);
+ String hours = fmt.format((ms / (1000 * 60 * 60)) % 24);
+
+ String millis = NumberFormat.getFormat("000").format(ms % 1000);
+
+ return hours + "h " + minutes + "m " + seconds + "s " + millis + "ms";
+ }
+
+ /**
+ * Called when the window is initialized.
+ */
+ public void init() {
+
+ show();
+ readStoredState();
+
+ Window.addResizeHandler(new com.google.gwt.event.logical.shared.ResizeHandler() {
+
+ Timer t = new Timer() {
+ @Override
+ public void run() {
+ applyPositionAndSize();
+ }
+ };
+
+ @Override
+ public void onResize(ResizeEvent event) {
+ t.cancel();
+ // TODO less
+ t.schedule(1000);
+ }
+ });
+ }
+
+ /**
+ * Called when the result from analyzeLayouts is received.
+ *
+ * @param ac
+ * @param meta
+ */
+ public void meta(ApplicationConnection ac, ValueMap meta) {
+ if (isClosed()) {
+ return;
+ }
+ for (Section s : sections) {
+ s.meta(ac, meta);
+ }
+ }
+
+ /**
+ * Called when a response is received
+ *
+ * @param ac
+ * @param uidl
+ */
+ public void uidl(ApplicationConnection ac, ValueMap uidl) {
+ if (isClosed()) {
+ return;
+ }
+ for (Section s : sections) {
+ s.uidl(ac, uidl);
+ }
+ }
+
+ /*
+ * Inner classes
+ */
+
+ /**
+ * Popup menu for {@link VDebugWindow}.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+ protected class Menu extends VOverlay {
+ FlowPanel content = new FlowPanel();
+
+ DebugButton[] sizes = new DebugButton[] {
+ new DebugButton(null, "Small", "A"),
+ new DebugButton(null, "Medium", "A"),
+ new DebugButton(null, "Large", "A") };
+
+ DebugButton[] modes = new DebugButton[] {
+ new DebugButton(Icon.DEVMODE_OFF,
+ "Debug only (causes page reload)"),
+ new DebugButton(Icon.DEVMODE_ON, "DevMode (causes page reload)"),
+ new DebugButton(Icon.DEVMODE_SUPER,
+ "SuperDevMode (causes page reload)") };
+
+ Menu() {
+ super(true, true);
+ setWidget(content);
+
+ setStylePrimaryName(STYLENAME + "-menu");
+ content.setStylePrimaryName(STYLENAME + "-menu-content");
+
+ FlowPanel size = new FlowPanel();
+ content.add(size);
+
+ final ClickHandler sizeHandler = new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ for (int i = 0; i < sizes.length; i++) {
+ Button b = sizes[i];
+ if (b == event.getSource()) {
+ setSize(i);
+ }
+ }
+ hide();
+ }
+ };
+ for (int i = 0; i < sizes.length; i++) {
+ Button b = sizes[i];
+ b.setStyleDependentName("size" + i, true);
+ b.addClickHandler(sizeHandler);
+ size.add(b);
+ }
+
+ FlowPanel mode = new FlowPanel();
+ content.add(mode);
+ final ClickHandler modeHandler = new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ for (int i = 0; i < modes.length; i++) {
+ Button b = modes[i];
+ if (b == event.getSource()) {
+ setDevMode(i);
+ }
+ }
+ hide();
+ }
+ };
+ modes[getDevMode()].setActive(true);
+ for (int i = 0; i < modes.length; i++) {
+ Button b = modes[i];
+ b.addClickHandler(modeHandler);
+ mode.add(b);
+ }
+
+ Button reset = new DebugButton(Icon.RESET, "Restore defaults.",
+ " Reset");
+ reset.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ resetStoredState();
+ readStoredState();
+ hide();
+ }
+ });
+ content.add(reset);
+ }
+
+ private void setSize(int size) {
+ for (int i = 0; i < sizes.length; i++) {
+ Button b = sizes[i];
+ b.setStyleDependentName(STYLENAME_ACTIVE, i == size);
+ }
+ setFontSize(size);
+ writeStoredState();
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ setSize(getFontSize());
+ }
+
+ private int getDevMode() {
+ if (Location.getParameter("superdevmode") != null) {
+ return 2;
+ } else if (Location.getParameter("gwt.codesvr") != null) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ private void setDevMode(int mode) {
+ UrlBuilder u = Location.createUrlBuilder();
+ switch (mode) {
+ case 2:
+ u.setParameter("superdevmode", "");
+ u.removeParameter("gwt.codesvr");
+ break;
+ case 1:
+ u.setParameter("gwt.codesvr", "localhost:9997");
+ u.removeParameter("superdevmode");
+ break;
+ default:
+ u.removeParameter("gwt.codesvr");
+ u.removeParameter("superdevmode");
+ }
+ Location.assign(u.buildString());
+ }
+
+ }
+
+ /**
+ * Handler for moving window.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+ protected class MoveHandler implements MouseDownHandler,
+ NativePreviewHandler {
+
+ HandlerRegistration handler;
+ int startX;
+ int startY;
+ int startTop;
+ int startLeft;
+
+ // moving stopped, remove handler on next event
+ boolean stop;
+
+ @Override
+ public void onPreviewNativeEvent(NativePreviewEvent event) {
+ if (event.getTypeInt() == Event.ONMOUSEMOVE && !stop
+ && hasMoved(event.getNativeEvent())) {
+ int dx = event.getNativeEvent().getClientX() - startX;
+ int dy = event.getNativeEvent().getClientY() - startY;
+
+ setPopupPosition(startLeft + dx, startTop + dy);
+ event.cancel();
+
+ } else if (event.getTypeInt() == Event.ONMOUSEUP) {
+ stop = true;
+ if (hasMoved(event.getNativeEvent())) {
+ event.cancel();
+ }
+
+ } else if (event.getTypeInt() == Event.ONCLICK) {
+ stop = true;
+ if (hasMoved(event.getNativeEvent())) {
+ event.cancel();
+ }
+
+ } else if (stop) {
+ stop = false;
+ handler.removeHandler();
+ handler = null;
+
+ readPositionAndSize();
+ writeStoredState();
+ }
+ }
+
+ private boolean hasMoved(NativeEvent event) {
+ return Math.abs(startX - event.getClientX()) > MOVE_TRESHOLD
+ || Math.abs(startY - event.getClientY()) > MOVE_TRESHOLD;
+ }
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ if (handler == null) {
+ handler = Event.addNativePreviewHandler(MoveHandler.this);
+ }
+ startX = event.getClientX();
+ startY = event.getClientY();
+ startLeft = getPopupLeft();
+ startTop = getPopupTop();
+ stop = false;
+ event.preventDefault();
+ }
+
+ }
+
+ /**
+ * Handler for resizing window.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+ protected class ResizeHandler implements MouseDownHandler,
+ MouseMoveHandler, NativePreviewHandler {
+
+ boolean resizeLeft;
+ boolean resizeRight;
+ boolean resizeUp;
+ boolean resizeDown;
+
+ boolean sizing;
+
+ HandlerRegistration dragHandler;
+
+ int startX;
+ int startY;
+ int startW;
+ int startH;
+ int startTop;
+ int startLeft;
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ sizing = updateResizeFlags(event);
+
+ if (sizing) {
+ startX = event.getClientX();
+ startY = event.getClientY();
+
+ startW = content.getOffsetWidth();
+ startH = content.getOffsetHeight();
+
+ startTop = getPopupTop();
+ startLeft = getPopupLeft();
+
+ dragHandler = Event.addNativePreviewHandler(this);
+
+ event.preventDefault();
+ }
+
+ }
+
+ @Override
+ public void onMouseMove(MouseMoveEvent event) {
+ updateResizeFlags(event);
+ updateCursor();
+ }
+
+ private void updateCursor() {
+ Element c = content.getElement();
+ if (resizeLeft) {
+ if (resizeUp) {
+ c.getStyle().setCursor(Cursor.NW_RESIZE);
+ } else if (resizeDown) {
+ c.getStyle().setCursor(Cursor.SW_RESIZE);
+ } else {
+ c.getStyle().setCursor(Cursor.W_RESIZE);
+ }
+ } else if (resizeRight) {
+ if (resizeUp) {
+ c.getStyle().setCursor(Cursor.NE_RESIZE);
+ } else if (resizeDown) {
+ c.getStyle().setCursor(Cursor.SE_RESIZE);
+ } else {
+ c.getStyle().setCursor(Cursor.E_RESIZE);
+ }
+ } else if (resizeUp) {
+ c.getStyle().setCursor(Cursor.N_RESIZE);
+ } else if (resizeDown) {
+ c.getStyle().setCursor(Cursor.S_RESIZE);
+ } else {
+ c.getStyle().setCursor(Cursor.AUTO);
+ }
+ }
+
+ private boolean updateResizeFlags(MouseEvent event) {
+ Element c = getElement();
+ int w = c.getOffsetWidth();
+ int h = c.getOffsetHeight() - head.getOffsetHeight();
+ int x = event.getRelativeX(c);
+ int y = event.getRelativeY(c) - head.getOffsetHeight();
+
+ resizeLeft = x < HANDLE_SIZE;
+ resizeRight = x > (w - HANDLE_SIZE);
+ resizeUp = y < HANDLE_SIZE;
+ resizeDown = y > (h - HANDLE_SIZE);
+
+ return resizeLeft || resizeRight || resizeUp || resizeDown;
+
+ }
+
+ @Override
+ public void onPreviewNativeEvent(NativePreviewEvent event) {
+ if (event.getTypeInt() == Event.ONMOUSEMOVE) {
+
+ int dx = event.getNativeEvent().getClientX() - startX;
+ int dy = event.getNativeEvent().getClientY() - startY;
+
+ int minw = tabs.getOffsetWidth() + controls.getOffsetWidth();
+ if (resizeLeft) {
+ int w = startW - dx;
+ if (w >= minw) {
+ content.setWidth(w + "px");
+ setPopupPosition(startLeft + dx, getPopupTop());
+ }
+ } else if (resizeRight) {
+ int w = startW + dx;
+ if (w >= minw) {
+ content.setWidth(w + "px");
+ }
+ }
+ if (resizeUp) {
+ int h = startH - dy;
+ if (h >= MIN_HEIGHT) {
+ content.setHeight(h + "px");
+ setPopupPosition(getPopupLeft(), startTop + dy);
+ }
+ } else if (resizeDown) {
+ int h = startH + dy;
+ if (h >= MIN_HEIGHT) {
+ content.setHeight(h + "px");
+ }
+ }
+
+ } else if (event.getTypeInt() == Event.ONMOUSEUP) {
+ dragHandler.removeHandler();
+ dragHandler = null;
+ content.getElement().getStyle().setCursor(Cursor.AUTO);
+ sizing = false;
+ readPositionAndSize();
+ writeStoredState();
+ }
+
+ event.cancel();
+ }
+
+ }
+
+}
diff --git a/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java b/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
index ce79b4c64c..8e6ad25407 100644
--- a/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
+++ b/client/src/com/vaadin/client/extensions/javascriptmanager/JavaScriptManagerConnector.java
@@ -23,8 +23,8 @@ import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.json.client.JSONArray;
import com.vaadin.client.ServerConnector;
-import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.communication.JavaScriptMethodInvocation;
+import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.extensions.AbstractExtensionConnector;
import com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc;
import com.vaadin.shared.extension.javascriptmanager.JavaScriptManagerState;
diff --git a/client/src/com/vaadin/client/metadata/Property.java b/client/src/com/vaadin/client/metadata/Property.java
index c0c375c14c..2e0ea49c88 100644
--- a/client/src/com/vaadin/client/metadata/Property.java
+++ b/client/src/com/vaadin/client/metadata/Property.java
@@ -88,4 +88,29 @@ public class Property {
return getSignature();
}
+ /**
+ * Gets the property name formatted for displaying in a user interface. This
+ * returns a string where e.g. "camelCase" has been converted to
+ * "Camel case".
+ *
+ * @return the name of this property, formatted for humans to read
+ */
+ public String getDisplayName() {
+ String camelCase = getName();
+ StringBuilder b = new StringBuilder(camelCase.length());
+ for (int i = 0; i < camelCase.length(); i++) {
+ char charAt = camelCase.charAt(i);
+ if (i == 0) {
+ // First char always upper case
+ b.append(Character.toUpperCase(charAt));
+ } else if (Character.isUpperCase(charAt)) {
+ b.append(' ');
+ b.append(Character.toLowerCase(charAt));
+ } else {
+ b.append(charAt);
+ }
+ }
+ return b.toString();
+ }
+
}
diff --git a/client/src/com/vaadin/client/metadata/TypeDataStore.java b/client/src/com/vaadin/client/metadata/TypeDataStore.java
index dff02749f8..aa37d75dc8 100644
--- a/client/src/com/vaadin/client/metadata/TypeDataStore.java
+++ b/client/src/com/vaadin/client/metadata/TypeDataStore.java
@@ -41,7 +41,6 @@ public class TypeDataStore {
private final FastStringSet delayedMethods = FastStringSet.create();
private final FastStringSet lastOnlyMethods = FastStringSet.create();
- private final FastStringSet hasGetTooltipInfo = FastStringSet.create();
private final FastStringMap<Type> returnTypes = FastStringMap.create();
private final FastStringMap<Invoker> invokers = FastStringMap.create();
@@ -291,22 +290,4 @@ public class TypeDataStore {
public static boolean hasProperties(Type type) {
return get().properties.containsKey(type.getSignature());
}
-
- /**
- * @deprecated As of 7.0.1. This is just a hack to avoid breaking backwards
- * compatibility and will be removed in Vaadin 7.1
- */
- @Deprecated
- public void setHasGetTooltipInfo(Class<?> clazz) {
- hasGetTooltipInfo.add(getType(clazz).getSignature());
- }
-
- /**
- * @deprecated As of 7.0.1. This is just a hack to avoid breaking backwards
- * compatibility and will be removed in Vaadin 7.1
- */
- @Deprecated
- public static boolean getHasGetTooltipInfo(Class clazz) {
- return get().hasGetTooltipInfo.contains(getType(clazz).getSignature());
- }
}
diff --git a/client/src/com/vaadin/client/ui/AbstractClickEventHandler.java b/client/src/com/vaadin/client/ui/AbstractClickEventHandler.java
index 2f97d30ece..e91abe9663 100644
--- a/client/src/com/vaadin/client/ui/AbstractClickEventHandler.java
+++ b/client/src/com/vaadin/client/ui/AbstractClickEventHandler.java
@@ -78,9 +78,8 @@ public abstract class AbstractClickEventHandler implements MouseDownHandler,
&& elementUnderMouse == lastMouseDownTarget) {
mouseUpPreviewMatched = true;
} else {
- VConsole.log("Ignoring mouseup from "
- + elementUnderMouse + " when mousedown was on "
- + lastMouseDownTarget);
+ VConsole.log("Ignoring mouseup from " + elementUnderMouse
+ + " when mousedown was on " + lastMouseDownTarget);
}
}
}
diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java
index ecd6abae08..13d1e6d56c 100644
--- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java
+++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java
@@ -35,7 +35,6 @@ import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.metadata.NoDataException;
import com.vaadin.client.metadata.Type;
import com.vaadin.client.metadata.TypeData;
-import com.vaadin.client.metadata.TypeDataStore;
import com.vaadin.client.ui.datefield.PopupDateFieldConnector;
import com.vaadin.client.ui.ui.UIConnector;
import com.vaadin.shared.AbstractComponentState;
@@ -205,11 +204,13 @@ public abstract class AbstractComponentConnector extends AbstractConnector
}
}
- private void updateComponentSize() {
- Profiler.enter("AbstractComponentConnector.updateComponentSize");
+ protected void updateComponentSize() {
+ updateComponentSize(getState().width == null ? "" : getState().width,
+ getState().height == null ? "" : getState().height);
+ }
- String newWidth = getState().width == null ? "" : getState().width;
- String newHeight = getState().height == null ? "" : getState().height;
+ protected void updateComponentSize(String newWidth, String newHeight) {
+ Profiler.enter("AbstractComponentConnector.updateComponentSize");
// Parent should be updated if either dimension changed between relative
// and non-relative
@@ -428,40 +429,13 @@ public abstract class AbstractComponentConnector extends AbstractConnector
}
}
- /**
- * {@inheritDoc}
- *
- * <p>
- * When overriding this method, {@link #hasTooltip()} should also be
- * overridden to return true in all situations where this method might
- * return a non-empty result.
- * </p>
- *
- * @see ComponentConnector#getTooltipInfo(Element)
- */
@Override
public TooltipInfo getTooltipInfo(Element element) {
return new TooltipInfo(getState().description, getState().errorMessage);
}
- /**
- * Check whether there might be a tooltip for this component. The framework
- * will only add event listeners for automatically handling tooltips (using
- * {@link #getTooltipInfo(Element)}) if this method returns true.
- *
- * @return <code>true</code> if some part of the component might have a
- * tooltip, otherwise <code>false</code>
- */
- private boolean hasTooltip() {
- /*
- * Hack to avoid breaking backwards compatibility - use a generator to
- * know whether there's a custom implementation of getTooltipInfo, and
- * in that case always assume that there might be tooltip.
- */
- if (TypeDataStore.getHasGetTooltipInfo(getClass())) {
- return true;
- }
-
+ @Override
+ public boolean hasTooltip() {
// Normally, there is a tooltip if description or errorMessage is set
AbstractComponentState state = getState();
if (state.description != null && !state.description.equals("")) {
diff --git a/client/src/com/vaadin/client/ui/AbstractConnector.java b/client/src/com/vaadin/client/ui/AbstractConnector.java
index 2c76aa93fe..6855c5cd2d 100644
--- a/client/src/com/vaadin/client/ui/AbstractConnector.java
+++ b/client/src/com/vaadin/client/ui/AbstractConnector.java
@@ -439,6 +439,7 @@ public abstract class AbstractConnector implements ServerConnector,
*
* @see com.vaadin.client.ServerConnector#hasEventListener(java.lang.String)
*/
+ @Override
public boolean hasEventListener(String eventIdentifier) {
Set<String> reg = getState().registeredEventListeners;
return (reg != null && reg.contains(eventIdentifier));
diff --git a/client/src/com/vaadin/client/ui/AbstractHasComponentsConnector.java b/client/src/com/vaadin/client/ui/AbstractHasComponentsConnector.java
index 4a6aefd082..d833f076e4 100644
--- a/client/src/com/vaadin/client/ui/AbstractHasComponentsConnector.java
+++ b/client/src/com/vaadin/client/ui/AbstractHasComponentsConnector.java
@@ -20,9 +20,9 @@ import java.util.List;
import com.google.gwt.event.shared.HandlerRegistration;
import com.vaadin.client.ComponentConnector;
-import com.vaadin.client.HasComponentsConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.ConnectorHierarchyChangeEvent.ConnectorHierarchyChangeHandler;
+import com.vaadin.client.HasComponentsConnector;
public abstract class AbstractHasComponentsConnector extends
AbstractComponentConnector implements HasComponentsConnector,
diff --git a/client/src/com/vaadin/client/ui/VAbsoluteLayout.java b/client/src/com/vaadin/client/ui/VAbsoluteLayout.java
index 88fbae6e88..dc080bcf7d 100644
--- a/client/src/com/vaadin/client/ui/VAbsoluteLayout.java
+++ b/client/src/com/vaadin/client/ui/VAbsoluteLayout.java
@@ -18,7 +18,6 @@ package com.vaadin.client.ui;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.ComplexPanel;
@@ -304,108 +303,43 @@ public class VAbsoluteLayout extends ComplexPanel {
* is added or removed
*/
public void layoutVertically() {
+ layout();
+ }
+
+ /**
+ * Performs an horizontal layout. Should be called when a widget is add or
+ * removed
+ */
+ public void layoutHorizontally() {
+ layout();
+ }
+
+ private void layout() {
for (Widget widget : getChildren()) {
if (widget instanceof AbsoluteWrapper) {
AbsoluteWrapper wrapper = (AbsoluteWrapper) widget;
-
- /*
- * Cleanup old wrappers which have been left empty by other
- * inner layouts moving the widget from the wrapper into their
- * own hierarchy. This usually happens when a call to
- * setWidget(widget) is done in an inner layout which
- * automatically detaches the widget from the parent, in this
- * case the wrapper, and re-attaches it somewhere else. This has
- * to be done in the layout phase since the order of the
- * hierarchy events are not defined.
- */
- if (wrapper.getWidget() == null) {
- wrapper.destroy();
- super.remove(wrapper);
- continue;
- }
-
- Style wrapperStyle = wrapper.getElement().getStyle();
- Style widgetStyle = wrapper.getWidget().getElement().getStyle();
-
- // Ensure previous heights do not affect the measures
- wrapperStyle.clearHeight();
-
- if (widgetStyle.getHeight() != null
- && widgetStyle.getHeight().endsWith("%")) {
- int h;
- if (wrapper.top != null && wrapper.bottom != null) {
- h = wrapper.getOffsetHeight();
- } else if (wrapper.bottom != null) {
- // top not defined, available space 0... bottom of
- // wrapper
- h = wrapper.getElement().getOffsetTop()
- + wrapper.getOffsetHeight();
- } else {
- // top defined or both undefined, available space ==
- // canvas - top
- h = canvas.getOffsetHeight()
- - wrapper.getElement().getOffsetTop();
- }
- wrapperStyle.setHeight(h, Unit.PX);
- }
-
wrapper.updateCaptionPosition();
}
}
}
/**
- * Performs an horizontal layout. Should be called when a widget is add or
- * removed
+ * Cleanup old wrappers which have been left empty by other inner layouts
+ * moving the widget from the wrapper into their own hierarchy. This usually
+ * happens when a call to setWidget(widget) is done in an inner layout which
+ * automatically detaches the widget from the parent, in this case the
+ * wrapper, and re-attaches it somewhere else. This has to be done in the
+ * layout phase since the order of the hierarchy events are not defined.
*/
- public void layoutHorizontally() {
+ public void cleanupWrappers() {
for (Widget widget : getChildren()) {
if (widget instanceof AbsoluteWrapper) {
AbsoluteWrapper wrapper = (AbsoluteWrapper) widget;
-
- /*
- * Cleanup old wrappers which have been left empty by other
- * inner layouts moving the widget from the wrapper into their
- * own hierarchy. This usually happens when a call to
- * setWidget(widget) is done in an inner layout which
- * automatically detaches the widget from the parent, in this
- * case the wrapper, and re-attaches it somewhere else. This has
- * to be done in the layout phase since the order of the
- * hierarchy events are not defined.
- */
if (wrapper.getWidget() == null) {
wrapper.destroy();
super.remove(wrapper);
continue;
}
-
- Style wrapperStyle = wrapper.getElement().getStyle();
- Style widgetStyle = wrapper.getWidget().getElement().getStyle();
-
- // Ensure previous heights do not affect the measures
- wrapperStyle.clearWidth();
-
- if (widgetStyle.getWidth() != null
- && widgetStyle.getWidth().endsWith("%")) {
- int w;
- if (wrapper.left != null && wrapper.right != null) {
- w = wrapper.getOffsetWidth();
- } else if (wrapper.right != null) {
- // left == null
- // available width == right edge == offsetleft + width
- w = wrapper.getOffsetWidth()
- + wrapper.getElement().getOffsetLeft();
- } else {
- // left != null && right == null || left == null &&
- // right == null
- // available width == canvas width - offset left
- w = canvas.getOffsetWidth()
- - wrapper.getElement().getOffsetLeft();
- }
- wrapperStyle.setWidth(w, Unit.PX);
- }
-
- wrapper.updateCaptionPosition();
}
}
}
diff --git a/client/src/com/vaadin/client/ui/VButton.java b/client/src/com/vaadin/client/ui/VButton.java
index decfb7c0cc..c67a9f8747 100644
--- a/client/src/com/vaadin/client/ui/VButton.java
+++ b/client/src/com/vaadin/client/ui/VButton.java
@@ -16,6 +16,7 @@
package com.vaadin.client.ui;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
@@ -25,7 +26,6 @@ import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.Accessibility;
import com.google.gwt.user.client.ui.FocusWidget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
@@ -103,7 +103,7 @@ public class VButton extends FocusWidget implements ClickHandler {
| Event.KEYEVENTS);
// Add a11y role "button"
- Accessibility.setRole(getElement(), Accessibility.ROLE_BUTTON);
+ Roles.getButtonRole().set(getElement());
getElement().appendChild(wrapper);
wrapper.appendChild(captionElement);
@@ -357,14 +357,14 @@ public class VButton extends FocusWidget implements ClickHandler {
this.enabled = enabled;
if (!enabled) {
cleanupCaptureState();
- Accessibility.removeState(getElement(),
- Accessibility.STATE_PRESSED);
+ Roles.getButtonRole().setAriaDisabledState(getElement(),
+ !enabled);
super.setTabIndex(-1);
} else {
- Accessibility.setState(getElement(),
- Accessibility.STATE_PRESSED, "false");
+ Roles.getButtonRole().removeAriaDisabledState(getElement());
super.setTabIndex(tabIndex);
}
+
}
}
diff --git a/client/src/com/vaadin/client/ui/VCalendar.java b/client/src/com/vaadin/client/ui/VCalendar.java
new file mode 100644
index 0000000000..c5c12f2d72
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/VCalendar.java
@@ -0,0 +1,1446 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.event.dom.client.ContextMenuHandler;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ui.calendar.schedule.CalendarDay;
+import com.vaadin.client.ui.calendar.schedule.CalendarEvent;
+import com.vaadin.client.ui.calendar.schedule.DayToolbar;
+import com.vaadin.client.ui.calendar.schedule.MonthGrid;
+import com.vaadin.client.ui.calendar.schedule.SimpleDayCell;
+import com.vaadin.client.ui.calendar.schedule.SimpleDayToolbar;
+import com.vaadin.client.ui.calendar.schedule.SimpleWeekToolbar;
+import com.vaadin.client.ui.calendar.schedule.WeekGrid;
+import com.vaadin.client.ui.calendar.schedule.WeeklyLongEvents;
+import com.vaadin.shared.ui.calendar.DateConstants;
+
+/**
+ * Client side implementation for Calendar
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class VCalendar extends Composite {
+
+ public static final String ATTR_FIRSTDAYOFWEEK = "firstDay";
+ public static final String ATTR_LASTDAYOFWEEK = "lastDay";
+ public static final String ATTR_FIRSTHOUROFDAY = "firstHour";
+ public static final String ATTR_LASTHOUROFDAY = "lastHour";
+
+ // private boolean hideWeekends;
+ private String[] monthNames;
+ private String[] dayNames;
+ private boolean format;
+ private final DockPanel outer = new DockPanel();
+ private int rows;
+
+ private boolean rangeSelectAllowed = true;
+ private boolean rangeMoveAllowed = true;
+ private boolean eventResizeAllowed = true;
+ private boolean eventMoveAllowed = true;
+
+ private final SimpleDayToolbar nameToolbar = new SimpleDayToolbar();
+
+ private final DayToolbar dayToolbar = new DayToolbar(this);
+ private final SimpleWeekToolbar weekToolbar;
+ private WeeklyLongEvents weeklyLongEvents;
+ private MonthGrid monthGrid;
+ private WeekGrid weekGrid;
+ private int intWidth = 0;
+ private int intHeight = 0;
+
+ protected final DateTimeFormat dateformat_datetime = DateTimeFormat
+ .getFormat("yyyy-MM-dd HH:mm:ss");
+ protected final DateTimeFormat dateformat_date = DateTimeFormat
+ .getFormat("yyyy-MM-dd");
+ protected final DateTimeFormat time12format_date = DateTimeFormat
+ .getFormat("h:mm a");
+ protected final DateTimeFormat time24format_date = DateTimeFormat
+ .getFormat("HH:mm");
+
+ private boolean readOnly = false;
+ private boolean disabled = false;
+
+ private boolean isHeightUndefined = false;
+
+ private boolean isWidthUndefined = false;
+ private int firstDay;
+ private int lastDay;
+ private int firstHour;
+ private int lastHour;
+
+ /**
+ * Listener interface for listening to event click events
+ */
+ public interface DateClickListener {
+ /**
+ * Triggered when a date was clicked
+ *
+ * @param date
+ * The date and time that was clicked
+ */
+ void dateClick(String date);
+ }
+
+ /**
+ * Listener interface for listening to week number click events
+ */
+ public interface WeekClickListener {
+ /**
+ * Called when a week number was selected.
+ *
+ * @param event
+ * The format of the vent string is "<year>w<week>"
+ */
+ void weekClick(String event);
+ }
+
+ /**
+ * Listener interface for listening to forward events
+ */
+ public interface ForwardListener {
+
+ /**
+ * Called when the calendar should move one view forward
+ */
+ void forward();
+ }
+
+ /**
+ * Listener interface for listening to backward events
+ */
+ public interface BackwardListener {
+
+ /**
+ * Called when the calendar should move one view backward
+ */
+ void backward();
+ }
+
+ /**
+ * Listener interface for listening to selection events
+ */
+ public interface RangeSelectListener {
+
+ /**
+ * Called when a user selected a new event by highlighting an area of
+ * the calendar.
+ *
+ * FIXME Fix the value nonsense.
+ *
+ * @param value
+ * The format of the value string is
+ * "<year>:<start-minutes>:<end-minutes>" if called from the
+ * {@link SimpleWeekToolbar} and "<yyyy-MM-dd>TO<yyyy-MM-dd>"
+ * if called from {@link MonthGrid}
+ */
+ void rangeSelected(String value);
+ }
+
+ /**
+ * Listener interface for listening to click events
+ */
+ public interface EventClickListener {
+ /**
+ * Called when an event was clicked
+ *
+ * @param event
+ * The event that was clicked
+ */
+ void eventClick(CalendarEvent event);
+ }
+
+ /**
+ * Listener interface for listening to event moved events. Occurs when a
+ * user drags an event to a new position
+ */
+ public interface EventMovedListener {
+ /**
+ * Triggered when an event was dragged to a new position and the start
+ * and end dates was changed
+ *
+ * @param event
+ * The event that was moved
+ */
+ void eventMoved(CalendarEvent event);
+ }
+
+ /**
+ * Listener interface for when an event gets resized (its start or end date
+ * changes)
+ */
+ public interface EventResizeListener {
+ /**
+ * Triggers when the time limits for the event was changed.
+ *
+ * @param event
+ * The event that was changed. The new time limits have been
+ * updated in the event before calling this method
+ */
+ void eventResized(CalendarEvent event);
+ }
+
+ /**
+ * Listener interface for listening to scroll events.
+ */
+ public interface ScrollListener {
+ /**
+ * Triggered when the calendar is scrolled
+ *
+ * @param scrollPosition
+ * The scroll position in pixels as returned by
+ * {@link ScrollPanel#getScrollPosition()}
+ */
+ void scroll(int scrollPosition);
+ }
+
+ /**
+ * Listener interface for listening to mouse events.
+ */
+ public interface MouseEventListener {
+ /**
+ * Triggered when a user wants an context menu
+ *
+ * @param event
+ * The context menu event
+ *
+ * @param widget
+ * The widget that the context menu should be added to
+ */
+ void contextMenu(ContextMenuEvent event, Widget widget);
+ }
+
+ /**
+ * Default constructor
+ */
+ public VCalendar() {
+ weekToolbar = new SimpleWeekToolbar(this);
+ initWidget(outer);
+ setStylePrimaryName("v-calendar");
+ blockSelect(getElement());
+ }
+
+ /**
+ * Hack for IE to not select text when dragging.
+ *
+ * @param e
+ * The element to apply the hack on
+ */
+ private native void blockSelect(Element e)
+ /*-{
+ e.onselectstart = function() {
+ return false;
+ }
+
+ e.ondragstart = function() {
+ return false;
+ }
+ }-*/;
+
+ private void updateEventsToWeekGrid(CalendarEvent[] events) {
+ List<CalendarEvent> allDayLong = new ArrayList<CalendarEvent>();
+ List<CalendarEvent> belowDayLong = new ArrayList<CalendarEvent>();
+
+ for (CalendarEvent e : events) {
+ if (e.isAllDay()) {
+ // Event is set on one "allDay" event or more than one.
+ allDayLong.add(e);
+
+ } else {
+ // Event is set only on one day.
+ belowDayLong.add(e);
+ }
+ }
+
+ weeklyLongEvents.addEvents(allDayLong);
+
+ for (CalendarEvent e : belowDayLong) {
+ weekGrid.addEvent(e);
+ }
+ }
+
+ /**
+ * Adds events to the month grid
+ *
+ * @param events
+ * The events to add
+ * @param drawImmediately
+ * Should the grid be rendered immediately. (currently not in
+ * use)
+ *
+ */
+ public void updateEventsToMonthGrid(Collection<CalendarEvent> events,
+ boolean drawImmediately) {
+ for (CalendarEvent e : sortEventsByDuration(events)) {
+ // FIXME Why is drawImmediately not used ?????
+ addEventToMonthGrid(e, false);
+ }
+ }
+
+ private void addEventToMonthGrid(CalendarEvent e, boolean renderImmediately) {
+ Date when = e.getStart();
+ Date to = e.getEnd();
+ boolean eventAdded = false;
+ boolean inProgress = false; // Event adding has started
+ boolean eventMoving = false;
+ List<SimpleDayCell> dayCells = new ArrayList<SimpleDayCell>();
+ List<SimpleDayCell> timeCells = new ArrayList<SimpleDayCell>();
+ for (int row = 0; row < monthGrid.getRowCount(); row++) {
+ if (eventAdded) {
+ break;
+ }
+ for (int cell = 0; cell < monthGrid.getCellCount(row); cell++) {
+ SimpleDayCell sdc = (SimpleDayCell) monthGrid.getWidget(row,
+ cell);
+ if (isEventInDay(when, to, sdc.getDate())
+ && isEventInDayWithTime(when, to, sdc.getDate(),
+ e.getEndTime(), e.isAllDay())) {
+ if (!eventMoving) {
+ eventMoving = sdc.getMoveEvent() != null;
+ }
+ long d = e.getRangeInMilliseconds();
+ if ((d > 0 && d <= DateConstants.DAYINMILLIS)
+ && !e.isAllDay()) {
+ timeCells.add(sdc);
+ } else {
+ dayCells.add(sdc);
+ }
+ inProgress = true;
+ continue;
+ } else if (inProgress) {
+ eventAdded = true;
+ inProgress = false;
+ break;
+ }
+ }
+ }
+
+ updateEventSlotIndex(e, dayCells);
+ updateEventSlotIndex(e, timeCells);
+
+ for (SimpleDayCell sdc : dayCells) {
+ sdc.addCalendarEvent(e);
+ }
+ for (SimpleDayCell sdc : timeCells) {
+ sdc.addCalendarEvent(e);
+ }
+
+ if (renderImmediately) {
+ reDrawAllMonthEvents(!eventMoving);
+ }
+ }
+
+ /*
+ * We must also handle the special case when the event lasts exactly for 24
+ * hours, thus spanning two days e.g. from 1.1.2001 00:00 to 2.1.2001 00:00.
+ * That special case still should span one day when rendered.
+ */
+ @SuppressWarnings("deprecation")
+ // Date methods are not deprecated in GWT
+ private boolean isEventInDayWithTime(Date from, Date to, Date date,
+ Date endTime, boolean isAllDay) {
+ return (isAllDay || !(to.getDay() == date.getDay()
+ && from.getDay() != to.getDay() && isMidnight(endTime)));
+ }
+
+ private void updateEventSlotIndex(CalendarEvent e, List<SimpleDayCell> cells) {
+ if (cells.isEmpty()) {
+ return;
+ }
+
+ if (e.getSlotIndex() == -1) {
+ // Update slot index
+ int newSlot = -1;
+ for (SimpleDayCell sdc : cells) {
+ int slot = sdc.getEventCount();
+ if (slot > newSlot) {
+ newSlot = slot;
+ }
+ }
+ newSlot++;
+
+ for (int i = 0; i < newSlot; i++) {
+ // check for empty slot
+ if (isSlotEmpty(e, i, cells)) {
+ newSlot = i;
+ break;
+ }
+ }
+ e.setSlotIndex(newSlot);
+ }
+ }
+
+ private void reDrawAllMonthEvents(boolean clearCells) {
+ for (int row = 0; row < monthGrid.getRowCount(); row++) {
+ for (int cell = 0; cell < monthGrid.getCellCount(row); cell++) {
+ SimpleDayCell sdc = (SimpleDayCell) monthGrid.getWidget(row,
+ cell);
+ sdc.reDraw(clearCells);
+ }
+ }
+ }
+
+ private boolean isSlotEmpty(CalendarEvent addedEvent, int slotIndex,
+ List<SimpleDayCell> cells) {
+ for (SimpleDayCell sdc : cells) {
+ CalendarEvent e = sdc.getCalendarEvent(slotIndex);
+ if (e != null && !e.equals(addedEvent)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Remove a month event from the view
+ *
+ * @param target
+ * The event to remove
+ *
+ * @param repaintImmediately
+ * Should we repaint after the event was removed?
+ */
+ public void removeMonthEvent(CalendarEvent target,
+ boolean repaintImmediately) {
+ if (target != null && target.getSlotIndex() >= 0) {
+ // Remove event
+ for (int row = 0; row < monthGrid.getRowCount(); row++) {
+ for (int cell = 0; cell < monthGrid.getCellCount(row); cell++) {
+ SimpleDayCell sdc = (SimpleDayCell) monthGrid.getWidget(
+ row, cell);
+ if (sdc == null) {
+ return;
+ }
+ sdc.removeEvent(target, repaintImmediately);
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates an event in the month grid
+ *
+ * @param changedEvent
+ * The event that has changed
+ */
+ public void updateEventToMonthGrid(CalendarEvent changedEvent) {
+ removeMonthEvent(changedEvent, true);
+ changedEvent.setSlotIndex(-1);
+ addEventToMonthGrid(changedEvent, true);
+ }
+
+ /**
+ * Sort the event by how long they are
+ *
+ * @param events
+ * The events to sort
+ * @return An array where the events has been sorted
+ */
+ public CalendarEvent[] sortEventsByDuration(Collection<CalendarEvent> events) {
+ CalendarEvent[] sorted = events
+ .toArray(new CalendarEvent[events.size()]);
+ Arrays.sort(sorted, getEventComparator());
+ return sorted;
+ }
+
+ /*
+ * Check if the given event occurs at the given date.
+ */
+ private boolean isEventInDay(Date eventWhen, Date eventTo, Date gridDate) {
+ if (eventWhen.compareTo(gridDate) <= 0
+ && eventTo.compareTo(gridDate) >= 0) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Re-render the week grid
+ *
+ * @param daysCount
+ * The amount of days to include in the week
+ * @param days
+ * The days
+ * @param today
+ * Todays date
+ * @param realDayNames
+ * The names of the dates
+ */
+ @SuppressWarnings("deprecation")
+ public void updateWeekGrid(int daysCount, List<CalendarDay> days,
+ Date today, String[] realDayNames) {
+ weekGrid.setFirstHour(getFirstHourOfTheDay());
+ weekGrid.setLastHour(getLastHourOfTheDay());
+ weekGrid.getTimeBar().updateTimeBar(is24HFormat());
+
+ dayToolbar.clear();
+ dayToolbar.addBackButton();
+ dayToolbar.setVerticalSized(isHeightUndefined);
+ dayToolbar.setHorizontalSized(isWidthUndefined);
+ weekGrid.clearDates();
+ weekGrid.setDisabled(isDisabledOrReadOnly());
+
+ for (CalendarDay day : days) {
+ String date = day.getDate();
+ String localized_date_format = day.getLocalizedDateFormat();
+ Date d = dateformat_date.parse(date);
+ int dayOfWeek = day.getDayOfWeek();
+ if (dayOfWeek < getFirstDayNumber()
+ || dayOfWeek > getLastDayNumber()) {
+ continue;
+ }
+ boolean isToday = false;
+ int dayOfMonth = d.getDate();
+ if (today.getDate() == dayOfMonth && today.getYear() == d.getYear()
+ && today.getMonth() == d.getMonth()) {
+ isToday = true;
+ }
+ dayToolbar.add(realDayNames[dayOfWeek - 1], date,
+ localized_date_format, isToday ? "today" : null);
+ weeklyLongEvents.addDate(d);
+ weekGrid.addDate(d);
+ if (isToday) {
+ weekGrid.setToday(d, today);
+ }
+ }
+ dayToolbar.addNextButton();
+ }
+
+ /**
+ * Updates the events in the Month view
+ *
+ * @param daysCount
+ * How many days there are
+ * @param daysUidl
+ *
+ * @param today
+ * Todays date
+ */
+ @SuppressWarnings("deprecation")
+ public void updateMonthGrid(int daysCount, List<CalendarDay> days,
+ Date today) {
+ int columns = getLastDayNumber() - getFirstDayNumber() + 1;
+ rows = (int) Math.ceil(daysCount / (double) 7);
+
+ monthGrid = new MonthGrid(this, rows, columns);
+ monthGrid.setEnabled(!isDisabledOrReadOnly());
+ weekToolbar.removeAllRows();
+ int pos = 0;
+ boolean monthNameDrawn = true;
+ boolean firstDayFound = false;
+ boolean lastDayFound = false;
+
+ for (CalendarDay day : days) {
+ String date = day.getDate();
+ Date d = dateformat_date.parse(date);
+ int dayOfWeek = day.getDayOfWeek();
+ int week = day.getWeek();
+
+ int dayOfMonth = d.getDate();
+
+ // reset at start of each month
+ if (dayOfMonth == 1) {
+ monthNameDrawn = false;
+ if (firstDayFound) {
+ lastDayFound = true;
+ }
+ firstDayFound = true;
+ }
+
+ if (dayOfWeek < getFirstDayNumber()
+ || dayOfWeek > getLastDayNumber()) {
+ continue;
+ }
+ int y = (pos / columns);
+ int x = pos - (y * columns);
+ if (x == 0 && daysCount > 7) {
+ // Add week to weekToolbar for navigation
+ weekToolbar.addWeek(week, d.getYear());
+ }
+ final SimpleDayCell cell = new SimpleDayCell(this, y, x);
+ cell.setMonthGrid(monthGrid);
+ cell.setDate(d);
+ cell.addDomHandler(new ContextMenuHandler() {
+ @Override
+ public void onContextMenu(ContextMenuEvent event) {
+ if (mouseEventListener != null) {
+ event.preventDefault();
+ event.stopPropagation();
+ mouseEventListener.contextMenu(event, cell);
+ }
+ }
+ }, ContextMenuEvent.getType());
+
+ if (!firstDayFound) {
+ cell.addStyleDependentName("prev-month");
+ } else if (lastDayFound) {
+ cell.addStyleDependentName("next-month");
+ }
+
+ if (dayOfMonth >= 1 && !monthNameDrawn) {
+ cell.setMonthNameVisible(true);
+ monthNameDrawn = true;
+ }
+
+ if (today.getDate() == dayOfMonth && today.getYear() == d.getYear()
+ && today.getMonth() == d.getMonth()) {
+ cell.setToday(true);
+
+ }
+ monthGrid.setWidget(y, x, cell);
+ pos++;
+ }
+ }
+
+ public void setSizeForChildren(int newWidth, int newHeight) {
+ intWidth = newWidth;
+ intHeight = newHeight;
+ isWidthUndefined = intWidth == -1;
+ dayToolbar.setVerticalSized(isHeightUndefined);
+ dayToolbar.setHorizontalSized(isWidthUndefined);
+ recalculateWidths();
+ recalculateHeights();
+ }
+
+ /**
+ * Recalculates the heights of the sub-components in the calendar
+ */
+ protected void recalculateHeights() {
+ if (monthGrid != null) {
+
+ if (intHeight == -1) {
+ monthGrid.addStyleDependentName("sizedheight");
+ } else {
+ monthGrid.removeStyleDependentName("sizedheight");
+ }
+
+ monthGrid.updateCellSizes(intWidth - weekToolbar.getOffsetWidth(),
+ intHeight - nameToolbar.getOffsetHeight());
+ weekToolbar.setHeightPX((intHeight == -1) ? intHeight : intHeight
+ - nameToolbar.getOffsetHeight());
+
+ } else if (weekGrid != null) {
+ weekGrid.setHeightPX((intHeight == -1) ? intHeight : intHeight
+ - weeklyLongEvents.getOffsetHeight()
+ - dayToolbar.getOffsetHeight());
+ }
+ }
+
+ /**
+ * Recalculates the widths of the sub-components in the calendar
+ */
+ protected void recalculateWidths() {
+ if (!isWidthUndefined) {
+ nameToolbar.setWidthPX(intWidth);
+ dayToolbar.setWidthPX(intWidth);
+
+ if (monthGrid != null) {
+ monthGrid.updateCellSizes(
+ intWidth - weekToolbar.getOffsetWidth(), intHeight
+ - nameToolbar.getOffsetHeight());
+ } else if (weekGrid != null) {
+ weekGrid.setWidthPX(intWidth);
+ weeklyLongEvents.setWidthPX(weekGrid.getInternalWidth());
+ }
+ } else {
+ dayToolbar.setWidthPX(intWidth);
+ nameToolbar.setWidthPX(intWidth);
+
+ if (monthGrid != null) {
+ if (intWidth == -1) {
+ monthGrid.addStyleDependentName("sizedwidth");
+
+ } else {
+ monthGrid.removeStyleDependentName("sizedwidth");
+ }
+ } else if (weekGrid != null) {
+ weekGrid.setWidthPX(intWidth);
+ weeklyLongEvents.setWidthPX(weekGrid.getInternalWidth());
+ }
+ }
+ }
+
+ /**
+ * Get the date format used to format dates only (excludes time)
+ *
+ * @return
+ */
+ public DateTimeFormat getDateFormat() {
+ return dateformat_date;
+ }
+
+ /**
+ * Get the time format used to format time only (excludes date)
+ *
+ * @return
+ */
+ public DateTimeFormat getTimeFormat() {
+ if (is24HFormat()) {
+ return time24format_date;
+ }
+ return time12format_date;
+ }
+
+ /**
+ * Get the date and time format to format the dates (includes both date and
+ * time)
+ *
+ * @return
+ */
+ public DateTimeFormat getDateTimeFormat() {
+ return dateformat_datetime;
+ }
+
+ /**
+ * Is the calendar either disabled or readonly
+ *
+ * @return
+ */
+ public boolean isDisabledOrReadOnly() {
+ return disabled || readOnly;
+ }
+
+ /**
+ * Is the component disabled
+ */
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ /**
+ * Is the component disabled
+ *
+ * @param disabled
+ * True if disabled
+ */
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ /**
+ * Is the component read-only
+ */
+ public boolean isReadOnly() {
+ return readOnly;
+ }
+
+ /**
+ * Is the component read-only
+ *
+ * @param readOnly
+ * True if component is readonly
+ */
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ }
+
+ /**
+ * Get the month grid component
+ *
+ * @return
+ */
+ public MonthGrid getMonthGrid() {
+ return monthGrid;
+ }
+
+ /**
+ * Get he week grid component
+ *
+ * @return
+ */
+ public WeekGrid getWeekGrid() {
+ return weekGrid;
+ }
+
+ /**
+ * Calculates correct size for all cells (size / amount of cells ) and
+ * distributes any overflow over all the cells.
+ *
+ * @param totalSize
+ * the total amount of size reserved for all cells
+ * @param numberOfCells
+ * the number of cells
+ * @param sizeModifier
+ * a modifier which is applied to all cells before distributing
+ * the overflow
+ * @return an integer array that contains the correct size for each cell
+ */
+ public static int[] distributeSize(int totalSize, int numberOfCells,
+ int sizeModifier) {
+ int[] cellSizes = new int[numberOfCells];
+ int startingSize = totalSize / numberOfCells;
+ int cellSizeOverFlow = totalSize % numberOfCells;
+
+ for (int i = 0; i < numberOfCells; i++) {
+ cellSizes[i] = startingSize + sizeModifier;
+ }
+
+ // distribute size overflow amongst all slots
+ int j = 0;
+ while (cellSizeOverFlow > 0) {
+ cellSizes[j]++;
+ cellSizeOverFlow--;
+ j++;
+ if (j >= numberOfCells) {
+ j = 0;
+ }
+ }
+
+ // cellSizes[numberOfCells - 1] += cellSizeOverFlow;
+
+ return cellSizes;
+ }
+
+ /**
+ * Returns a comparator which can compare calendar events.
+ *
+ * @return
+ */
+ public static Comparator<CalendarEvent> getEventComparator() {
+ return new Comparator<CalendarEvent>() {
+
+ @Override
+ public int compare(CalendarEvent o1, CalendarEvent o2) {
+ if (o1.isAllDay() != o2.isAllDay()) {
+ if (o2.isAllDay()) {
+ return 1;
+ }
+ return -1;
+ }
+
+ Long d1 = o1.getRangeInMilliseconds();
+ Long d2 = o2.getRangeInMilliseconds();
+ int r = 0;
+ if (!d1.equals(0L) && !d2.equals(0L)) {
+ r = d2.compareTo(d1);
+ return (r == 0) ? ((Integer) o2.getIndex()).compareTo(o1
+ .getIndex()) : r;
+ }
+
+ if (d2.equals(0L) && d1.equals(0L)) {
+ return ((Integer) o2.getIndex()).compareTo(o1.getIndex());
+ } else if (d2.equals(0L) && d1 >= DateConstants.DAYINMILLIS) {
+ return -1;
+ } else if (d2.equals(0L) && d1 < DateConstants.DAYINMILLIS) {
+ return 1;
+ } else if (d1.equals(0L) && d2 >= DateConstants.DAYINMILLIS) {
+ return 1;
+ } else if (d1.equals(0L) && d2 < DateConstants.DAYINMILLIS) {
+ return -1;
+ }
+ r = d2.compareTo(d1);
+ return (r == 0) ? ((Integer) o2.getIndex()).compareTo(o1
+ .getIndex()) : r;
+ }
+ };
+ }
+
+ /**
+ * Is the date at midnight
+ *
+ * @param date
+ * The date to check
+ *
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ public static boolean isMidnight(Date date) {
+ return (date.getHours() == 0 && date.getMinutes() == 0 && date
+ .getSeconds() == 0);
+ }
+
+ /**
+ * Are the dates equal (uses second resolution)
+ *
+ * @param date1
+ * The first the to compare
+ * @param date2
+ * The second date to compare
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ public static boolean areDatesEqualToSecond(Date date1, Date date2) {
+ return date1.getYear() == date2.getYear()
+ && date1.getMonth() == date2.getMonth()
+ && date1.getDay() == date2.getDay()
+ && date1.getHours() == date2.getHours()
+ && date1.getSeconds() == date2.getSeconds();
+ }
+
+ /**
+ * Is the calendar event zero seconds long and is occurring at midnight
+ *
+ * @param event
+ * The event to check
+ * @return
+ */
+ public static boolean isZeroLengthMidnightEvent(CalendarEvent event) {
+ return areDatesEqualToSecond(event.getStartTime(), event.getEndTime())
+ && isMidnight(event.getEndTime());
+ }
+
+ /**
+ * Should the 24h time format be used
+ *
+ * @param format
+ * True if the 24h format should be used else the 12h format is
+ * used
+ */
+ public void set24HFormat(boolean format) {
+ this.format = format;
+ }
+
+ /**
+ * Is the 24h time format used
+ */
+ public boolean is24HFormat() {
+ return format;
+ }
+
+ /**
+ * Set the names of the week days
+ *
+ * @param names
+ * The names of the days (Monday, Thursday,...)
+ */
+ public void setDayNames(String[] names) {
+ assert (names.length == 7);
+ dayNames = names;
+ }
+
+ /**
+ * Get the names of the week days
+ */
+ public String[] getDayNames() {
+ return dayNames;
+ }
+
+ /**
+ * Set the names of the months
+ *
+ * @param names
+ * The names of the months (January, February,...)
+ */
+ public void setMonthNames(String[] names) {
+ assert (names.length == 12);
+ monthNames = names;
+ }
+
+ /**
+ * Get the month names
+ */
+ public String[] getMonthNames() {
+ return monthNames;
+ }
+
+ /**
+ * Set the number when a week starts
+ *
+ * @param dayNumber
+ * The number of the day
+ */
+ public void setFirstDayNumber(int dayNumber) {
+ assert (dayNumber >= 1 && dayNumber <= 7);
+ firstDay = dayNumber;
+ }
+
+ /**
+ * Get the number when a week starts
+ */
+ public int getFirstDayNumber() {
+ return firstDay;
+ }
+
+ /**
+ * Set the number when a week ends
+ *
+ * @param dayNumber
+ * The number of the day
+ */
+ public void setLastDayNumber(int dayNumber) {
+ assert (dayNumber >= 1 && dayNumber <= 7);
+ lastDay = dayNumber;
+ }
+
+ /**
+ * Get the number when a week ends
+ */
+ public int getLastDayNumber() {
+ return lastDay;
+ }
+
+ /**
+ * Set the number when a week starts
+ *
+ * @param dayNumber
+ * The number of the day
+ */
+ public void setFirstHourOfTheDay(int hour) {
+ assert (hour >= 0 && hour <= 23);
+ firstHour = hour;
+ }
+
+ /**
+ * Get the number when a week starts
+ */
+ public int getFirstHourOfTheDay() {
+ return firstHour;
+ }
+
+ /**
+ * Set the number when a week ends
+ *
+ * @param dayNumber
+ * The number of the day
+ */
+ public void setLastHourOfTheDay(int hour) {
+ assert (hour >= 0 && hour <= 23);
+ lastHour = hour;
+ }
+
+ /**
+ * Get the number when a week ends
+ */
+ public int getLastHourOfTheDay() {
+ return lastHour;
+ }
+
+ /**
+ * Re-renders the whole week view
+ *
+ * @param scroll
+ * The amount of pixels to scroll the week view
+ * @param today
+ * Todays date
+ * @param daysInMonth
+ * How many days are there in the month
+ * @param firstDayOfWeek
+ * The first day of the week
+ * @param events
+ * The events to render
+ */
+ public void updateWeekView(int scroll, Date today, int daysInMonth,
+ int firstDayOfWeek, Collection<CalendarEvent> events,
+ List<CalendarDay> days) {
+
+ while (outer.getWidgetCount() > 0) {
+ outer.remove(0);
+ }
+
+ monthGrid = null;
+ String[] realDayNames = new String[getDayNames().length];
+ int j = 0;
+
+ if (firstDayOfWeek == 2) {
+ for (int i = 1; i < getDayNames().length; i++) {
+ realDayNames[j++] = getDayNames()[i];
+ }
+ realDayNames[j] = getDayNames()[0];
+ } else {
+ for (int i = 0; i < getDayNames().length; i++) {
+ realDayNames[j++] = getDayNames()[i];
+ }
+
+ }
+
+ weeklyLongEvents = new WeeklyLongEvents(this);
+ if (weekGrid == null) {
+ weekGrid = new WeekGrid(this, is24HFormat());
+ }
+ updateWeekGrid(daysInMonth, days, today, realDayNames);
+ updateEventsToWeekGrid(sortEventsByDuration(events));
+ outer.add(dayToolbar, DockPanel.NORTH);
+ outer.add(weeklyLongEvents, DockPanel.NORTH);
+ outer.add(weekGrid, DockPanel.SOUTH);
+ weekGrid.setVerticalScrollPosition(scroll);
+ }
+
+ /**
+ * Re-renders the whole month view
+ *
+ * @param firstDayOfWeek
+ * The first day of the week
+ * @param today
+ * Todays date
+ * @param daysInMonth
+ * Amount of days in the month
+ * @param events
+ * The events to render
+ * @param days
+ * The day information
+ */
+ public void updateMonthView(int firstDayOfWeek, Date today,
+ int daysInMonth, Collection<CalendarEvent> events,
+ List<CalendarDay> days) {
+
+ // Remove all week numbers from bar
+ while (outer.getWidgetCount() > 0) {
+ outer.remove(0);
+ }
+
+ int firstDay = getFirstDayNumber();
+ int lastDay = getLastDayNumber();
+ int daysPerWeek = lastDay - firstDay + 1;
+ int j = 0;
+
+ String[] dayNames = getDayNames();
+ String[] realDayNames = new String[daysPerWeek];
+
+ if (firstDayOfWeek == 2) {
+ for (int i = firstDay; i < lastDay + 1; i++) {
+ if (i == 7) {
+ realDayNames[j++] = dayNames[0];
+ } else {
+ realDayNames[j++] = dayNames[i];
+ }
+ }
+ } else {
+ for (int i = firstDay - 1; i < lastDay; i++) {
+ realDayNames[j++] = dayNames[i];
+ }
+ }
+
+ nameToolbar.setDayNames(realDayNames);
+
+ weeklyLongEvents = null;
+ weekGrid = null;
+
+ updateMonthGrid(daysInMonth, days, today);
+
+ outer.add(nameToolbar, DockPanel.NORTH);
+ outer.add(weekToolbar, DockPanel.WEST);
+ weekToolbar.updateCellHeights();
+ outer.add(monthGrid, DockPanel.CENTER);
+
+ updateEventsToMonthGrid(events, false);
+ }
+
+ private DateClickListener dateClickListener;
+
+ /**
+ * Sets the listener for listening to event clicks
+ *
+ * @param listener
+ * The listener to use
+ */
+ public void setListener(DateClickListener listener) {
+ dateClickListener = listener;
+ }
+
+ /**
+ * Gets the listener for listening to event clicks
+ *
+ * @return
+ */
+ public DateClickListener getDateClickListener() {
+ return dateClickListener;
+ }
+
+ private ForwardListener forwardListener;
+
+ /**
+ * Set the listener which listens to forward events from the calendar
+ *
+ * @param listener
+ * The listener to use
+ */
+ public void setListener(ForwardListener listener) {
+ forwardListener = listener;
+ }
+
+ /**
+ * Get the listener which listens to forward events from the calendar
+ *
+ * @return
+ */
+ public ForwardListener getForwardListener() {
+ return forwardListener;
+ }
+
+ private BackwardListener backwardListener;
+
+ /**
+ * Set the listener which listens to backward events from the calendar
+ *
+ * @param listener
+ * The listener to use
+ */
+ public void setListener(BackwardListener listener) {
+ backwardListener = listener;
+ }
+
+ /**
+ * Set the listener which listens to backward events from the calendar
+ *
+ * @return
+ */
+ public BackwardListener getBackwardListener() {
+ return backwardListener;
+ }
+
+ private WeekClickListener weekClickListener;
+
+ /**
+ * Set the listener that listens to user clicking on the week numbers
+ *
+ * @param listener
+ * The listener to use
+ */
+ public void setListener(WeekClickListener listener) {
+ weekClickListener = listener;
+ }
+
+ /**
+ * Get the listener that listens to user clicking on the week numbers
+ *
+ * @return
+ */
+ public WeekClickListener getWeekClickListener() {
+ return weekClickListener;
+ }
+
+ private RangeSelectListener rangeSelectListener;
+
+ /**
+ * Set the listener that listens to the user highlighting a region in the
+ * calendar
+ *
+ * @param listener
+ * The listener to use
+ */
+ public void setListener(RangeSelectListener listener) {
+ rangeSelectListener = listener;
+ }
+
+ /**
+ * Get the listener that listens to the user highlighting a region in the
+ * calendar
+ *
+ * @return
+ */
+ public RangeSelectListener getRangeSelectListener() {
+ return rangeSelectListener;
+ }
+
+ private EventClickListener eventClickListener;
+
+ /**
+ * Get the listener that listens to the user clicking on the events
+ */
+ public EventClickListener getEventClickListener() {
+ return eventClickListener;
+ }
+
+ /**
+ * Set the listener that listens to the user clicking on the events
+ *
+ * @param listener
+ * The listener to use
+ */
+ public void setListener(EventClickListener listener) {
+ eventClickListener = listener;
+ }
+
+ private EventMovedListener eventMovedListener;
+
+ /**
+ * Get the listener that listens to when event is dragged to a new location
+ *
+ * @return
+ */
+ public EventMovedListener getEventMovedListener() {
+ return eventMovedListener;
+ }
+
+ /**
+ * Set the listener that listens to when event is dragged to a new location
+ *
+ * @param eventMovedListener
+ * The listener to use
+ */
+ public void setListener(EventMovedListener eventMovedListener) {
+ this.eventMovedListener = eventMovedListener;
+ }
+
+ private ScrollListener scrollListener;
+
+ /**
+ * Get the listener that listens to when the calendar widget is scrolled
+ *
+ * @return
+ */
+ public ScrollListener getScrollListener() {
+ return scrollListener;
+ }
+
+ /**
+ * Set the listener that listens to when the calendar widget is scrolled
+ *
+ * @param scrollListener
+ * The listener to use
+ */
+ public void setListener(ScrollListener scrollListener) {
+ this.scrollListener = scrollListener;
+ }
+
+ private EventResizeListener eventResizeListener;
+
+ /**
+ * Get the listener that listens to when an events time limits are being
+ * adjusted
+ *
+ * @return
+ */
+ public EventResizeListener getEventResizeListener() {
+ return eventResizeListener;
+ }
+
+ /**
+ * Set the listener that listens to when an events time limits are being
+ * adjusted
+ *
+ * @param eventResizeListener
+ * The listener to use
+ */
+ public void setListener(EventResizeListener eventResizeListener) {
+ this.eventResizeListener = eventResizeListener;
+ }
+
+ private MouseEventListener mouseEventListener;
+ private boolean forwardNavigationEnabled = true;
+ private boolean backwardNavigationEnabled = true;
+
+ /**
+ * Get the listener that listen to mouse events
+ *
+ * @return
+ */
+ public MouseEventListener getMouseEventListener() {
+ return mouseEventListener;
+ }
+
+ /**
+ * Set the listener that listen to mouse events
+ *
+ * @param mouseEventListener
+ * The listener to use
+ */
+ public void setListener(MouseEventListener mouseEventListener) {
+ this.mouseEventListener = mouseEventListener;
+ }
+
+ /**
+ * Is selecting a range allowed?
+ */
+ public boolean isRangeSelectAllowed() {
+ return rangeSelectAllowed;
+ }
+
+ /**
+ * Set selecting a range allowed
+ *
+ * @param rangeSelectAllowed
+ * Should selecting a range be allowed
+ */
+ public void setRangeSelectAllowed(boolean rangeSelectAllowed) {
+ this.rangeSelectAllowed = rangeSelectAllowed;
+ }
+
+ /**
+ * Is moving a range allowed
+ *
+ * @return
+ */
+ public boolean isRangeMoveAllowed() {
+ return rangeMoveAllowed;
+ }
+
+ /**
+ * Is moving a range allowed
+ *
+ * @param rangeMoveAllowed
+ * Is it allowed
+ */
+ public void setRangeMoveAllowed(boolean rangeMoveAllowed) {
+ this.rangeMoveAllowed = rangeMoveAllowed;
+ }
+
+ /**
+ * Is resizing an event allowed
+ */
+ public boolean isEventResizeAllowed() {
+ return eventResizeAllowed;
+ }
+
+ /**
+ * Is resizing an event allowed
+ *
+ * @param eventResizeAllowed
+ * True if allowed false if not
+ */
+ public void setEventResizeAllowed(boolean eventResizeAllowed) {
+ this.eventResizeAllowed = eventResizeAllowed;
+ }
+
+ /**
+ * Is moving an event allowed
+ */
+ public boolean isEventMoveAllowed() {
+ return eventMoveAllowed;
+ }
+
+ /**
+ * Is moving an event allowed
+ *
+ * @param eventMoveAllowed
+ * True if moving is allowed, false if not
+ */
+ public void setEventMoveAllowed(boolean eventMoveAllowed) {
+ this.eventMoveAllowed = eventMoveAllowed;
+ }
+
+ public boolean isBackwardNavigationEnabled() {
+ return backwardNavigationEnabled;
+ }
+
+ public void setBackwardNavigationEnabled(boolean enabled) {
+ backwardNavigationEnabled = enabled;
+ }
+
+ public boolean isForwardNavigationEnabled() {
+ return forwardNavigationEnabled;
+ }
+
+ public void setForwardNavigationEnabled(boolean enabled) {
+ forwardNavigationEnabled = enabled;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/VCalendarPanel.java b/client/src/com/vaadin/client/ui/VCalendarPanel.java
index e234cc911c..311932b819 100644
--- a/client/src/com/vaadin/client/ui/VCalendarPanel.java
+++ b/client/src/com/vaadin/client/ui/VCalendarPanel.java
@@ -19,6 +19,8 @@ package com.vaadin.client.ui;
import java.util.Date;
import java.util.Iterator;
+import com.google.gwt.aria.client.Roles;
+import com.google.gwt.aria.client.SelectedValue;
import com.google.gwt.dom.client.Node;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -40,6 +42,7 @@ import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
@@ -118,6 +121,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
private static final String CN_OFFMONTH = "offmonth";
+ private static final String CN_OUTSIDE_RANGE = "outside-range";
+
/**
* Represents a click handler for when a user selects a value by using the
* mouse
@@ -133,6 +138,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
@Override
public void onClick(ClickEvent event) {
Date newDate = ((Day) event.getSource()).getDate();
+ if (!isDateInsideRange(newDate, Resolution.DAY)) {
+ return;
+ }
if (newDate.getMonth() != displayedMonth.getMonth()
|| newDate.getYear() != displayedMonth.getYear()) {
// If an off-month date was clicked, we must change the
@@ -175,9 +183,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
private boolean showISOWeekNumbers;
- private Date displayedMonth;
+ private FocusedDate displayedMonth;
- private Date focusedDate;
+ private FocusedDate focusedDate;
private Day selectedDay;
@@ -198,8 +206,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
private boolean initialRenderDone = false;
public VCalendarPanel() {
-
+ getElement().setId(DOM.createUniqueId());
setStyleName(VDateField.CLASSNAME + "-calendarpanel");
+ Roles.getGridRole().set(getElement());
/*
* Firefox auto-repeat works correctly only if we use a key press
@@ -267,6 +276,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
private void selectDate(Date date) {
if (selectedDay != null) {
selectedDay.removeStyleDependentName(CN_SELECTED);
+ Roles.getGridcellRole().removeAriaSelectedState(
+ selectedDay.getElement());
}
int rowCount = days.getRowCount();
@@ -279,6 +290,8 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (curday.getDate().equals(date)) {
curday.addStyleDependentName(CN_SELECTED);
selectedDay = curday;
+ Roles.getGridcellRole().setAriaSelectedState(
+ selectedDay.getElement(), SelectedValue.TRUE);
return;
}
}
@@ -290,7 +303,7 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Updates year, month, day from focusedDate to value
*/
private void selectFocused() {
- if (focusedDate != null) {
+ if (focusedDate != null && isDateInsideRange(focusedDate, resolution)) {
if (value == null) {
// No previously selected value (set to null on server side).
// Create a new date using current date and time
@@ -397,10 +410,13 @@ public class VCalendarPanel extends FocusableFlexTable implements
prevMonth = new VEventButton();
prevMonth.setHTML("&lsaquo;");
prevMonth.setStyleName("v-button-prevmonth");
+
prevMonth.setTabIndex(-1);
+
nextMonth = new VEventButton();
nextMonth.setHTML("&rsaquo;");
nextMonth.setStyleName("v-button-nextmonth");
+
nextMonth.setTabIndex(-1);
setWidget(0, 3, nextMonth);
@@ -414,18 +430,23 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
if (prevYear == null) {
+
prevYear = new VEventButton();
prevYear.setHTML("&laquo;");
prevYear.setStyleName("v-button-prevyear");
+
prevYear.setTabIndex(-1);
nextYear = new VEventButton();
nextYear.setHTML("&raquo;");
nextYear.setStyleName("v-button-nextyear");
+
nextYear.setTabIndex(-1);
setWidget(0, 0, prevYear);
setWidget(0, 4, nextYear);
}
+ updateControlButtonRangeStyles(needsMonth);
+
final String monthName = needsMonth ? getDateTimeService().getMonth(
displayedMonth.getMonth()) : "";
final int year = displayedMonth.getYear() + 1900;
@@ -446,6 +467,48 @@ public class VCalendarPanel extends FocusableFlexTable implements
+ "</span>");
}
+ private void updateControlButtonRangeStyles(boolean needsMonth) {
+
+ if (focusedDate == null) {
+ return;
+ }
+
+ if (needsMonth) {
+ Date prevMonthDate = (Date) focusedDate.clone();
+ removeOneMonth(prevMonthDate);
+
+ if (!isDateInsideRange(prevMonthDate, Resolution.MONTH)) {
+ prevMonth.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ prevMonth.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+ Date nextMonthDate = (Date) focusedDate.clone();
+ addOneMonth(nextMonthDate);
+ if (!isDateInsideRange(nextMonthDate, Resolution.MONTH)) {
+ nextMonth.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ nextMonth.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+ }
+
+ Date prevYearDate = (Date) focusedDate.clone();
+ prevYearDate.setYear(prevYearDate.getYear() - 1);
+ if (!isDateInsideRange(prevYearDate, Resolution.YEAR)) {
+ prevYear.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ prevYear.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+
+ Date nextYearDate = (Date) focusedDate.clone();
+ nextYearDate.setYear(nextYearDate.getYear() + 1);
+ if (!isDateInsideRange(nextYearDate, Resolution.YEAR)) {
+ nextYear.addStyleName(CN_OUTSIDE_RANGE);
+ } else {
+ nextYear.removeStyleName(CN_OUTSIDE_RANGE);
+ }
+
+ }
+
private DateTimeService getDateTimeService() {
return dateTimeService;
}
@@ -470,6 +533,107 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
/**
+ * Checks inclusively whether a date is inside a range of dates or not.
+ *
+ * @param date
+ * @return
+ */
+ private boolean isDateInsideRange(Date date, Resolution minResolution) {
+ assert (date != null);
+
+ return isAcceptedByRangeEnd(date, minResolution)
+ && isAcceptedByRangeStart(date, minResolution);
+ }
+
+ /**
+ * Accepts dates greater than or equal to rangeStart, depending on the
+ * resolution. If the resolution is set to DAY, the range will compare on a
+ * day-basis. If the resolution is set to YEAR, only years are compared. So
+ * even if the range is set to one millisecond in next year, also next year
+ * will be included.
+ *
+ * @param date
+ * @param minResolution
+ * @return
+ */
+ private boolean isAcceptedByRangeStart(Date date, Resolution minResolution) {
+ assert (date != null);
+
+ // rangeStart == null means that we accept all values below rangeEnd
+ if (rangeStart == null) {
+ return true;
+ }
+
+ Date valueDuplicate = (Date) date.clone();
+ Date rangeStartDuplicate = (Date) rangeStart.clone();
+
+ if (minResolution == Resolution.YEAR) {
+ return valueDuplicate.getYear() >= rangeStartDuplicate.getYear();
+ }
+ if (minResolution == Resolution.MONTH) {
+ valueDuplicate = clearDateBelowMonth(valueDuplicate);
+ rangeStartDuplicate = clearDateBelowMonth(rangeStartDuplicate);
+ } else {
+ valueDuplicate = clearDateBelowDay(valueDuplicate);
+ rangeStartDuplicate = clearDateBelowDay(rangeStartDuplicate);
+ }
+
+ return !rangeStartDuplicate.after(valueDuplicate);
+ }
+
+ /**
+ * Accepts dates earlier than or equal to rangeStart, depending on the
+ * resolution. If the resolution is set to DAY, the range will compare on a
+ * day-basis. If the resolution is set to YEAR, only years are compared. So
+ * even if the range is set to one millisecond in next year, also next year
+ * will be included.
+ *
+ * @param date
+ * @param minResolution
+ * @return
+ */
+ private boolean isAcceptedByRangeEnd(Date date, Resolution minResolution) {
+ assert (date != null);
+
+ // rangeEnd == null means that we accept all values above rangeStart
+ if (rangeEnd == null) {
+ return true;
+ }
+
+ Date valueDuplicate = (Date) date.clone();
+ Date rangeEndDuplicate = (Date) rangeEnd.clone();
+
+ if (minResolution == Resolution.YEAR) {
+ return valueDuplicate.getYear() <= rangeEndDuplicate.getYear();
+ }
+ if (minResolution == Resolution.MONTH) {
+ valueDuplicate = clearDateBelowMonth(valueDuplicate);
+ rangeEndDuplicate = clearDateBelowMonth(rangeEndDuplicate);
+ } else {
+ valueDuplicate = clearDateBelowDay(valueDuplicate);
+ rangeEndDuplicate = clearDateBelowDay(rangeEndDuplicate);
+ }
+
+ return !rangeEndDuplicate.before(valueDuplicate);
+
+ }
+
+ private static Date clearDateBelowMonth(Date date) {
+ date.setDate(1);
+ return clearDateBelowDay(date);
+ }
+
+ private static Date clearDateBelowDay(Date date) {
+ date.setHours(0);
+ date.setMinutes(0);
+ date.setSeconds(0);
+ // Clearing milliseconds
+ long time = date.getTime() / 1000;
+ date = new Date(time * 1000);
+ return date;
+ }
+
+ /**
* Builds the day and time selectors of the calendar.
*/
private void buildCalendarBody() {
@@ -528,6 +692,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
} else {
days.setHTML(headerRow, firstWeekdayColumn + i, "");
}
+
+ Roles.getColumnheaderRole().set(
+ days.getCellFormatter().getElement(headerRow,
+ firstWeekdayColumn + i));
}
// Zero out hours, minutes, seconds, and milliseconds to compare dates
@@ -551,12 +719,20 @@ public class VCalendarPanel extends FocusableFlexTable implements
for (int dayOfWeek = 0; dayOfWeek < 7; dayOfWeek++) {
// Actually write the day of month
- Day day = new Day((Date) curr.clone());
+ Date dayDate = (Date) curr.clone();
+ Day day = new Day(dayDate);
+
day.setStyleName(parent.getStylePrimaryName()
+ "-calendarpanel-day");
+ if (!isDateInsideRange(dayDate, Resolution.DAY)) {
+ day.addStyleDependentName(CN_OUTSIDE_RANGE);
+ }
+
if (curr.equals(selectedDate)) {
day.addStyleDependentName(CN_SELECTED);
+ Roles.getGridcellRole().setAriaSelectedState(
+ day.getElement(), SelectedValue.TRUE);
selectedDay = day;
}
if (curr.equals(today)) {
@@ -574,10 +750,14 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
days.setWidget(weekOfMonth, firstWeekdayColumn + dayOfWeek, day);
+ Roles.getGridcellRole().set(
+ days.getCellFormatter().getElement(weekOfMonth,
+ firstWeekdayColumn + dayOfWeek));
// ISO week numbers if requested
days.getCellFormatter().setVisible(weekOfMonth, weekColumn,
isShowISOWeekNumbers());
+
if (isShowISOWeekNumbers()) {
final String baseCssClass = parent.getStylePrimaryName()
+ "-calendarpanel-weeknumber";
@@ -615,8 +795,9 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (focusedDate == null) {
Date now = new Date();
// focusedDate must have zero hours, mins, secs, millisecs
- focusedDate = new Date(now.getYear(), now.getMonth(), now.getDate());
- displayedMonth = new Date(now.getYear(), now.getMonth(), 1);
+ focusedDate = new FocusedDate(now.getYear(), now.getMonth(),
+ now.getDate());
+ displayedMonth = new FocusedDate(now.getYear(), now.getMonth(), 1);
}
if (getResolution().getCalendarField() <= Resolution.MONTH
@@ -653,6 +834,17 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Moves the focus forward the given number of days.
*/
private void focusNextDay(int days) {
+ if (focusedDate == null) {
+ return;
+ }
+
+ Date focusCopy = ((Date) focusedDate.clone());
+ focusCopy.setDate(focusedDate.getDate() + days);
+ if (!isDateInsideRange(focusCopy, resolution)) {
+ // If not inside allowed range, then do not move anything
+ return;
+ }
+
int oldMonth = focusedDate.getMonth();
int oldYear = focusedDate.getYear();
focusedDate.setDate(focusedDate.getDate() + days);
@@ -662,6 +854,7 @@ public class VCalendarPanel extends FocusableFlexTable implements
// Month did not change, only move the selection
focusDay(focusedDate);
} else {
+
// If the month changed we need to re-render the calendar
displayedMonth.setMonth(focusedDate.getMonth());
displayedMonth.setYear(focusedDate.getYear());
@@ -681,38 +874,83 @@ public class VCalendarPanel extends FocusableFlexTable implements
*/
private void focusNextMonth() {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setMonth(currentMonth + 1);
+ if (focusedDate == null) {
+ return;
+ }
+ // Trying to request next month
+ Date requestedNextMonthDate = (Date) focusedDate.clone();
+ addOneMonth(requestedNextMonthDate);
+
+ if (!isDateInsideRange(requestedNextMonthDate, Resolution.MONTH)) {
+ return;
+ }
+
+ // Now also checking whether the day is inside the range or not. If not
+ // inside,
+ // correct it
+ if (!isDateInsideRange(requestedNextMonthDate, Resolution.DAY)) {
+ requestedNextMonthDate = adjustDateToFitInsideRange(requestedNextMonthDate);
+ }
+ focusedDate.setYear(requestedNextMonthDate.getYear());
+ focusedDate.setMonth(requestedNextMonthDate.getMonth());
+ focusedDate.setDate(requestedNextMonthDate.getDate());
+ displayedMonth.setMonth(displayedMonth.getMonth() + 1);
+
+ renderCalendar();
+ }
+
+ private static void addOneMonth(Date date) {
+ int currentMonth = date.getMonth();
int requestedMonth = (currentMonth + 1) % 12;
+ date.setMonth(date.getMonth() + 1);
+
/*
* If the selected value was e.g. 31.3 the new value would be 31.4 but
* this value is invalid so the new value will be 1.5. This is taken
* care of by decreasing the value until we have the correct month.
*/
- while (focusedDate.getMonth() != requestedMonth) {
- focusedDate.setDate(focusedDate.getDate() - 1);
+ while (date.getMonth() != requestedMonth) {
+ date.setDate(date.getDate() - 1);
}
- displayedMonth.setMonth(displayedMonth.getMonth() + 1);
-
- renderCalendar();
}
- /**
- * Selects the previous month
- */
- private void focusPreviousMonth() {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setMonth(currentMonth - 1);
+ private static void removeOneMonth(Date date) {
+ int currentMonth = date.getMonth();
+
+ date.setMonth(date.getMonth() - 1);
/*
* If the selected value was e.g. 31.12 the new value would be 31.11 but
* this value is invalid so the new value will be 1.12. This is taken
* care of by decreasing the value until we have the correct month.
*/
- while (focusedDate.getMonth() == currentMonth) {
- focusedDate.setDate(focusedDate.getDate() - 1);
+ while (date.getMonth() == currentMonth) {
+ date.setDate(date.getDate() - 1);
+ }
+ }
+
+ /**
+ * Selects the previous month
+ */
+ private void focusPreviousMonth() {
+
+ if (focusedDate == null) {
+ return;
}
+ Date requestedPreviousMonthDate = (Date) focusedDate.clone();
+ removeOneMonth(requestedPreviousMonthDate);
+
+ if (!isDateInsideRange(requestedPreviousMonthDate, Resolution.MONTH)) {
+ return;
+ }
+
+ if (!isDateInsideRange(requestedPreviousMonthDate, Resolution.DAY)) {
+ requestedPreviousMonthDate = adjustDateToFitInsideRange(requestedPreviousMonthDate);
+ }
+ focusedDate.setYear(requestedPreviousMonthDate.getYear());
+ focusedDate.setMonth(requestedPreviousMonthDate.getMonth());
+ focusedDate.setDate(requestedPreviousMonthDate.getDate());
displayedMonth.setMonth(displayedMonth.getMonth() - 1);
renderCalendar();
@@ -722,16 +960,41 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Selects the previous year
*/
private void focusPreviousYear(int years) {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setYear(focusedDate.getYear() - years);
- displayedMonth.setYear(displayedMonth.getYear() - years);
- /*
- * If the focused date was a leap day (Feb 29), the new date becomes Mar
- * 1 if the new year is not also a leap year. Set it to Feb 28 instead.
- */
- if (focusedDate.getMonth() != currentMonth) {
- focusedDate.setDate(0);
+
+ if (focusedDate == null) {
+ return;
+ }
+ Date previousYearDate = (Date) focusedDate.clone();
+ previousYearDate.setYear(previousYearDate.getYear() - years);
+ // Do not focus if not inside range
+ if (!isDateInsideRange(previousYearDate, Resolution.YEAR)) {
+ return;
+ }
+ // If we remove one year, but have to roll back a bit, fit it
+ // into the calendar. Also the months have to be changed
+ if (!isDateInsideRange(previousYearDate, Resolution.DAY)) {
+ previousYearDate = adjustDateToFitInsideRange(previousYearDate);
+
+ focusedDate.setYear(previousYearDate.getYear());
+ focusedDate.setMonth(previousYearDate.getMonth());
+ focusedDate.setDate(previousYearDate.getDate());
+ displayedMonth.setYear(previousYearDate.getYear());
+ displayedMonth.setMonth(previousYearDate.getMonth());
+ } else {
+
+ int currentMonth = focusedDate.getMonth();
+ focusedDate.setYear(focusedDate.getYear() - years);
+ displayedMonth.setYear(displayedMonth.getYear() - years);
+ /*
+ * If the focused date was a leap day (Feb 29), the new date becomes
+ * Mar 1 if the new year is not also a leap year. Set it to Feb 28
+ * instead.
+ */
+ if (focusedDate.getMonth() != currentMonth) {
+ focusedDate.setDate(0);
+ }
}
+
renderCalendar();
}
@@ -739,16 +1002,41 @@ public class VCalendarPanel extends FocusableFlexTable implements
* Selects the next year
*/
private void focusNextYear(int years) {
- int currentMonth = focusedDate.getMonth();
- focusedDate.setYear(focusedDate.getYear() + years);
- displayedMonth.setYear(displayedMonth.getYear() + years);
- /*
- * If the focused date was a leap day (Feb 29), the new date becomes Mar
- * 1 if the new year is not also a leap year. Set it to Feb 28 instead.
- */
- if (focusedDate.getMonth() != currentMonth) {
- focusedDate.setDate(0);
+
+ if (focusedDate == null) {
+ return;
}
+ Date nextYearDate = (Date) focusedDate.clone();
+ nextYearDate.setYear(nextYearDate.getYear() + years);
+ // Do not focus if not inside range
+ if (!isDateInsideRange(nextYearDate, Resolution.YEAR)) {
+ return;
+ }
+ // If we add one year, but have to roll back a bit, fit it
+ // into the calendar. Also the months have to be changed
+ if (!isDateInsideRange(nextYearDate, Resolution.DAY)) {
+ nextYearDate = adjustDateToFitInsideRange(nextYearDate);
+
+ focusedDate.setYear(nextYearDate.getYear());
+ focusedDate.setMonth(nextYearDate.getMonth());
+ focusedDate.setDate(nextYearDate.getDate());
+ displayedMonth.setYear(nextYearDate.getYear());
+ displayedMonth.setMonth(nextYearDate.getMonth());
+ } else {
+
+ int currentMonth = focusedDate.getMonth();
+ focusedDate.setYear(focusedDate.getYear() + years);
+ displayedMonth.setYear(displayedMonth.getYear() + years);
+ /*
+ * If the focused date was a leap day (Feb 29), the new date becomes
+ * Mar 1 if the new year is not also a leap year. Set it to Feb 28
+ * instead.
+ */
+ if (focusedDate.getMonth() != currentMonth) {
+ focusedDate.setDate(0);
+ }
+ }
+
renderCalendar();
}
@@ -1062,9 +1350,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
*/
} else if (keycode == getResetKey() && !shift) {
// Restore showing value the selected value
- focusedDate = new Date(value.getYear(), value.getMonth(),
+ focusedDate = new FocusedDate(value.getYear(), value.getMonth(),
value.getDate());
- displayedMonth = new Date(value.getYear(), value.getMonth(), 1);
+ displayedMonth = new FocusedDate(value.getYear(), value.getMonth(),
+ 1);
renderCalendar();
return true;
}
@@ -1246,6 +1535,20 @@ public class VCalendarPanel extends FocusableFlexTable implements
}
/**
+ * Adjusts a date to fit inside the range, only if outside
+ *
+ * @param date
+ */
+ private Date adjustDateToFitInsideRange(Date date) {
+ if (rangeStart != null && rangeStart.after(date)) {
+ date = (Date) rangeStart.clone();
+ } else if (rangeEnd != null && rangeEnd.before(date)) {
+ date = (Date) rangeEnd.clone();
+ }
+ return date;
+ }
+
+ /**
* Sets the data of the Panel.
*
* @param currentDate
@@ -1257,16 +1560,47 @@ public class VCalendarPanel extends FocusableFlexTable implements
if (currentDate == value && currentDate != null) {
return;
}
+ boolean currentDateWasAdjusted = false;
+ // Check that selected date is inside the allowed range
+ if (currentDate != null && !isDateInsideRange(currentDate, resolution)) {
+ currentDate = adjustDateToFitInsideRange(currentDate);
+ currentDateWasAdjusted = true;
+ }
Date oldDisplayedMonth = displayedMonth;
value = currentDate;
- if (value == null) {
- focusedDate = displayedMonth = null;
+ // If current date was adjusted, we will not select any date,
+ // since that will look like a date is selected. Instead we
+ // only focus on the adjusted value
+ if (value == null || currentDateWasAdjusted) {
+ // If ranges enabled, we may need to focus on a different view to
+ // potentially not get stuck
+ if (rangeStart != null || rangeEnd != null) {
+ Date dateThatFitsInsideRange = adjustDateToFitInsideRange(new Date());
+ focusedDate = new FocusedDate(
+ dateThatFitsInsideRange.getYear(),
+ dateThatFitsInsideRange.getMonth(),
+ dateThatFitsInsideRange.getDate());
+ displayedMonth = new FocusedDate(
+ dateThatFitsInsideRange.getYear(),
+ dateThatFitsInsideRange.getMonth(), 1);
+ // value was adjusted. Set selected to null to not cause
+ // confusion, but this is only needed (and allowed) when we have
+ // a day
+ // resolution
+ if (getResolution().getCalendarField() >= Resolution.DAY
+ .getCalendarField()) {
+ value = null;
+ }
+ } else {
+ focusedDate = displayedMonth = null;
+ }
} else {
- focusedDate = new Date(value.getYear(), value.getMonth(),
+ focusedDate = new FocusedDate(value.getYear(), value.getMonth(),
value.getDate());
- displayedMonth = new Date(value.getYear(), value.getMonth(), 1);
+ displayedMonth = new FocusedDate(value.getYear(), value.getMonth(),
+ 1);
}
// Re-render calendar if the displayed month is changed,
@@ -1704,6 +2038,10 @@ public class VCalendarPanel extends FocusableFlexTable implements
private static final String SUBPART_DAY = "day";
private static final String SUBPART_MONTH_YEAR_HEADER = "header";
+ private Date rangeStart;
+
+ private Date rangeEnd;
+
@Override
public String getSubPartName(Element subElement) {
if (contains(nextMonth, subElement)) {
@@ -1821,4 +2159,75 @@ public class VCalendarPanel extends FocusableFlexTable implements
mouseTimer.cancel();
}
}
+
+ /**
+ * Helper class to inform the screen reader that the user changed the
+ * selected date. It sets the value of a field that is outside the view, and
+ * is defined as a live area. That way the screen reader recognizes the
+ * change and reads it to the user.
+ */
+ public class FocusedDate extends Date {
+
+ public FocusedDate(int year, int month, int date) {
+ super(year, month, date);
+ }
+
+ @Override
+ public void setTime(long time) {
+ super.setTime(time);
+ setLabel();
+ }
+
+ @Override
+ @Deprecated
+ public void setDate(int date) {
+ super.setDate(date);
+ setLabel();
+ }
+
+ @Override
+ @Deprecated
+ public void setMonth(int month) {
+ super.setMonth(month);
+ setLabel();
+ }
+
+ @Override
+ @Deprecated
+ public void setYear(int year) {
+ super.setYear(year);
+ setLabel();
+ }
+
+ private void setLabel() {
+ if (parent instanceof VPopupCalendar) {
+ ((VPopupCalendar) parent).setFocusedDate(this);
+ }
+ }
+ }
+
+ /**
+ * Sets the start range for this component. The start range is inclusive,
+ * and it depends on the current resolution, what is considered inside the
+ * range.
+ *
+ * @param startDate
+ * - the allowed range's start date
+ */
+ public void setRangeStart(Date rangeStart) {
+ this.rangeStart = rangeStart;
+
+ }
+
+ /**
+ * Sets the end range for this component. The end range is inclusive, and it
+ * depends on the current resolution, what is considered inside the range.
+ *
+ * @param endDate
+ * - the allowed range's end date
+ */
+ public void setRangeEnd(Date rangeEnd) {
+ this.rangeEnd = rangeEnd;
+
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VCheckBox.java b/client/src/com/vaadin/client/ui/VCheckBox.java
index ca1e3ebcdb..bb49dd7f0a 100644
--- a/client/src/com/vaadin/client/ui/VCheckBox.java
+++ b/client/src/com/vaadin/client/ui/VCheckBox.java
@@ -22,9 +22,12 @@ import com.google.gwt.user.client.Event;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Util;
import com.vaadin.client.VTooltip;
+import com.vaadin.client.ui.aria.AriaHelper;
+import com.vaadin.client.ui.aria.HandlesAriaInvalid;
+import com.vaadin.client.ui.aria.HandlesAriaRequired;
public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
- Field {
+ Field, HandlesAriaInvalid, HandlesAriaRequired {
public static final String CLASSNAME = "v-checkbox";
@@ -69,4 +72,23 @@ public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
}
}
+ /**
+ * Gives access to the input element.
+ *
+ * @return Element of the CheckBox itself
+ */
+ private Element getCheckBoxElement() {
+ // FIXME: Would love to use a better way to access the checkbox element
+ return (Element) getElement().getFirstChildElement();
+ }
+
+ @Override
+ public void setAriaRequired(boolean required) {
+ AriaHelper.handleInputRequired(getCheckBoxElement(), required);
+ }
+
+ @Override
+ public void setAriaInvalid(boolean invalid) {
+ AriaHelper.handleInputInvalid(getCheckBoxElement(), invalid);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VColorPickerArea.java b/client/src/com/vaadin/client/ui/VColorPickerArea.java
index bdae65438f..81f2c8fcc7 100644
--- a/client/src/com/vaadin/client/ui/VColorPickerArea.java
+++ b/client/src/com/vaadin/client/ui/VColorPickerArea.java
@@ -67,6 +67,7 @@ public class VColorPickerArea extends Widget implements ClickHandler, HasHTML,
* @param handler
* @return HandlerRegistration used to remove the handler
*/
+ @Override
public HandlerRegistration addClickHandler(ClickHandler handler) {
return addDomHandler(handler, ClickEvent.getType());
}
diff --git a/client/src/com/vaadin/client/ui/VContextMenu.java b/client/src/com/vaadin/client/ui/VContextMenu.java
index 80751652df..02ee5b07c5 100644
--- a/client/src/com/vaadin/client/ui/VContextMenu.java
+++ b/client/src/com/vaadin/client/ui/VContextMenu.java
@@ -29,19 +29,26 @@ import com.google.gwt.event.dom.client.HasBlurHandlers;
import com.google.gwt.event.dom.client.HasFocusHandlers;
import com.google.gwt.event.dom.client.HasKeyDownHandlers;
import com.google.gwt.event.dom.client.HasKeyPressHandlers;
+import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
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.Window;
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.RootPanel;
import com.google.gwt.user.client.ui.impl.FocusImpl;
import com.vaadin.client.Focusable;
import com.vaadin.client.Util;
@@ -56,6 +63,8 @@ public class VContextMenu extends VOverlay implements SubPartAware {
private int top;
+ private Element focusedElement;
+
private VLazyExecutor delayedImageLoadExecutioner = new VLazyExecutor(100,
new ScheduledCommand() {
@Override
@@ -75,6 +84,21 @@ public class VContextMenu extends VOverlay implements SubPartAware {
super(true, false, true);
setWidget(menu);
setStyleName("v-contextmenu");
+ getElement().setId(DOM.createUniqueId());
+
+ addCloseHandler(new CloseHandler<PopupPanel>() {
+ @Override
+ public void onClose(CloseEvent<PopupPanel> event) {
+ Element currentFocus = Util.getFocusedElement();
+ if (focusedElement != null
+ && (currentFocus == null
+ || menu.getElement().isOrHasChild(currentFocus) || RootPanel
+ .getBodyElement().equals(currentFocus))) {
+ focusedElement.focus();
+ focusedElement = null;
+ }
+ }
+ });
}
protected void imagesLoaded() {
@@ -115,6 +139,10 @@ public class VContextMenu extends VOverlay implements SubPartAware {
// Attach onload listeners to all images
Util.sinkOnloadForImages(menu.getElement());
+ // Store the currently focused element, which will be re-focused when
+ // context menu is closed
+ focusedElement = Util.getFocusedElement();
+
setPopupPositionAndShow(new PositionCallback() {
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
@@ -168,10 +196,11 @@ public class VContextMenu extends VOverlay implements SubPartAware {
*/
class CMenuBar extends MenuBar implements HasFocusHandlers,
HasBlurHandlers, HasKeyDownHandlers, HasKeyPressHandlers,
- Focusable, LoadHandler {
+ Focusable, LoadHandler, KeyUpHandler {
public CMenuBar() {
super(true);
addDomHandler(this, LoadEvent.getType());
+ addDomHandler(this, KeyUpEvent.getType());
}
@Override
@@ -240,6 +269,13 @@ public class VContextMenu extends VOverlay implements SubPartAware {
delayedImageLoadExecutioner.trigger();
}
+ @Override
+ public void onKeyUp(KeyUpEvent event) {
+ // Allow to close context menu with ESC
+ if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
+ hide();
+ }
+ }
}
@Override
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java
index a3156221b9..e08fbf8ab6 100644
--- a/client/src/com/vaadin/client/ui/VFilterSelect.java
+++ b/client/src/com/vaadin/client/ui/VFilterSelect.java
@@ -24,6 +24,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.Style;
@@ -66,6 +67,10 @@ import com.vaadin.client.Focusable;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
+import com.vaadin.client.ui.aria.AriaHelper;
+import com.vaadin.client.ui.aria.HandlesAriaCaption;
+import com.vaadin.client.ui.aria.HandlesAriaInvalid;
+import com.vaadin.client.ui.aria.HandlesAriaRequired;
import com.vaadin.client.ui.menubar.MenuBar;
import com.vaadin.client.ui.menubar.MenuItem;
import com.vaadin.shared.AbstractComponentState;
@@ -81,7 +86,8 @@ import com.vaadin.shared.ui.combobox.FilteringMode;
@SuppressWarnings("deprecation")
public class VFilterSelect extends Composite implements Field, KeyDownHandler,
KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable,
- SubPartAware {
+ SubPartAware, HandlesAriaCaption, HandlesAriaInvalid,
+ HandlesAriaRequired {
/**
* Represents a suggestion in the suggestion popup box
@@ -241,6 +247,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
DOM.sinkEvents(root, Event.ONMOUSEDOWN | Event.ONMOUSEWHEEL);
addCloseHandler(this);
+
+ Roles.getListRole().set(getElement());
}
/**
@@ -736,6 +744,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
while (it.hasNext()) {
final FilterSelectSuggestion s = it.next();
final MenuItem mi = new MenuItem(s.getDisplayString(), true, s);
+ Roles.getListitemRole().set(mi.getElement());
Util.sinkOnloadForImages(mi.getElement());
@@ -1106,9 +1115,15 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
});
popupOpener.sinkEvents(Event.ONMOUSEDOWN);
+ Roles.getButtonRole()
+ .setAriaHiddenState(popupOpener.getElement(), true);
+ Roles.getButtonRole().set(popupOpener.getElement());
+
panel.add(tb);
panel.add(popupOpener);
initWidget(panel);
+ Roles.getComboboxRole().set(panel.getElement());
+
tb.addKeyDownHandler(this);
tb.addKeyUpHandler(this);
@@ -1226,8 +1241,11 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
// Always update styles as they might have been overwritten
if (textInputEnabled) {
removeStyleDependentName(STYLE_NO_INPUT);
+ Roles.getTextboxRole().removeAriaReadonlyProperty(tb.getElement());
} else {
addStyleDependentName(STYLE_NO_INPUT);
+ Roles.getTextboxRole().setAriaReadonlyProperty(tb.getElement(),
+ true);
}
if (this.textInputEnabled == textInputEnabled) {
@@ -1937,4 +1955,19 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
return null;
}
+
+ @Override
+ public void setAriaRequired(boolean required) {
+ AriaHelper.handleInputRequired(tb, required);
+ }
+
+ @Override
+ public void setAriaInvalid(boolean invalid) {
+ AriaHelper.handleInputInvalid(tb, invalid);
+ }
+
+ @Override
+ public void bindAriaCaption(Element captionElement) {
+ AriaHelper.bindCaption(tb, captionElement);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java
index 495e842bfd..6c2661d1d8 100644
--- a/client/src/com/vaadin/client/ui/VFormLayout.java
+++ b/client/src/com/vaadin/client/ui/VFormLayout.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.DOM;
@@ -34,6 +35,7 @@ import com.vaadin.client.ComponentConnector;
import com.vaadin.client.Focusable;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VTooltip;
+import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.shared.AbstractComponentState;
import com.vaadin.shared.ComponentConstants;
import com.vaadin.shared.ui.ComponentStateUtil;
@@ -93,6 +95,8 @@ public class VFormLayout extends SimplePanel {
public VFormLayoutTable() {
DOM.setElementProperty(getElement(), "cellPadding", "0");
DOM.setElementProperty(getElement(), "cellSpacing", "0");
+
+ Roles.getPresentationRole().set(getElement());
}
/*
@@ -276,6 +280,9 @@ public class VFormLayout extends SimplePanel {
if (state.caption != null) {
if (captionText == null) {
captionText = DOM.createSpan();
+
+ AriaHelper.bindCaption(owner.getWidget(), captionText);
+
DOM.insertChild(getElement(), captionText, icon == null ? 0
: 1);
}
@@ -298,6 +305,9 @@ public class VFormLayout extends SimplePanel {
boolean required = owner instanceof AbstractFieldConnector
&& ((AbstractFieldConnector) owner).isRequired();
+
+ AriaHelper.handleInputRequired(owner.getWidget(), required);
+
if (required) {
if (requiredFieldIndicator == null) {
requiredFieldIndicator = DOM.createSpan();
@@ -305,6 +315,11 @@ public class VFormLayout extends SimplePanel {
DOM.setElementProperty(requiredFieldIndicator, "className",
"v-required-field-indicator");
DOM.appendChild(getElement(), requiredFieldIndicator);
+
+ // Hide the required indicator from screen reader, as this
+ // information is set directly at the input field
+ Roles.getTextboxRole().setAriaHiddenState(
+ requiredFieldIndicator, true);
}
} else {
if (requiredFieldIndicator != null) {
@@ -364,6 +379,8 @@ public class VFormLayout extends SimplePanel {
showError = false;
}
+ AriaHelper.handleInputInvalid(owner.getWidget(), showError);
+
if (showError) {
if (errorIndicatorElement == null) {
errorIndicatorElement = DOM.createDiv();
@@ -371,6 +388,11 @@ public class VFormLayout extends SimplePanel {
DOM.setElementProperty(errorIndicatorElement, "className",
"v-errorindicator");
DOM.appendChild(getElement(), errorIndicatorElement);
+
+ // Hide the error indicator from screen reader, as this
+ // information is set directly at the input field
+ Roles.getFormRole().setAriaHiddenState(
+ errorIndicatorElement, true);
}
} else if (errorIndicatorElement != null) {
diff --git a/client/src/com/vaadin/client/ui/VLabel.java b/client/src/com/vaadin/client/ui/VLabel.java
index 83fc8e207e..8acd653778 100644
--- a/client/src/com/vaadin/client/ui/VLabel.java
+++ b/client/src/com/vaadin/client/ui/VLabel.java
@@ -16,7 +16,6 @@
package com.vaadin.client.ui;
-import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.HTML;
import com.vaadin.client.ApplicationConnection;
@@ -57,10 +56,8 @@ public class VLabel extends HTML {
super.setWidth(width);
if (width == null || width.equals("")) {
setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true);
- getElement().getStyle().setDisplay(Display.INLINE_BLOCK);
} else {
setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false);
- getElement().getStyle().clearDisplay();
}
}
diff --git a/client/src/com/vaadin/client/ui/VNativeButton.java b/client/src/com/vaadin/client/ui/VNativeButton.java
index 6e1c5bae77..71413a76e6 100644
--- a/client/src/com/vaadin/client/ui/VNativeButton.java
+++ b/client/src/com/vaadin/client/ui/VNativeButton.java
@@ -16,14 +16,9 @@
package com.vaadin.client.ui;
-import com.google.gwt.core.client.Scheduler;
-import com.google.gwt.core.client.Scheduler.ScheduledCommand;
-import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
-import com.google.gwt.event.dom.client.MouseEvent;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Button;
@@ -31,7 +26,6 @@ import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.Util;
-import com.vaadin.client.VConsole;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;
diff --git a/client/src/com/vaadin/client/ui/VOptionGroup.java b/client/src/com/vaadin/client/ui/VOptionGroup.java
index 2ba8a9e729..eed5549e39 100644
--- a/client/src/com/vaadin/client/ui/VOptionGroup.java
+++ b/client/src/com/vaadin/client/ui/VOptionGroup.java
@@ -22,6 +22,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
@@ -99,6 +100,13 @@ public class VOptionGroup extends VOptionGroupBase implements FocusHandler,
public void buildOptions(UIDL uidl) {
panel.clear();
optionsEnabled.clear();
+
+ if (isMultiselect()) {
+ Roles.getGroupRole().set(getElement());
+ } else {
+ Roles.getRadiogroupRole().set(getElement());
+ }
+
for (final Iterator<?> it = uidl.getChildIterator(); it.hasNext();) {
final UIDL opUidl = (UIDL) it.next();
CheckBox op;
diff --git a/client/src/com/vaadin/client/ui/VOptionGroupBase.java b/client/src/com/vaadin/client/ui/VOptionGroupBase.java
index 4d60b2eba8..cc691130ad 100644
--- a/client/src/com/vaadin/client/ui/VOptionGroupBase.java
+++ b/client/src/com/vaadin/client/ui/VOptionGroupBase.java
@@ -118,6 +118,7 @@ public abstract class VOptionGroupBase extends Composite implements Field,
return multiselect;
}
+ @Override
public boolean isEnabled() {
return enabled;
}
@@ -190,6 +191,7 @@ public abstract class VOptionGroupBase extends Composite implements Field,
}
}
+ @Override
public void setEnabled(boolean enabled) {
if (this.enabled != enabled) {
this.enabled = enabled;
diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java
index 2a2578aa16..e431da127d 100644
--- a/client/src/com/vaadin/client/ui/VPopupCalendar.java
+++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java
@@ -18,6 +18,9 @@ package com.vaadin.client.ui;
import java.util.Date;
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.LiveValue;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -25,18 +28,25 @@ import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.VCalendarPanel.FocusOutListener;
import com.vaadin.client.ui.VCalendarPanel.SubmitListener;
+import com.vaadin.client.ui.aria.AriaHelper;
+import com.vaadin.shared.ui.datefield.PopupDateFieldState;
import com.vaadin.shared.ui.datefield.Resolution;
/**
@@ -68,6 +78,12 @@ public class VPopupCalendar extends VTextualDate implements Field,
private boolean textFieldEnabled = true;
+ private String captionId;
+
+ private Label selectedDate;
+
+ private Element descriptionForAssisitveDevicesElement;
+
public VPopupCalendar() {
super();
@@ -75,8 +91,23 @@ public class VPopupCalendar extends VTextualDate implements Field,
calendarToggle.addClickHandler(this);
// -2 instead of -1 to avoid FocusWidget.onAttach to reset it
calendarToggle.getElement().setTabIndex(-2);
+
+ Roles.getButtonRole().set(calendarToggle.getElement());
+ Roles.getButtonRole().setAriaHiddenState(calendarToggle.getElement(),
+ true);
+
add(calendarToggle);
+ // Description of the usage of the widget for assisitve device users
+ descriptionForAssisitveDevicesElement = DOM.createDiv();
+ descriptionForAssisitveDevicesElement
+ .setInnerText(PopupDateFieldState.DESCRIPTION_FOR_ASSISTIVE_DEVICES);
+ AriaHelper.ensureHasId(descriptionForAssisitveDevicesElement);
+ Roles.getTextboxRole().setAriaDescribedbyProperty(text.getElement(),
+ Id.of(descriptionForAssisitveDevicesElement));
+ AriaHelper.setVisibleForAssistiveDevicesOnly(
+ descriptionForAssisitveDevicesElement, true);
+
calendar = GWT.create(VCalendarPanel.class);
calendar.setParentField(this);
calendar.setFocusOutListener(new FocusOutListener() {
@@ -88,6 +119,14 @@ public class VPopupCalendar extends VTextualDate implements Field,
}
});
+ // FIXME: Problem is, that the element with the provided id does not
+ // exist yet in html. This is the same problem as with the context menu.
+ // Apply here the same fix (#11795)
+ Roles.getTextboxRole().setAriaControlsProperty(text.getElement(),
+ Id.of(calendar.getElement()));
+ Roles.getButtonRole().setAriaControlsProperty(
+ calendarToggle.getElement(), Id.of(calendar.getElement()));
+
calendar.setSubmitListener(new SubmitListener() {
@Override
public void onSubmit() {
@@ -109,7 +148,20 @@ public class VPopupCalendar extends VTextualDate implements Field,
popup = new VOverlay(true, true, true);
popup.setOwner(this);
- popup.setWidget(calendar);
+ FlowPanel wrapper = new FlowPanel();
+ selectedDate = new Label();
+ selectedDate.setStyleName(getStylePrimaryName() + "-selecteddate");
+ AriaHelper.setVisibleForAssistiveDevicesOnly(selectedDate.getElement(),
+ true);
+
+ Roles.getTextboxRole().setAriaLiveProperty(selectedDate.getElement(),
+ LiveValue.ASSERTIVE);
+ Roles.getTextboxRole().setAriaAtomicProperty(selectedDate.getElement(),
+ true);
+ wrapper.add(selectedDate);
+ wrapper.add(calendar);
+
+ popup.setWidget(wrapper);
popup.addCloseHandler(this);
DOM.setElementProperty(calendar.getElement(), "id",
@@ -120,6 +172,19 @@ public class VPopupCalendar extends VTextualDate implements Field,
updateStyleNames();
}
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ DOM.appendChild(RootPanel.get().getElement(),
+ descriptionForAssisitveDevicesElement);
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+ descriptionForAssisitveDevicesElement.removeFromParent();
+ }
+
@SuppressWarnings("deprecation")
public void updateValue(Date newDate) {
Date currentDate = getCurrentDate();
@@ -181,8 +246,54 @@ public class VPopupCalendar extends VTextualDate implements Field,
text.setEnabled(textFieldEnabled);
if (textFieldEnabled) {
calendarToggle.setTabIndex(-1);
+ Roles.getButtonRole().setAriaHiddenState(
+ calendarToggle.getElement(), true);
} else {
calendarToggle.setTabIndex(0);
+ Roles.getButtonRole().setAriaHiddenState(
+ calendarToggle.getElement(), false);
+ }
+
+ handleAriaAttributes();
+ }
+
+ @Override
+ public void bindAriaCaption(Element captionElement) {
+ if (captionElement == null) {
+ captionId = null;
+ } else {
+ captionId = captionElement.getId();
+ }
+
+ if (isTextFieldEnabled()) {
+ super.bindAriaCaption(captionElement);
+ } else {
+ AriaHelper.bindCaption(calendarToggle, captionElement);
+ }
+
+ handleAriaAttributes();
+ }
+
+ private void handleAriaAttributes() {
+ Widget removeFromWidget;
+ Widget setForWidget;
+
+ if (isTextFieldEnabled()) {
+ setForWidget = text;
+ removeFromWidget = calendarToggle;
+ } else {
+ setForWidget = calendarToggle;
+ removeFromWidget = text;
+ }
+
+ Roles.getFormRole().removeAriaLabelledbyProperty(
+ removeFromWidget.getElement());
+ if (captionId == null) {
+ Roles.getFormRole().removeAriaLabelledbyProperty(
+ setForWidget.getElement());
+ } else {
+ Roles.getFormRole().setAriaLabelledbyProperty(
+ setForWidget.getElement(), Id.of(captionId));
}
}
@@ -270,10 +381,6 @@ public class VPopupCalendar extends VTextualDate implements Field,
}
}
- // fix size
- popup.setWidth(w + "px");
- popup.setHeight(h + "px");
-
popup.setPopupPosition(l,
t + calendarToggle.getOffsetHeight() + 2);
@@ -350,6 +457,32 @@ public class VPopupCalendar extends VTextualDate implements Field,
calendar.setFocus(focus);
}
+ @Override
+ public void setEnabled(boolean enabled) {
+ super.setEnabled(enabled);
+
+ if (enabled) {
+ Roles.getButtonRole().setAriaDisabledState(
+ calendarToggle.getElement(), true);
+ } else {
+ Roles.getButtonRole().setAriaDisabledState(
+ calendarToggle.getElement(), false);
+ }
+ }
+
+ /**
+ * Sets the content of a special field for assistive devices, so that they
+ * can recognize the change and inform the user (reading out in case of
+ * screen reader)
+ *
+ * @param selectedDate
+ * Date that is currently selected
+ */
+ public void setFocusedDate(Date selectedDate) {
+ this.selectedDate.setText(DateTimeFormat.getFormat("dd, MMMM, yyyy")
+ .format(selectedDate));
+ }
+
/**
* For internal use only. May be removed or replaced in the future.
*
@@ -439,4 +572,50 @@ public class VPopupCalendar extends VTextualDate implements Field,
return super.getSubPartName(subElement);
}
+ /**
+ * Set a description that explains the usage of the Widget for users of
+ * assistive devices.
+ *
+ * @param descriptionForAssistiveDevices
+ * String with the description
+ */
+ public void setDescriptionForAssistiveDevices(
+ String descriptionForAssistiveDevices) {
+ descriptionForAssisitveDevicesElement
+ .setInnerText(descriptionForAssistiveDevices);
+ }
+
+ /**
+ * Get the description that explains the usage of the Widget for users of
+ * assistive devices.
+ *
+ * @return String with the description
+ */
+ public String getDescriptionForAssistiveDevices() {
+ return descriptionForAssisitveDevicesElement.getInnerText();
+ }
+
+ /**
+ * Sets the start range for this component. The start range is inclusive,
+ * and it depends on the current resolution, what is considered inside the
+ * range.
+ *
+ * @param startDate
+ * - the allowed range's start date
+ */
+ public void setRangeStart(Date rangeStart) {
+ calendar.setRangeStart(rangeStart);
+ }
+
+ /**
+ * Sets the end range for this component. The end range is inclusive, and it
+ * depends on the current resolution, what is considered inside the range.
+ *
+ * @param endDate
+ * - the allowed range's end date
+ */
+ public void setRangeEnd(Date rangeEnd) {
+ calendar.setRangeEnd(rangeEnd);
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/VPopupView.java b/client/src/com/vaadin/client/ui/VPopupView.java
index d983da2b62..05fbd2c073 100644
--- a/client/src/com/vaadin/client/ui/VPopupView.java
+++ b/client/src/com/vaadin/client/ui/VPopupView.java
@@ -202,7 +202,6 @@ public class VPopupView extends HTML implements Iterable<Widget> {
private boolean hasHadMouseOver = false;
private boolean hideOnMouseOut = true;
private final Set<Element> activeChildren = new HashSet<Element>();
- private boolean hiding = false;
private ShortcutActionHandler shortcutActionHandler;
@@ -264,7 +263,6 @@ public class VPopupView extends HTML implements Iterable<Widget> {
@Override
public void hide(boolean autoClosed) {
VConsole.log("Hiding popupview");
- hiding = true;
syncChildren();
if (popupComponentWidget != null && popupComponentWidget != loading) {
remove(popupComponentWidget);
@@ -276,8 +274,6 @@ public class VPopupView extends HTML implements Iterable<Widget> {
@Override
public void show() {
- hiding = false;
-
// Find the shortcut action handler that should handle keyboard
// events from the popup. The events do not propagate automatically
// because the popup is directly attached to the RootPanel.
@@ -353,31 +349,6 @@ public class VPopupView extends HTML implements Iterable<Widget> {
this.hideOnMouseOut = hideOnMouseOut;
}
- /*
- *
- * We need a hack make popup act as a child of VPopupView in Vaadin's
- * component tree, but work in default GWT manner when closing or
- * opening.
- *
- * (non-Javadoc)
- *
- * @see com.google.gwt.user.client.ui.Widget#getParent()
- */
- @Override
- public Widget getParent() {
- if (!isAttached() || hiding) {
- return super.getParent();
- } else {
- return VPopupView.this;
- }
- }
-
- @Override
- protected void onDetach() {
- super.onDetach();
- hiding = false;
- }
-
@Override
public Element getContainerElement() {
return super.getContainerElement();
diff --git a/client/src/com/vaadin/client/ui/VTextualDate.java b/client/src/com/vaadin/client/ui/VTextualDate.java
index 2f444a8587..9d7e31faab 100644
--- a/client/src/com/vaadin/client/ui/VTextualDate.java
+++ b/client/src/com/vaadin/client/ui/VTextualDate.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui;
import java.util.Date;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ChangeEvent;
@@ -30,11 +31,16 @@ import com.vaadin.client.Focusable;
import com.vaadin.client.LocaleNotLoadedException;
import com.vaadin.client.LocaleService;
import com.vaadin.client.VConsole;
+import com.vaadin.client.ui.aria.AriaHelper;
+import com.vaadin.client.ui.aria.HandlesAriaCaption;
+import com.vaadin.client.ui.aria.HandlesAriaInvalid;
+import com.vaadin.client.ui.aria.HandlesAriaRequired;
import com.vaadin.shared.EventId;
import com.vaadin.shared.ui.datefield.Resolution;
public class VTextualDate extends VDateField implements Field, ChangeHandler,
- Focusable, SubPartAware {
+ Focusable, SubPartAware, HandlesAriaCaption, HandlesAriaInvalid,
+ HandlesAriaRequired {
private static final String PARSE_ERROR_CLASSNAME = "-parseerror";
@@ -76,6 +82,9 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
getClient()
.updateVariable(getId(), EventId.FOCUS, "", true);
}
+
+ // Needed for tooltip event handling
+ VTextualDate.this.fireEvent(event);
}
});
text.addBlurHandler(new BlurHandler() {
@@ -94,8 +103,12 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
EventId.BLUR)) {
getClient().updateVariable(getId(), EventId.BLUR, "", true);
}
+
+ // Needed for tooltip event handling
+ VTextualDate.this.fireEvent(event);
}
});
+
add(text);
}
@@ -150,6 +163,21 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
return formatStr;
}
+ @Override
+ public void bindAriaCaption(Element captionElement) {
+ AriaHelper.bindCaption(text, captionElement);
+ }
+
+ @Override
+ public void setAriaRequired(boolean required) {
+ AriaHelper.handleInputRequired(text, required);
+ }
+
+ @Override
+ public void setAriaInvalid(boolean invalid) {
+ AriaHelper.handleInputInvalid(text, invalid);
+ }
+
/**
* Updates the text field according to the current date (provided by
* {@link #getDate()}). Takes care of updating text, enabling and disabling
@@ -178,8 +206,12 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
if (readonly) {
text.addStyleName("v-readonly");
+ Roles.getTextboxRole().setAriaReadonlyProperty(text.getElement(),
+ true);
} else {
text.removeStyleName("v-readonly");
+ Roles.getTextboxRole()
+ .removeAriaReadonlyProperty(text.getElement());
}
}
@@ -348,5 +380,4 @@ public class VTextualDate extends VDateField implements Field, ChangeHandler,
return null;
}
-
}
diff --git a/client/src/com/vaadin/client/ui/VTree.java b/client/src/com/vaadin/client/ui/VTree.java
index 624dce4f13..51c00ca310 100644
--- a/client/src/com/vaadin/client/ui/VTree.java
+++ b/client/src/com/vaadin/client/ui/VTree.java
@@ -24,6 +24,10 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import com.google.gwt.aria.client.ExpandedValue;
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.Roles;
+import com.google.gwt.aria.client.SelectedValue;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
@@ -56,6 +60,8 @@ import com.vaadin.client.ConnectorMap;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
+import com.vaadin.client.ui.aria.AriaHelper;
+import com.vaadin.client.ui.aria.HandlesAriaCaption;
import com.vaadin.client.ui.dd.DDUtil;
import com.vaadin.client.ui.dd.VAbstractDropHandler;
import com.vaadin.client.ui.dd.VAcceptCallback;
@@ -75,7 +81,8 @@ import com.vaadin.shared.ui.tree.TreeConstants;
*/
public class VTree extends FocusElementPanel implements VHasDropHandler,
FocusHandler, BlurHandler, KeyPressHandler, KeyDownHandler,
- SubPartAware, ActionOwner {
+ SubPartAware, ActionOwner, HandlesAriaCaption {
+ private String lastNodeKey = "";
public static final String CLASSNAME = "v-tree";
@@ -168,6 +175,8 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
public VTree() {
super();
setStyleName(CLASSNAME);
+
+ Roles.getTreeRole().set(body.getElement());
add(body);
addFocusHandler(this);
@@ -865,12 +874,24 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
}
protected void constructDom() {
+ String labelId = DOM.createUniqueId();
+
addStyleName(CLASSNAME);
+ String treeItemId = DOM.createUniqueId();
+ getElement().setId(treeItemId);
+ Roles.getTreeitemRole().set(getElement());
+ Roles.getTreeitemRole().setAriaSelectedState(getElement(),
+ SelectedValue.FALSE);
+ Roles.getTreeitemRole().setAriaLabelledbyProperty(getElement(),
+ Id.of(labelId));
nodeCaptionDiv = DOM.createDiv();
DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME
+ "-caption");
Element wrapper = DOM.createDiv();
+ wrapper.setId(labelId);
+ wrapper.setAttribute("for", treeItemId);
+
nodeCaptionSpan = DOM.createSpan();
DOM.appendChild(getElement(), nodeCaptionDiv);
DOM.appendChild(nodeCaptionDiv, wrapper);
@@ -886,6 +907,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
childNodeContainer = new FlowPanel();
childNodeContainer.setStyleName(CLASSNAME + "-children");
+ Roles.getGroupRole().set(childNodeContainer.getElement());
setWidget(childNodeContainer);
}
@@ -914,10 +936,13 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
new String[] { key }, true);
}
addStyleName(CLASSNAME + "-expanded");
+ Roles.getTreeitemRole().setAriaExpandedState(getElement(),
+ ExpandedValue.TRUE);
childNodeContainer.setVisible(true);
-
} else {
removeStyleName(CLASSNAME + "-expanded");
+ Roles.getTreeitemRole().setAriaExpandedState(getElement(),
+ ExpandedValue.FALSE);
childNodeContainer.setVisible(false);
if (notifyServer) {
client.updateVariable(paintableId, "collapse",
@@ -1094,15 +1119,17 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
Util.scrollIntoViewVertically(nodeCaptionDiv);
}
- public void setIcon(String iconUrl) {
+ public void setIcon(String iconUrl, String altText) {
if (iconUrl != null) {
// Add icon if not present
if (icon == null) {
icon = new Icon(client);
+ Roles.getImgRole().set(icon.getElement());
DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv),
icon.getElement(), nodeCaptionSpan);
}
icon.setUri(iconUrl);
+ icon.getElement().setAttribute("alt", altText);
} else {
// Remove icon if present
if (icon != null) {
@@ -1517,10 +1544,34 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
// Unfocus previously focused node
if (focusedNode != null) {
focusedNode.setFocused(false);
+
+ Roles.getTreeRole().removeAriaActivedescendantProperty(
+ focusedNode.getElement());
}
if (node != null) {
node.setFocused(true);
+ Roles.getTreeitemRole().setAriaSelectedState(node.getElement(),
+ SelectedValue.TRUE);
+
+ /*
+ * FIXME: This code needs to be changed when the keyboard navigation
+ * doesn't immediately trigger a selection change anymore.
+ *
+ * Right now this function is called before and after the Tree is
+ * rebuilt when up/down arrow keys are pressed. This leads to the
+ * problem, that the newly selected item is announced too often with
+ * a screen reader.
+ *
+ * Behaviour is different when using the Tree with and without
+ * screen reader.
+ */
+ if (node.key.equals(lastNodeKey)) {
+ Roles.getTreeRole().setAriaActivedescendantProperty(
+ getFocusElement(), Id.of(node.getElement()));
+ } else {
+ lastNodeKey = node.key;
+ }
}
focusedNode = node;
@@ -2161,4 +2212,8 @@ public class VTree extends FocusElementPanel implements VHasDropHandler,
keyToNode.clear();
}
+ @Override
+ public void bindAriaCaption(Element captionElement) {
+ AriaHelper.bindCaption(body, captionElement);
+ }
}
diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java
index 51a775cb7e..38dfdba1b8 100644
--- a/client/src/com/vaadin/client/ui/VWindow.java
+++ b/client/src/com/vaadin/client/ui/VWindow.java
@@ -43,12 +43,13 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ConnectorMap;
-import com.vaadin.client.Console;
import com.vaadin.client.Focusable;
import com.vaadin.client.LayoutManager;
import com.vaadin.client.Util;
+import com.vaadin.client.debug.internal.VDebugWindow;
import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
import com.vaadin.shared.EventId;
+import com.vaadin.shared.ui.window.WindowMode;
/**
* "Sub window" component.
@@ -58,18 +59,6 @@ import com.vaadin.shared.EventId;
public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
ScrollHandler, KeyDownHandler, FocusHandler, BlurHandler, Focusable {
- /**
- * Minimum allowed height of a window. This refers to the content area, not
- * the outer borders.
- */
- private static final int MIN_CONTENT_AREA_HEIGHT = 100;
-
- /**
- * Minimum allowed width of a window. This refers to the content area, not
- * the outer borders.
- */
- private static final int MIN_CONTENT_AREA_WIDTH = 150;
-
private static ArrayList<VWindow> windowOrder = new ArrayList<VWindow>();
private static boolean orderingDefered;
@@ -114,6 +103,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
public Element closeBox;
/** For internal use only. May be removed or replaced in the future. */
+ public Element maximizeRestoreBox;
+
+ /** For internal use only. May be removed or replaced in the future. */
public ApplicationConnection client;
/** For internal use only. May be removed or replaced in the future. */
@@ -262,6 +254,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
resizeBox = DOM.createDiv();
DOM.setElementProperty(resizeBox, "className", CLASSNAME + "-resizebox");
closeBox = DOM.createDiv();
+ maximizeRestoreBox = DOM.createDiv();
+ DOM.setElementProperty(maximizeRestoreBox, "className", CLASSNAME
+ + "-maximizebox");
DOM.setElementProperty(closeBox, "className", CLASSNAME + "-closebox");
DOM.appendChild(footer, resizeBox);
@@ -269,14 +264,15 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap");
DOM.appendChild(wrapper, header);
+ DOM.appendChild(wrapper, maximizeRestoreBox);
DOM.appendChild(wrapper, closeBox);
DOM.appendChild(header, headerText);
DOM.appendChild(wrapper, contents);
DOM.appendChild(wrapper, footer);
DOM.appendChild(super.getContainerElement(), wrapper);
- sinkEvents(Event.MOUSEEVENTS | Event.TOUCHEVENTS | Event.ONCLICK
- | Event.ONLOSECAPTURE);
+ sinkEvents(Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.TOUCHEVENTS
+ | Event.ONCLICK | Event.ONLOSECAPTURE);
setWidget(contentPanel);
@@ -575,6 +571,31 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}
}
+ public void updateMaximizeRestoreClassName(boolean visible,
+ WindowMode windowMode) {
+ String className;
+ if (windowMode == WindowMode.MAXIMIZED) {
+ className = CLASSNAME + "-restorebox";
+ } else {
+ className = CLASSNAME + "-maximizebox";
+ }
+ if (!visible) {
+ className = className + " " + className + "-disabled";
+ }
+ maximizeRestoreBox.setClassName(className);
+ }
+
+ // TODO this will eventually be removed, currently used to avoid updating to
+ // server side.
+ public void setPopupPositionNoUpdate(int left, int top) {
+ if (top < 0) {
+ // ensure window is not moved out of browser window from top of the
+ // screen
+ top = 0;
+ }
+ super.setPopupPosition(left, top);
+ }
+
@Override
public void setPopupPosition(int left, int top) {
if (top < 0) {
@@ -616,6 +637,8 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
return contents;
}
+ private Event headerDragPending;
+
@Override
public void onBrowserEvent(final Event event) {
boolean bubble = true;
@@ -632,6 +655,28 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
onCloseClick();
}
bubble = false;
+ } else if (target == maximizeRestoreBox) {
+ // handled in connector
+ if (type != Event.ONCLICK) {
+ bubble = false;
+ }
+ } else if (header.isOrHasChild(target) && !dragging) {
+ // dblclick handled in connector
+ if (type != Event.ONDBLCLICK && draggable) {
+ if (type == Event.ONMOUSEDOWN) {
+ headerDragPending = event;
+ } else if (type == Event.ONMOUSEMOVE
+ && headerDragPending != null) {
+ // ie won't work unless this is set here
+ dragging = true;
+ onDragEvent(headerDragPending);
+ onDragEvent(event);
+ headerDragPending = null;
+ } else {
+ headerDragPending = null;
+ }
+ bubble = false;
+ }
} else if (dragging || !contents.isOrHasChild(target)) {
onDragEvent(event);
bubble = false;
@@ -648,7 +693,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
*/
if (type == Event.ONMOUSEDOWN
&& !contentPanel.getElement().isOrHasChild(target)
- && target != closeBox) {
+ && target != closeBox && target != maximizeRestoreBox) {
contentPanel.focus();
}
@@ -746,16 +791,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}
int w = Util.getTouchOrMouseClientX(event) - startX + origW;
- int minWidth = getMinWidth();
- if (w < minWidth) {
- w = minWidth;
- }
-
int h = Util.getTouchOrMouseClientY(event) - startY + origH;
- int minHeight = getMinHeight();
- if (h < minHeight) {
- h = minHeight;
- }
setWidth(w + "px");
setHeight(h + "px");
@@ -775,7 +811,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
}
}
- private void updateContentsSize() {
+ public void updateContentsSize() {
LayoutManager layoutManager = getLayoutManager();
layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector(
this));
@@ -896,7 +932,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
// debug window
Widget w = Util.findWidget(target, null);
while (w != null) {
- if (w instanceof Console) {
+ if (w instanceof VDebugWindow) {
return true; // allow debug-window clicks
} else if (ConnectorMap.get(client).isConnector(w)) {
return false;
@@ -959,10 +995,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
contentPanel.focus();
}
- public int getMinHeight() {
- return MIN_CONTENT_AREA_HEIGHT + getDecorationHeight();
- }
-
private int getDecorationHeight() {
LayoutManager lm = getLayoutManager();
int headerHeight = lm.getOuterHeight(header);
@@ -974,10 +1006,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
return LayoutManager.get(client);
}
- public int getMinWidth() {
- return MIN_CONTENT_AREA_WIDTH + getDecorationWidth();
- }
-
private int getDecorationWidth() {
LayoutManager layoutManager = getLayoutManager();
return layoutManager.getOuterWidth(getElement())
diff --git a/client/src/com/vaadin/client/ui/absolutelayout/AbsoluteLayoutConnector.java b/client/src/com/vaadin/client/ui/absolutelayout/AbsoluteLayoutConnector.java
index 868c14f742..da79639dcd 100644
--- a/client/src/com/vaadin/client/ui/absolutelayout/AbsoluteLayoutConnector.java
+++ b/client/src/com/vaadin/client/ui/absolutelayout/AbsoluteLayoutConnector.java
@@ -100,8 +100,7 @@ public class AbsoluteLayoutConnector extends
/*
* (non-Javadoc)
*
- * @see
- * com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin
+ * @see com.vaadin.client.HasComponentsConnector#updateCaption(com.vaadin
* .client.ComponentConnector)
*/
@Override
@@ -188,6 +187,8 @@ public class AbsoluteLayoutConnector extends
oldChild.removeStateChangeHandler(childStateChangeHandler);
}
}
+
+ getWidget().cleanupWrappers();
}
/*
diff --git a/client/src/com/vaadin/client/ui/aria/AriaHelper.java b/client/src/com/vaadin/client/ui/aria/AriaHelper.java
new file mode 100644
index 0000000000..0ff58cf510
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/aria/AriaHelper.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.ui.aria;
+
+import com.google.gwt.aria.client.Id;
+import com.google.gwt.aria.client.InvalidValue;
+import com.google.gwt.aria.client.Roles;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Helper class that helps to implement the WAI-ARIA functionality.
+ */
+public class AriaHelper {
+ public static final String ASSISTIVE_DEVICE_ONLY_STYLE = "v-assistive-device-only";
+
+ /**
+ * Binds a caption (label in HTML speak) to the form element as required by
+ * WAI-ARIA specification.
+ *
+ * @param widget
+ * Widget, that should be bound to the caption
+ * @param captionElements
+ * Element with of caption to bind
+ */
+ public static void bindCaption(Widget widget, Element captionElement) {
+ assert widget != null : "Valid Widget required";
+
+ if (widget instanceof HandlesAriaCaption) {
+ // Let the widget handle special cases itself
+ if (captionElement == null) {
+ ((HandlesAriaCaption) widget).bindAriaCaption(null);
+ } else {
+ ensureHasId(captionElement);
+ ((HandlesAriaCaption) widget).bindAriaCaption(captionElement);
+ }
+ } else if (captionElement != null) {
+ // Handle the default case
+ ensureHasId(captionElement);
+ String ownerId = ensureHasId(widget.getElement());
+ captionElement.setAttribute("for", ownerId);
+
+ Roles.getTextboxRole().setAriaLabelledbyProperty(
+ widget.getElement(), Id.of(captionElement));
+ } else {
+ clearCaption(widget);
+ }
+ }
+
+ /**
+ * Removes a binding to a caption added with bindCaption() from the provided
+ * Widget.
+ *
+ * @param widget
+ * Widget, that was bound to a caption before
+ */
+ private static void clearCaption(Widget widget) {
+ Roles.getTextboxRole()
+ .removeAriaLabelledbyProperty(widget.getElement());
+ }
+
+ /**
+ * Handles the required actions depending of the input Widget being required
+ * or not.
+ *
+ * @param widget
+ * Widget, typically an input Widget like TextField
+ * @param required
+ * boolean, true when the element is required
+ */
+ public static void handleInputRequired(Widget widget, boolean required) {
+ assert widget != null : "Valid Widget required";
+
+ if (widget instanceof HandlesAriaRequired) {
+ ((HandlesAriaRequired) widget).setAriaRequired(required);
+ } else {
+ handleInputRequired(widget.getElement(), required);
+ }
+ }
+
+ /**
+ * Handles the required actions depending of the input element being
+ * required or not.
+ *
+ * @param element
+ * Element, typically from an input Widget like TextField
+ * @param required
+ * boolean, true when the element is required
+ */
+ public static void handleInputRequired(Element element, boolean required) {
+ if (required) {
+ Roles.getTextboxRole().setAriaRequiredProperty(element, required);
+ } else {
+ Roles.getTextboxRole().removeAriaRequiredProperty(element);
+ }
+ }
+
+ /**
+ * Handles the required actions depending of the input Widget contains
+ * unaccepted input.
+ *
+ * @param widget
+ * Widget, typically an input Widget like TextField
+ * @param invalid
+ * boolean, true when the Widget input has an error
+ */
+ public static void handleInputInvalid(Widget widget, boolean invalid) {
+ assert widget != null : "Valid Widget required";
+
+ if (widget instanceof HandlesAriaInvalid) {
+ ((HandlesAriaInvalid) widget).setAriaInvalid(invalid);
+ } else {
+ handleInputInvalid(widget.getElement(), invalid);
+ }
+ }
+
+ /**
+ * Handles the required actions depending of the input element contains
+ * unaccepted input.
+ *
+ * @param element
+ * Element, typically an input Widget like TextField
+ * @param invalid
+ * boolean, true when the element input has an error
+ */
+ public static void handleInputInvalid(Element element, boolean invalid) {
+ if (invalid) {
+ Roles.getTextboxRole().setAriaInvalidState(element,
+ InvalidValue.TRUE);
+ } else {
+ Roles.getTextboxRole().removeAriaInvalidState(element);
+ }
+ }
+
+ /**
+ * Makes sure that the provided element has an id attribute. Adds a new
+ * unique id if not.
+ *
+ * @param element
+ * Element to check
+ * @return String with the id of the element
+ */
+ public static String ensureHasId(Element element) {
+ assert element != null : "Valid Element required";
+
+ String id = element.getId();
+ if (null == id || id.isEmpty()) {
+ id = DOM.createUniqueId();
+ element.setId(id);
+ }
+ return id;
+ }
+
+ /**
+ * Allows to move an element out of the visible area of the browser window.
+ *
+ * This makes it possible to have additional information for an assistive
+ * device, that is not in the way for visual users.
+ *
+ * @param element
+ * Element to move out of sight
+ * @param boolean assistiveOnly true when element should only be visible for
+ * assistive devices, false to make the element visible for all
+ */
+ public static void setVisibleForAssistiveDevicesOnly(Element element,
+ boolean assistiveOnly) {
+ if (assistiveOnly) {
+ element.addClassName(ASSISTIVE_DEVICE_ONLY_STYLE);
+ } else {
+ element.removeClassName(ASSISTIVE_DEVICE_ONLY_STYLE);
+ }
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/aria/HandlesAriaCaption.java b/client/src/com/vaadin/client/ui/aria/HandlesAriaCaption.java
new file mode 100644
index 0000000000..50f83fdede
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/aria/HandlesAriaCaption.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.ui.aria;
+
+import com.google.gwt.user.client.Element;
+
+/**
+ * Some Widgets need to handle the caption handling for WAI-ARIA themselfs, as
+ * for example the required ids need to be set in a specific way. In such a
+ * case, the Widget needs to implement this interface.
+ */
+public interface HandlesAriaCaption {
+
+ /**
+ * Called to bind the provided caption (label in HTML speak) element to the
+ * main input element of the Widget.
+ *
+ * Binding should be removed from the main input field when captionElement
+ * is null.
+ *
+ * @param captionElement
+ * Element of the caption
+ */
+ void bindAriaCaption(Element captionElement);
+}
diff --git a/client/src/com/vaadin/client/ui/aria/HandlesAriaInvalid.java b/client/src/com/vaadin/client/ui/aria/HandlesAriaInvalid.java
new file mode 100644
index 0000000000..05cb82b0d6
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/aria/HandlesAriaInvalid.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.ui.aria;
+
+/**
+ * Some Widgets need to handle the required handling for WAI-ARIA themselfs, as
+ * this attribute needs to be set to the input element itself. In such a case,
+ * the Widget needs to implement this interface.
+ */
+public interface HandlesAriaInvalid {
+ /**
+ * Called to set the element, typically an input element, as invalid.
+ *
+ * @param invalid
+ * boolean, true when the element should be marked invalid, false
+ * otherwise
+ */
+ void setAriaInvalid(boolean invalid);
+}
diff --git a/client/src/com/vaadin/client/ui/aria/HandlesAriaRequired.java b/client/src/com/vaadin/client/ui/aria/HandlesAriaRequired.java
new file mode 100644
index 0000000000..9b18bfb4de
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/aria/HandlesAriaRequired.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.client.ui.aria;
+
+/**
+ * Some Widgets need to handle the required handling for WAI-ARIA themselfs, as
+ * this attribute needs to be set to the input element itself. In such a case,
+ * the Widget needs to implement this interface.
+ */
+public interface HandlesAriaRequired {
+ /**
+ * Called to set the element, typically an input element, as required.
+ *
+ * @param required
+ * boolean true when the element needs to be set as required
+ */
+ void setAriaRequired(boolean required);
+}
diff --git a/client/src/com/vaadin/client/ui/button/ButtonConnector.java b/client/src/com/vaadin/client/ui/button/ButtonConnector.java
index 9733d206c7..fff983c168 100644
--- a/client/src/com/vaadin/client/ui/button/ButtonConnector.java
+++ b/client/src/com/vaadin/client/ui/button/ButtonConnector.java
@@ -24,6 +24,7 @@ import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
import com.vaadin.client.EventHelper;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.communication.StateChangeEvent;
@@ -83,8 +84,10 @@ public class ButtonConnector extends AbstractComponentConnector implements
if (getIcon() != null) {
if (getWidget().icon == null) {
getWidget().icon = new Icon(getConnection());
- getWidget().wrapper.insertBefore(
- getWidget().icon.getElement(),
+ Element iconElement = getWidget().icon.getElement();
+ iconElement.setAttribute("alt", getState().iconAltText);
+
+ getWidget().wrapper.insertBefore(iconElement,
getWidget().captionElement);
}
getWidget().icon.setUri(getIcon());
diff --git a/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java
new file mode 100644
index 0000000000..285d15792b
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/CalendarConnector.java
@@ -0,0 +1,662 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.TooltipInfo;
+import com.vaadin.client.UIDL;
+import com.vaadin.client.Util;
+import com.vaadin.client.VConsole;
+import com.vaadin.client.communication.RpcProxy;
+import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.client.ui.Action;
+import com.vaadin.client.ui.ActionOwner;
+import com.vaadin.client.ui.SimpleManagedLayout;
+import com.vaadin.client.ui.VCalendar;
+import com.vaadin.client.ui.VCalendar.BackwardListener;
+import com.vaadin.client.ui.VCalendar.DateClickListener;
+import com.vaadin.client.ui.VCalendar.EventClickListener;
+import com.vaadin.client.ui.VCalendar.EventMovedListener;
+import com.vaadin.client.ui.VCalendar.EventResizeListener;
+import com.vaadin.client.ui.VCalendar.ForwardListener;
+import com.vaadin.client.ui.VCalendar.MouseEventListener;
+import com.vaadin.client.ui.VCalendar.RangeSelectListener;
+import com.vaadin.client.ui.VCalendar.WeekClickListener;
+import com.vaadin.client.ui.calendar.schedule.CalendarDay;
+import com.vaadin.client.ui.calendar.schedule.CalendarEvent;
+import com.vaadin.client.ui.calendar.schedule.DateCell;
+import com.vaadin.client.ui.calendar.schedule.DateCell.DateCellSlot;
+import com.vaadin.client.ui.calendar.schedule.DateCellDayEvent;
+import com.vaadin.client.ui.calendar.schedule.DateUtil;
+import com.vaadin.client.ui.calendar.schedule.HasTooltipKey;
+import com.vaadin.client.ui.calendar.schedule.SimpleDayCell;
+import com.vaadin.client.ui.calendar.schedule.dd.CalendarDropHandler;
+import com.vaadin.client.ui.dd.VHasDropHandler;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.Connect.LoadStyle;
+import com.vaadin.shared.ui.calendar.CalendarClientRpc;
+import com.vaadin.shared.ui.calendar.CalendarEventId;
+import com.vaadin.shared.ui.calendar.CalendarServerRpc;
+import com.vaadin.shared.ui.calendar.CalendarState;
+import com.vaadin.shared.ui.calendar.DateConstants;
+import com.vaadin.ui.Calendar;
+
+/**
+ * Handles communication between Calendar on the server side and
+ * {@link VCalendar} on the client side.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@Connect(value = Calendar.class, loadStyle = LoadStyle.LAZY)
+public class CalendarConnector extends AbstractComponentConnector implements
+ VHasDropHandler, ActionOwner, SimpleManagedLayout {
+
+ private CalendarServerRpc rpc = RpcProxy.create(CalendarServerRpc.class,
+ this);
+
+ private CalendarDropHandler dropHandler;
+
+ private final HashMap<String, String> actionMap = new HashMap<String, String>();
+ private HashMap<Object, String> tooltips = new HashMap<Object, String>();
+
+ /**
+ *
+ */
+ public CalendarConnector() {
+
+ // Listen to events
+ registerListeners();
+ }
+
+ @Override
+ protected void init() {
+ super.init();
+ registerRpc(CalendarClientRpc.class, new CalendarClientRpc() {
+ @Override
+ public void scroll(int scrollPosition) {
+ // TODO widget scroll
+ }
+ });
+ getLayoutManager().registerDependency(this, getWidget().getElement());
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ getLayoutManager().unregisterDependency(this, getWidget().getElement());
+ }
+
+ @Override
+ public VCalendar getWidget() {
+ return (VCalendar) super.getWidget();
+ }
+
+ @Override
+ public CalendarState getState() {
+ return (CalendarState) super.getState();
+ }
+
+ /**
+ * Registers listeners on the calendar so server can be notified of the
+ * events
+ */
+ protected void registerListeners() {
+ getWidget().setListener(new DateClickListener() {
+ @Override
+ public void dateClick(String date) {
+ if (!getWidget().isDisabledOrReadOnly()
+ && hasEventListener(CalendarEventId.DATECLICK)) {
+ rpc.dateClick(date);
+ }
+ }
+ });
+ getWidget().setListener(new ForwardListener() {
+ @Override
+ public void forward() {
+ if (hasEventListener(CalendarEventId.FORWARD)) {
+ rpc.forward();
+ }
+ }
+ });
+ getWidget().setListener(new BackwardListener() {
+ @Override
+ public void backward() {
+ if (hasEventListener(CalendarEventId.BACKWARD)) {
+ rpc.backward();
+ }
+ }
+ });
+ getWidget().setListener(new RangeSelectListener() {
+ @Override
+ public void rangeSelected(String value) {
+ if (hasEventListener(CalendarEventId.RANGESELECT)) {
+ rpc.rangeSelect(value);
+ }
+ }
+ });
+ getWidget().setListener(new WeekClickListener() {
+ @Override
+ public void weekClick(String event) {
+ if (!getWidget().isDisabledOrReadOnly()
+ && hasEventListener(CalendarEventId.WEEKCLICK)) {
+ rpc.weekClick(event);
+ }
+ }
+ });
+ getWidget().setListener(new EventMovedListener() {
+ @Override
+ public void eventMoved(CalendarEvent event) {
+ if (hasEventListener(CalendarEventId.EVENTMOVE)) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(DateUtil.formatClientSideDate(event.getStart()));
+ sb.append("-");
+ sb.append(DateUtil.formatClientSideTime(event
+ .getStartTime()));
+ rpc.eventMove(event.getIndex(), sb.toString());
+ }
+ }
+ });
+ getWidget().setListener(new EventResizeListener() {
+ @Override
+ public void eventResized(CalendarEvent event) {
+ if (hasEventListener(CalendarEventId.EVENTRESIZE)) {
+ StringBuilder buffer = new StringBuilder();
+
+ buffer.append(DateUtil.formatClientSideDate(event
+ .getStart()));
+ buffer.append("-");
+ buffer.append(DateUtil.formatClientSideTime(event
+ .getStartTime()));
+
+ String newStartDate = buffer.toString();
+
+ buffer = new StringBuilder();
+ buffer.append(DateUtil.formatClientSideDate(event.getEnd()));
+ buffer.append("-");
+ buffer.append(DateUtil.formatClientSideTime(event
+ .getEndTime()));
+
+ String newEndDate = buffer.toString();
+
+ rpc.eventResize(event.getIndex(), newStartDate, newEndDate);
+ }
+ }
+ });
+ getWidget().setListener(new VCalendar.ScrollListener() {
+ @Override
+ public void scroll(int scrollPosition) {
+ // This call is @Delayed (== non-immediate)
+ rpc.scroll(scrollPosition);
+ }
+ });
+ getWidget().setListener(new EventClickListener() {
+ @Override
+ public void eventClick(CalendarEvent event) {
+ if (hasEventListener(CalendarEventId.EVENTCLICK)) {
+ rpc.eventClick(event.getIndex());
+ }
+ }
+ });
+ getWidget().setListener(new MouseEventListener() {
+ @Override
+ public void contextMenu(ContextMenuEvent event, final Widget widget) {
+ final NativeEvent ne = event.getNativeEvent();
+ int left = ne.getClientX();
+ int top = ne.getClientY();
+ top += Window.getScrollTop();
+ left += Window.getScrollLeft();
+ getClient().getContextMenu().showAt(new ActionOwner() {
+ @Override
+ public String getPaintableId() {
+ return CalendarConnector.this.getPaintableId();
+ }
+
+ @Override
+ public ApplicationConnection getClient() {
+ return CalendarConnector.this.getClient();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public Action[] getActions() {
+ if (widget instanceof SimpleDayCell) {
+ /*
+ * Month view
+ */
+ SimpleDayCell cell = (SimpleDayCell) widget;
+ Date start = new Date(cell.getDate().getYear(),
+ cell.getDate().getMonth(), cell.getDate()
+ .getDate(), 0, 0, 0);
+
+ Date end = new Date(cell.getDate().getYear(), cell
+ .getDate().getMonth(), cell.getDate()
+ .getDate(), 23, 59, 59);
+
+ return CalendarConnector.this.getActionsBetween(
+ start, end);
+ } else if (widget instanceof DateCell) {
+ /*
+ * Week and Day view
+ */
+ DateCell cell = (DateCell) widget;
+ int slotIndex = DOM.getChildIndex(
+ cell.getElement(), (Element) ne
+ .getEventTarget().cast());
+ DateCellSlot slot = cell.getSlot(slotIndex);
+ return CalendarConnector.this.getActionsBetween(
+ slot.getFrom(), slot.getTo());
+ } else if (widget instanceof DateCellDayEvent) {
+ /*
+ * Context menu on event
+ */
+ DateCellDayEvent dayEvent = (DateCellDayEvent) widget;
+ CalendarEvent event = dayEvent.getCalendarEvent();
+ Action[] actions = CalendarConnector.this
+ .getActionsBetween(event.getStartTime(),
+ event.getEndTime());
+ for (Action action : actions) {
+ ((VCalendarAction) action).setEvent(event);
+ }
+ return actions;
+
+ }
+ return null;
+ }
+ }, left, top);
+ }
+ });
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ CalendarState state = getState();
+ VCalendar widget = getWidget();
+ boolean monthView = state.days.size() > 7;
+
+ // Enable or disable the forward and backward navigation buttons
+ widget.setForwardNavigationEnabled(hasEventListener(CalendarEventId.FORWARD));
+ widget.setBackwardNavigationEnabled(hasEventListener(CalendarEventId.BACKWARD));
+
+ widget.set24HFormat(state.format24H);
+ widget.setDayNames(state.dayNames);
+ widget.setMonthNames(state.monthNames);
+ widget.setFirstDayNumber(state.firstVisibleDayOfWeek);
+ widget.setLastDayNumber(state.lastVisibleDayOfWeek);
+ widget.setFirstHourOfTheDay(state.firstHourOfDay);
+ widget.setLastHourOfTheDay(state.lastHourOfDay);
+ widget.setReadOnly(state.readOnly);
+ widget.setDisabled(!state.enabled);
+
+ widget.setRangeSelectAllowed(hasEventListener(CalendarEventId.RANGESELECT));
+ widget.setRangeMoveAllowed(hasEventListener(CalendarEventId.EVENTMOVE));
+ widget.setEventMoveAllowed(hasEventListener(CalendarEventId.EVENTMOVE));
+ widget.setEventResizeAllowed(hasEventListener(CalendarEventId.EVENTRESIZE));
+
+ List<CalendarState.Day> days = state.days;
+ List<CalendarState.Event> events = state.events;
+
+ if (monthView) {
+ updateMonthView(days, events);
+ } else {
+ updateWeekView(days, events);
+ }
+
+ updateSizes();
+
+ registerEventToolTips(state.events);
+ updateActionMap(state.actions);
+ }
+
+ /*
+ * (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) {
+
+ // check for DD -related access criteria
+ // Iterator<Object> childIterator = uidl.getChildIterator();
+ // while (childIterator.hasNext()) {
+ // UIDL child = (UIDL) childIterator.next();
+ //
+ // // Drag&drop
+ // if (ACCESSCRITERIA.equals(child.getTag())) {
+ // if (monthView
+ // && !(getDropHandler() instanceof CalendarMonthDropHandler)) {
+ // setDropHandler(new CalendarMonthDropHandler());
+ //
+ // } else if (!monthView
+ // && !(getDropHandler() instanceof CalendarWeekDropHandler)) {
+ // setDropHandler(new CalendarWeekDropHandler());
+ // }
+ //
+ // getDropHandler().setCalendarPaintable(this);
+ // getDropHandler().updateAcceptRules(child);
+ //
+ // } else {
+ // setDropHandler(null);
+ // }
+ //
+ // }
+ }
+
+ /**
+ * Returns the ApplicationConnection used to connect to the server side
+ */
+ @Override
+ public ApplicationConnection getClient() {
+ return getConnection();
+ }
+
+ /**
+ * Register the description of the events as tooltips. This way, any event
+ * displaying widget can use the event index as a key to display the
+ * tooltip.
+ */
+ private void registerEventToolTips(List<CalendarState.Event> events) {
+ for (CalendarState.Event e : events) {
+ if (e.description != null && !"".equals(e.description)) {
+ tooltips.put(e.index, e.description);
+ } else {
+ tooltips.remove(e.index);
+ }
+ }
+ }
+
+ @Override
+ public TooltipInfo getTooltipInfo(com.google.gwt.dom.client.Element element) {
+ TooltipInfo tooltipInfo = null;
+ Widget w = Util.findWidget((Element) element, null);
+ if (w instanceof HasTooltipKey) {
+ tooltipInfo = GWT.create(TooltipInfo.class);
+ String title = tooltips.get(((HasTooltipKey) w).getTooltipKey());
+ tooltipInfo.setTitle(title != null ? title : "");
+ }
+ if (tooltipInfo == null) {
+ tooltipInfo = super.getTooltipInfo(element);
+ }
+ return tooltipInfo;
+ }
+
+ @Override
+ public boolean hasTooltip() {
+ /*
+ * Tooltips are not processed until updateFromUIDL, so we can't be sure
+ * that there are no tooltips during onStateChange when this is used.
+ */
+ return true;
+ }
+
+ private void updateMonthView(List<CalendarState.Day> days,
+ List<CalendarState.Event> events) {
+ CalendarState state = getState();
+ getWidget().updateMonthView(state.firstDayOfWeek,
+ getWidget().getDateTimeFormat().parse(state.now), days.size(),
+ calendarEventListOf(events, state.format24H),
+ calendarDayListOf(days));
+ }
+
+ private void updateWeekView(List<CalendarState.Day> days,
+ List<CalendarState.Event> events) {
+ CalendarState state = getState();
+ getWidget().updateWeekView(state.scroll,
+ getWidget().getDateTimeFormat().parse(state.now), days.size(),
+ state.firstDayOfWeek,
+ calendarEventListOf(events, state.format24H),
+ calendarDayListOf(days));
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VHasDropHandler#getDropHandler()
+ */
+ @Override
+ public CalendarDropHandler getDropHandler() {
+ return dropHandler;
+ }
+
+ /**
+ * Set the drop handler
+ *
+ * @param dropHandler
+ * The drophandler to use
+ */
+ public void setDropHandler(CalendarDropHandler dropHandler) {
+ this.dropHandler = dropHandler;
+ }
+
+ private Action[] getActionsBetween(Date start, Date end) {
+ List<Action> actions = new ArrayList<Action>();
+ for (int i = 0; i < actionKeys.size(); i++) {
+ final String actionKey = actionKeys.get(i);
+ Date actionStartDate;
+ Date actionEndDate;
+ try {
+ actionStartDate = getActionStartDate(actionKey);
+ actionEndDate = getActionEndDate(actionKey);
+ } catch (ParseException pe) {
+ VConsole.error("Failed to parse action date");
+ continue;
+ }
+
+ boolean startIsValid = start.compareTo(actionStartDate) >= 0;
+ boolean endIsValid = end.compareTo(actionEndDate) <= 0;
+ if (startIsValid && endIsValid) {
+ VCalendarAction a = new VCalendarAction(this, rpc, actionKey);
+ a.setCaption(getActionCaption(actionKey));
+ a.setIconUrl(getActionIcon(actionKey));
+ a.setActionStartDate(start);
+ a.setActionEndDate(end);
+ actions.add(a);
+ }
+ }
+
+ return actions.toArray(new Action[actions.size()]);
+ }
+
+ private List<String> actionKeys = new ArrayList<String>();
+
+ private void updateActionMap(List<CalendarState.Action> actions) {
+ actionMap.clear();
+ actionKeys.clear();
+
+ if (actions == null) {
+ return;
+ }
+
+ for (CalendarState.Action action : actions) {
+ String id = action.actionKey + "-" + action.startDate + "-"
+ + action.endDate;
+ actionMap.put(id + "_c", action.caption);
+ actionMap.put(id + "_s", action.startDate);
+ actionMap.put(id + "_e", action.endDate);
+ actionKeys.add(id);
+ if (action.iconKey != null) {
+ actionMap.put(id + "_i", getResourceUrl(action.iconKey));
+
+ } else {
+ actionMap.remove(id + "_i");
+ }
+ }
+ }
+
+ /**
+ * Get the text that is displayed for a context menu item
+ *
+ * @param actionKey
+ * The unique action key
+ * @return
+ */
+ public String getActionCaption(String actionKey) {
+ return actionMap.get(actionKey + "_c");
+ }
+
+ /**
+ * Get the icon url for a context menu item
+ *
+ * @param actionKey
+ * The unique action key
+ * @return
+ */
+ public String getActionIcon(String actionKey) {
+ return actionMap.get(actionKey + "_i");
+ }
+
+ /**
+ * Get the start date for an action item
+ *
+ * @param actionKey
+ * The unique action key
+ * @return
+ * @throws ParseException
+ */
+ public Date getActionStartDate(String actionKey) throws ParseException {
+ String dateStr = actionMap.get(actionKey + "_s");
+ DateTimeFormat formatter = DateTimeFormat
+ .getFormat(DateConstants.ACTION_DATE_FORMAT_PATTERN);
+ return formatter.parse(dateStr);
+ }
+
+ /**
+ * Get the end date for an action item
+ *
+ * @param actionKey
+ * The unique action key
+ * @return
+ * @throws ParseException
+ */
+ public Date getActionEndDate(String actionKey) throws ParseException {
+ String dateStr = actionMap.get(actionKey + "_e");
+ DateTimeFormat formatter = DateTimeFormat
+ .getFormat(DateConstants.ACTION_DATE_FORMAT_PATTERN);
+ return formatter.parse(dateStr);
+ }
+
+ /**
+ * Returns ALL currently registered events. Use {@link #getActions(Date)} to
+ * get the actions for a specific date
+ */
+ @Override
+ public Action[] getActions() {
+ List<Action> actions = new ArrayList<Action>();
+ for (int i = 0; i < actionKeys.size(); i++) {
+ final String actionKey = actionKeys.get(i);
+ final VCalendarAction a = new VCalendarAction(this, rpc, actionKey);
+ a.setCaption(getActionCaption(actionKey));
+ a.setIconUrl(getActionIcon(actionKey));
+
+ try {
+ a.setActionStartDate(getActionStartDate(actionKey));
+ a.setActionEndDate(getActionEndDate(actionKey));
+ } catch (ParseException pe) {
+ VConsole.error(pe);
+ }
+
+ actions.add(a);
+ }
+ return actions.toArray(new Action[actions.size()]);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.ui.ActionOwner#getPaintableId()
+ */
+ @Override
+ public String getPaintableId() {
+ return getConnectorId();
+ }
+
+ private List<CalendarEvent> calendarEventListOf(
+ List<CalendarState.Event> events, boolean format24h) {
+ List<CalendarEvent> list = new ArrayList<CalendarEvent>(events.size());
+ for (CalendarState.Event event : events) {
+ final String dateFrom = event.dateFrom;
+ final String dateTo = event.dateTo;
+ final String timeFrom = event.timeFrom;
+ final String timeTo = event.timeTo;
+ CalendarEvent calendarEvent = new CalendarEvent();
+ calendarEvent.setAllDay(event.allDay);
+ calendarEvent.setCaption(event.caption);
+ calendarEvent.setDescription(event.description);
+ calendarEvent.setStart(getWidget().getDateFormat().parse(dateFrom));
+ calendarEvent.setEnd(getWidget().getDateFormat().parse(dateTo));
+ calendarEvent.setFormat24h(format24h);
+ calendarEvent.setStartTime(getWidget().getDateTimeFormat().parse(
+ dateFrom + " " + timeFrom));
+ calendarEvent.setEndTime(getWidget().getDateTimeFormat().parse(
+ dateTo + " " + timeTo));
+ calendarEvent.setStyleName(event.styleName);
+ calendarEvent.setIndex(event.index);
+ list.add(calendarEvent);
+ }
+ return list;
+ }
+
+ private List<CalendarDay> calendarDayListOf(List<CalendarState.Day> days) {
+ List<CalendarDay> list = new ArrayList<CalendarDay>(days.size());
+ for (CalendarState.Day day : days) {
+ CalendarDay d = new CalendarDay(day.date, day.localizedDateFormat,
+ day.dayOfWeek, day.week);
+
+ list.add(d);
+ }
+ return list;
+ }
+
+ @Override
+ public void layout() {
+ updateSizes();
+ }
+
+ private void updateSizes() {
+ int height = getLayoutManager()
+ .getOuterHeight(getWidget().getElement());
+ int width = getLayoutManager().getOuterWidth(getWidget().getElement());
+
+ if (isUndefinedWidth()) {
+ width = -1;
+ }
+ if (isUndefinedHeight()) {
+ height = -1;
+ }
+
+ getWidget().setSizeForChildren(width, height);
+
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/VCalendarAction.java b/client/src/com/vaadin/client/ui/calendar/VCalendarAction.java
new file mode 100644
index 0000000000..2a529354e5
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/VCalendarAction.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar;
+
+import java.util.Date;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.vaadin.client.ui.Action;
+import com.vaadin.client.ui.calendar.schedule.CalendarEvent;
+import com.vaadin.shared.ui.calendar.CalendarServerRpc;
+import com.vaadin.shared.ui.calendar.DateConstants;
+
+/**
+ * Action performed by the calendar
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class VCalendarAction extends Action {
+
+ private CalendarServerRpc rpc;
+
+ private String actionKey = "";
+
+ private Date actionStartDate;
+
+ private Date actionEndDate;
+
+ private CalendarEvent event;
+
+ private final DateTimeFormat dateformat_datetime = DateTimeFormat
+ .getFormat(DateConstants.ACTION_DATE_FORMAT_PATTERN);
+
+ /**
+ *
+ * @param owner
+ */
+ public VCalendarAction(CalendarConnector owner) {
+ super(owner);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param owner
+ * The owner who trigger this kinds of events
+ * @param rpc
+ * The CalendarRpc which is used for executing actions
+ * @param key
+ * The unique action key which identifies this particular action
+ */
+ public VCalendarAction(CalendarConnector owner, CalendarServerRpc rpc,
+ String key) {
+ this(owner);
+ this.rpc = rpc;
+ actionKey = key;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.terminal.gwt.client.ui.Action#execute()
+ */
+ @Override
+ public void execute() {
+ String startDate = dateformat_datetime.format(actionStartDate);
+ String endDate = dateformat_datetime.format(actionEndDate);
+
+ if (event == null) {
+ rpc.actionOnEmptyCell(actionKey.split("-")[0], startDate, endDate);
+ } else {
+ rpc.actionOnEvent(actionKey.split("-")[0], startDate, endDate,
+ event.getIndex());
+ }
+
+ owner.getClient().getContextMenu().hide();
+ }
+
+ /**
+ * Get the date and time when the action starts
+ *
+ * @return
+ */
+ public Date getActionStartDate() {
+ return actionStartDate;
+ }
+
+ /**
+ * Set the date when the actions start
+ *
+ * @param actionStartDate
+ * The date and time when the action starts
+ */
+ public void setActionStartDate(Date actionStartDate) {
+ this.actionStartDate = actionStartDate;
+ }
+
+ /**
+ * Get the date and time when the action ends
+ *
+ * @return
+ */
+ public Date getActionEndDate() {
+ return actionEndDate;
+ }
+
+ /**
+ * Set the date and time when the action ends
+ *
+ * @param actionEndDate
+ * The date and time when the action ends
+ */
+ public void setActionEndDate(Date actionEndDate) {
+ this.actionEndDate = actionEndDate;
+ }
+
+ public CalendarEvent getEvent() {
+ return event;
+ }
+
+ public void setEvent(CalendarEvent event) {
+ this.event = event;
+ }
+
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java b/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java
new file mode 100644
index 0000000000..ca176c08c1
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/CalendarDay.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+/**
+ * Utility class used to represent a day when updating views. Only used
+ * internally.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class CalendarDay {
+ private String date;
+ private String localizedDateFormat;
+ private int dayOfWeek;
+ private int week;
+
+ public CalendarDay(String date, String localizedDateFormat, int dayOfWeek,
+ int week) {
+ super();
+ this.date = date;
+ this.localizedDateFormat = localizedDateFormat;
+ this.dayOfWeek = dayOfWeek;
+ this.week = week;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public String getLocalizedDateFormat() {
+ return localizedDateFormat;
+ }
+
+ public int getDayOfWeek() {
+ return dayOfWeek;
+ }
+
+ public int getWeek() {
+ return week;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/CalendarEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/CalendarEvent.java
new file mode 100644
index 0000000000..e2c06d41ea
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/CalendarEvent.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.vaadin.shared.ui.calendar.DateConstants;
+
+/**
+ * A client side implementation of a calendar event
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class CalendarEvent {
+ private int index;
+ private String caption;
+ private Date start, end;
+ private String styleName;
+ private Date startTime, endTime;
+ private String description;
+ private int slotIndex = -1;
+ private boolean format24h;
+
+ DateTimeFormat dateformat_date = DateTimeFormat.getFormat("h:mm a");
+ DateTimeFormat dateformat_date24 = DateTimeFormat.getFormat("H:mm");
+ private boolean allDay;
+
+ /**
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getStyleName()
+ */
+ public String getStyleName() {
+ return styleName;
+ }
+
+ /**
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getStart()
+ */
+ public Date getStart() {
+ return start;
+ }
+
+ /**
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getStyleName()
+ * @param style
+ */
+ public void setStyleName(String style) {
+ styleName = style;
+ }
+
+ /**
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getStart()
+ * @param start
+ */
+ public void setStart(Date start) {
+ this.start = start;
+ }
+
+ /**
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getEnd()
+ * @return
+ */
+ public Date getEnd() {
+ return end;
+ }
+
+ /**
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getEnd()
+ * @param end
+ */
+ public void setEnd(Date end) {
+ this.end = end;
+ }
+
+ /**
+ * Returns the start time of the event
+ *
+ * @return Time embedded in the {@link Date} object
+ */
+ public Date getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Set the start time of the event
+ *
+ * @param startTime
+ * The time of the event. Use the time fields in the {@link Date}
+ * object
+ */
+ public void setStartTime(Date startTime) {
+ this.startTime = startTime;
+ }
+
+ /**
+ * Get the end time of the event
+ *
+ * @return Time embedded in the {@link Date} object
+ */
+ public Date getEndTime() {
+ return endTime;
+ }
+
+ /**
+ * Set the end time of the event
+ *
+ * @param endTime
+ * Time embedded in the {@link Date} object
+ */
+ public void setEndTime(Date endTime) {
+ this.endTime = endTime;
+ }
+
+ /**
+ * Get the (server side) index of the event
+ *
+ * @return
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Get the index of the slot where the event in rendered
+ *
+ * @return
+ */
+ public int getSlotIndex() {
+ return slotIndex;
+ }
+
+ /**
+ * Set the index of the slot where the event in rendered
+ *
+ * @param index
+ * The index of the slot
+ */
+ public void setSlotIndex(int index) {
+ slotIndex = index;
+ }
+
+ /**
+ * Set the (server side) index of the event
+ *
+ * @param index
+ * The index
+ */
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ /**
+ * Get the caption of the event. The caption is the text displayed in the
+ * calendar on the event.
+ *
+ * @return
+ */
+ public String getCaption() {
+ return caption;
+ }
+
+ /**
+ * Set the caption of the event. The caption is the text displayed in the
+ * calendar on the event.
+ *
+ * @param caption
+ * The visible caption of the event
+ */
+ public void setCaption(String caption) {
+ this.caption = caption;
+ }
+
+ /**
+ * Get the description of the event. The description is the text displayed
+ * when hoovering over the event with the mouse
+ *
+ * @return
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Set the description of the event. The description is the text displayed
+ * when hoovering over the event with the mouse
+ *
+ * @param description
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Does the event use the 24h time format
+ *
+ * @param format24h
+ * True if it uses the 24h format, false if it uses the 12h time
+ * format
+ */
+ public void setFormat24h(boolean format24h) {
+ this.format24h = format24h;
+ }
+
+ /**
+ * Is the event an all day event.
+ *
+ * @param allDay
+ * True if the event should be rendered all day
+ */
+ public void setAllDay(boolean allDay) {
+ this.allDay = allDay;
+ }
+
+ /**
+ * Is the event an all day event.
+ *
+ * @return
+ */
+ public boolean isAllDay() {
+ return allDay;
+ }
+
+ /**
+ * Get the time as a formatted string
+ *
+ * @return
+ */
+ public String getTimeAsText() {
+ if (format24h) {
+ return dateformat_date24.format(startTime);
+ } else {
+ return dateformat_date.format(startTime);
+ }
+ }
+
+ /**
+ * Get the amount of milliseconds between the start and end of the event
+ *
+ * @return
+ */
+ public long getRangeInMilliseconds() {
+ return getEndTime().getTime() - getStartTime().getTime();
+ }
+
+ /**
+ * Get the amount of minutes between the start and end of the event
+ *
+ * @return
+ */
+ public long getRangeInMinutes() {
+ return (getRangeInMilliseconds() / DateConstants.MINUTEINMILLIS);
+ }
+
+ /**
+ * Get the amount of minutes for the event on a specific day. This is useful
+ * if the event spans several days.
+ *
+ * @param targetDay
+ * The date to check
+ * @return
+ */
+ public long getRangeInMinutesForDay(Date targetDay) {
+ if (isTimeOnDifferentDays()) {
+ // Time range is on different days. Calculate the second day's
+ // range.
+ long range = (getEndTime().getTime() - getEnd().getTime())
+ / DateConstants.MINUTEINMILLIS;
+
+ if (getEnd().compareTo(targetDay) != 0) {
+ // Calculate first day's range.
+ return getRangeInMinutes() - range;
+ }
+
+ return range;
+ } else {
+ return getRangeInMinutes();
+ }
+ }
+
+ /**
+ * Does the event span several days
+ *
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ public boolean isTimeOnDifferentDays() {
+ if (getEndTime().getTime() - getStart().getTime() > DateConstants.DAYINMILLIS) {
+ return true;
+ }
+
+ if (getStart().compareTo(getEnd()) != 0) {
+ if (getEndTime().getHours() == 0 && getEndTime().getMinutes() == 0) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCell.java
new file mode 100644
index 0000000000..516447153e
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCell.java
@@ -0,0 +1,810 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.Style.Display;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.event.dom.client.ContextMenuHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.Util;
+
+public class DateCell extends FocusableComplexPanel implements
+ MouseDownHandler, MouseMoveHandler, MouseUpHandler, KeyDownHandler,
+ ContextMenuHandler {
+ private static final String DRAGEMPHASISSTYLE = " dragemphasis";
+ private Date date;
+ private int width;
+ private int eventRangeStart = -1;
+ private int eventRangeStop = -1;
+ final WeekGrid weekgrid;
+ private boolean disabled = false;
+ private int height;
+ private final Element[] slotElements;
+ private final List<DateCellSlot> slots = new ArrayList<DateCell.DateCellSlot>();
+ private int[] slotElementHeights;
+ private int startingSlotHeight;
+ private Date today;
+ private Element todaybar;
+ private final List<HandlerRegistration> handlers;
+ private final int numberOfSlots;
+ private final int firstHour;
+ private final int lastHour;
+
+ public class DateCellSlot extends Widget {
+
+ private final DateCell cell;
+
+ private final Date from;
+
+ private final Date to;
+
+ public DateCellSlot(DateCell cell, Date from, Date to) {
+ setElement(DOM.createDiv());
+ getElement().setInnerHTML("&nbsp;");
+ this.cell = cell;
+ this.from = from;
+ this.to = to;
+ }
+
+ public Date getFrom() {
+ return from;
+ }
+
+ public Date getTo() {
+ return to;
+ }
+
+ public DateCell getParentCell() {
+ return cell;
+ }
+ }
+
+ public DateCell(WeekGrid parent, Date date) {
+ weekgrid = parent;
+ Element mainElement = DOM.createDiv();
+ setElement(mainElement);
+ makeFocusable();
+ setDate(date);
+
+ addStyleName("v-calendar-day-times");
+
+ handlers = new LinkedList<HandlerRegistration>();
+
+ // 2 slots / hour
+ firstHour = weekgrid.getFirstHour();
+ lastHour = weekgrid.getLastHour();
+ numberOfSlots = (lastHour - firstHour + 1) * 2;
+ long slotTime = Math.round(((lastHour - firstHour + 1) * 3600000.0)
+ / numberOfSlots);
+
+ slotElements = new Element[numberOfSlots];
+ slotElementHeights = new int[numberOfSlots];
+
+ slots.clear();
+ long start = getDate().getTime() + firstHour * 3600000;
+ long end = start + slotTime;
+ for (int i = 0; i < numberOfSlots; i++) {
+ DateCellSlot slot = new DateCellSlot(this, new Date(start),
+ new Date(end));
+ if (i % 2 == 0) {
+ slot.setStyleName("v-datecellslot-even");
+ } else {
+ slot.setStyleName("v-datecellslot");
+ }
+ Event.sinkEvents(slot.getElement(), Event.MOUSEEVENTS);
+ mainElement.appendChild(slot.getElement());
+ slotElements[i] = slot.getElement();
+ slots.add(slot);
+ start = end;
+ end = start + slotTime;
+ }
+
+ // Sink events for tooltip handling
+ Event.sinkEvents(mainElement, Event.MOUSEEVENTS);
+ }
+
+ public int getFirstHour() {
+ return firstHour;
+ }
+
+ public int getLastHour() {
+ return lastHour;
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+
+ handlers.add(addHandler(this, MouseDownEvent.getType()));
+ handlers.add(addHandler(this, MouseUpEvent.getType()));
+ handlers.add(addHandler(this, MouseMoveEvent.getType()));
+ handlers.add(addDomHandler(this, ContextMenuEvent.getType()));
+ handlers.add(addKeyDownHandler(this));
+ }
+
+ @Override
+ protected void onDetach() {
+ for (HandlerRegistration handler : handlers) {
+ handler.removeHandler();
+ }
+ handlers.clear();
+
+ super.onDetach();
+ }
+
+ public int getSlotIndex(Element slotElement) {
+ for (int i = 0; i < slotElements.length; i++) {
+ if (slotElement == slotElements[i]) {
+ return i;
+ }
+ }
+
+ throw new IllegalArgumentException("Element not found in this DateCell");
+ }
+
+ public DateCellSlot getSlot(int index) {
+ return slots.get(index);
+ }
+
+ public int getNumberOfSlots() {
+ return numberOfSlots;
+ }
+
+ public void setTimeBarWidth(int timebarWidth) {
+ todaybar.getStyle().setWidth(timebarWidth, Unit.PX);
+ }
+
+ /**
+ * @param isHorizontalSized
+ * if true, this DateCell is sized with CSS and not via
+ * {@link #setWidthPX(int)}
+ */
+ public void setHorizontalSized(boolean isHorizontalSized) {
+ if (isHorizontalSized) {
+ addStyleDependentName("Hsized");
+
+ width = getOffsetWidth()
+ - Util.measureHorizontalBorder(getElement());
+ recalculateEventWidths();
+ } else {
+ removeStyleDependentName("Hsized");
+ }
+ }
+
+ /**
+ * @param isVerticalSized
+ * if true, this DateCell is sized with CSS and not via
+ * {@link #setHeightPX(int)}
+ */
+ public void setVerticalSized(boolean isVerticalSized) {
+ if (isVerticalSized) {
+ addStyleDependentName("Vsized");
+
+ // recalc heights&size for events. all other height sizes come
+ // from css
+ startingSlotHeight = slotElements[0].getOffsetHeight();
+ recalculateEventPositions();
+
+ if (isToday()) {
+ recalculateTimeBarPosition();
+ }
+
+ } else {
+ removeStyleDependentName("Vsized");
+ }
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public void setWidthPX(int cellWidth) {
+ width = cellWidth;
+ setWidth(cellWidth + "px");
+ recalculateEventWidths();
+ }
+
+ public void setHeightPX(int height, int[] cellHeights) {
+ this.height = height;
+ slotElementHeights = cellHeights;
+ setHeight(height + "px");
+ recalculateCellHeights();
+ recalculateEventPositions();
+ if (today != null) {
+ recalculateTimeBarPosition();
+ }
+ }
+
+ // date methods are not deprecated in GWT
+ @SuppressWarnings("deprecation")
+ private void recalculateTimeBarPosition() {
+ int h = today.getHours();
+ int m = today.getMinutes();
+ if (h >= firstHour && h <= lastHour) {
+ int pixelTop = weekgrid.getPixelTopFor(m + 60 * h);
+ todaybar.getStyle().clearDisplay();
+ todaybar.getStyle().setTop(pixelTop, Unit.PX);
+ } else {
+ todaybar.getStyle().setDisplay(Display.NONE);
+ }
+ }
+
+ private void recalculateEventPositions() {
+ for (int i = 0; i < getWidgetCount(); i++) {
+ DateCellDayEvent dayEvent = (DateCellDayEvent) getWidget(i);
+ updatePositionFor(dayEvent, getDate(), dayEvent.getCalendarEvent());
+ }
+ }
+
+ public void recalculateEventWidths() {
+ List<DateCellGroup> groups = new ArrayList<DateCellGroup>();
+
+ int count = getWidgetCount();
+
+ List<Integer> handled = new ArrayList<Integer>();
+
+ // Iterate through all events and group them. Events that overlaps
+ // with each other, are added to the same group.
+ for (int i = 0; i < count; i++) {
+ if (handled.contains(i)) {
+ continue;
+ }
+
+ DateCellGroup curGroup = getOverlappingEvents(i);
+ handled.addAll(curGroup.getItems());
+
+ boolean newGroup = true;
+ // No need to check other groups, if size equals the count
+ if (curGroup.getItems().size() != count) {
+ // Check other groups. When the whole group overlaps with
+ // other group, the group is merged to the other.
+ for (DateCellGroup g : groups) {
+
+ if (WeekGridMinuteTimeRange.doesOverlap(
+ curGroup.getDateRange(), g.getDateRange())) {
+ newGroup = false;
+ updateGroup(g, curGroup);
+ }
+ }
+ } else {
+ if (newGroup) {
+ groups.add(curGroup);
+ }
+ break;
+ }
+
+ if (newGroup) {
+ groups.add(curGroup);
+ }
+ }
+
+ drawDayEvents(groups);
+ }
+
+ private void recalculateCellHeights() {
+ startingSlotHeight = height / numberOfSlots;
+
+ for (int i = 0; i < slotElements.length; i++) {
+ slotElements[i].getStyle()
+ .setHeight(slotElementHeights[i], Unit.PX);
+ }
+
+ Iterator<Widget> it = iterator();
+ while (it.hasNext()) {
+ Widget child = it.next();
+ if (child instanceof DateCellDayEvent) {
+ ((DateCellDayEvent) child).setSlotHeightInPX(getSlotHeight());
+ }
+
+ }
+ }
+
+ public int getSlotHeight() {
+ return startingSlotHeight;
+ }
+
+ public int getSlotBorder() {
+ return Util
+ .measureVerticalBorder((com.google.gwt.user.client.Element) slotElements[0]);
+ }
+
+ private void drawDayEvents(List<DateCellGroup> groups) {
+ for (DateCellGroup g : groups) {
+ int col = 0;
+ int colCount = 0;
+ List<Integer> order = new ArrayList<Integer>();
+ Map<Integer, Integer> columns = new HashMap<Integer, Integer>();
+ for (Integer eventIndex : g.getItems()) {
+ DateCellDayEvent d = (DateCellDayEvent) getWidget(eventIndex);
+ d.setMoveWidth(width);
+
+ int freeSpaceCol = findFreeColumnSpaceOnLeft(
+ new WeekGridMinuteTimeRange(d.getCalendarEvent()
+ .getStartTime(), d.getCalendarEvent()
+ .getEndTime()), order, columns);
+ if (freeSpaceCol >= 0) {
+ col = freeSpaceCol;
+ columns.put(eventIndex, col);
+ int newOrderindex = 0;
+ for (Integer i : order) {
+ if (columns.get(i) >= col) {
+ newOrderindex = order.indexOf(i);
+ break;
+ }
+ }
+ order.add(newOrderindex, eventIndex);
+ } else {
+ // New column
+ col = colCount++;
+ columns.put(eventIndex, col);
+ order.add(eventIndex);
+ }
+ }
+
+ // Update widths and left position
+ int eventWidth = (width / colCount);
+ for (Integer index : g.getItems()) {
+ DateCellDayEvent d = (DateCellDayEvent) getWidget(index);
+ d.getElement()
+ .getStyle()
+ .setMarginLeft((eventWidth * columns.get(index)),
+ Unit.PX);
+ d.setWidth(eventWidth + "px");
+ d.setSlotHeightInPX(getSlotHeight());
+ }
+ }
+ }
+
+ private int findFreeColumnSpaceOnLeft(WeekGridMinuteTimeRange dateRange,
+ List<Integer> order, Map<Integer, Integer> columns) {
+ int freeSpot = -1;
+ int skipIndex = -1;
+ for (Integer eventIndex : order) {
+ int col = columns.get(eventIndex);
+ if (col == skipIndex) {
+ continue;
+ }
+
+ if (freeSpot != -1 && freeSpot != col) {
+ // Free spot found
+ return freeSpot;
+ }
+
+ DateCellDayEvent d = (DateCellDayEvent) getWidget(eventIndex);
+ WeekGridMinuteTimeRange nextRange = new WeekGridMinuteTimeRange(d
+ .getCalendarEvent().getStartTime(), d.getCalendarEvent()
+ .getEndTime());
+
+ if (WeekGridMinuteTimeRange.doesOverlap(dateRange, nextRange)) {
+ skipIndex = col;
+ freeSpot = -1;
+ } else {
+ freeSpot = col;
+ }
+ }
+
+ return freeSpot;
+ }
+
+ /* Update top and bottom date range values. Add new index to the group. */
+ private void updateGroup(DateCellGroup targetGroup, DateCellGroup byGroup) {
+ Date newStart = targetGroup.getStart();
+ Date newEnd = targetGroup.getEnd();
+ if (byGroup.getStart().before(targetGroup.getStart())) {
+ newStart = byGroup.getEnd();
+ }
+ if (byGroup.getStart().after(targetGroup.getEnd())) {
+ newStart = byGroup.getStart();
+ }
+
+ targetGroup.setDateRange(new WeekGridMinuteTimeRange(newStart, newEnd));
+
+ for (Integer index : byGroup.getItems()) {
+ if (!targetGroup.getItems().contains(index)) {
+ targetGroup.add(index);
+ }
+ }
+ }
+
+ /**
+ * Returns all overlapping DayEvent indexes in the Group. Including the
+ * target.
+ *
+ * @param targetIndex
+ * Index of DayEvent in the current DateCell widget.
+ * @return Group that contains all Overlapping DayEvent indexes
+ */
+ public DateCellGroup getOverlappingEvents(int targetIndex) {
+ DateCellGroup g = new DateCellGroup(targetIndex);
+
+ int count = getWidgetCount();
+ DateCellDayEvent target = (DateCellDayEvent) getWidget(targetIndex);
+ WeekGridMinuteTimeRange targetRange = new WeekGridMinuteTimeRange(
+ target.getCalendarEvent().getStartTime(), target
+ .getCalendarEvent().getEndTime());
+ Date groupStart = targetRange.getStart();
+ Date groupEnd = targetRange.getEnd();
+
+ for (int i = 0; i < count; i++) {
+ if (targetIndex == i) {
+ continue;
+ }
+
+ DateCellDayEvent d = (DateCellDayEvent) getWidget(i);
+ WeekGridMinuteTimeRange nextRange = new WeekGridMinuteTimeRange(d
+ .getCalendarEvent().getStartTime(), d.getCalendarEvent()
+ .getEndTime());
+ if (WeekGridMinuteTimeRange.doesOverlap(targetRange, nextRange)) {
+ g.add(i);
+
+ // Update top & bottom values to the greatest
+ if (nextRange.getStart().before(targetRange.getStart())) {
+ groupStart = targetRange.getStart();
+ }
+ if (nextRange.getEnd().after(targetRange.getEnd())) {
+ groupEnd = targetRange.getEnd();
+ }
+ }
+ }
+
+ g.setDateRange(new WeekGridMinuteTimeRange(groupStart, groupEnd));
+ return g;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void addEvent(Date targetDay, CalendarEvent calendarEvent) {
+ Element main = getElement();
+ DateCellDayEvent dayEvent = new DateCellDayEvent(this, weekgrid,
+ calendarEvent);
+ dayEvent.setSlotHeightInPX(getSlotHeight());
+ dayEvent.setDisabled(isDisabled());
+
+ if (startingSlotHeight > 0) {
+ updatePositionFor(dayEvent, targetDay, calendarEvent);
+ }
+
+ add(dayEvent, (com.google.gwt.user.client.Element) main);
+ }
+
+ // date methods are not deprecated in GWT
+ @SuppressWarnings("deprecation")
+ private void updatePositionFor(DateCellDayEvent dayEvent, Date targetDay,
+ CalendarEvent calendarEvent) {
+ if (canDisplay(calendarEvent)) {
+
+ dayEvent.getElement().getStyle().clearDisplay();
+
+ Date fromDt = calendarEvent.getStartTime();
+ int h = fromDt.getHours();
+ int m = fromDt.getMinutes();
+ long range = calendarEvent.getRangeInMinutesForDay(targetDay);
+
+ boolean onDifferentDays = calendarEvent.isTimeOnDifferentDays();
+ if (onDifferentDays) {
+ if (calendarEvent.getStart().compareTo(targetDay) != 0) {
+ // Current day slot is for the end date. Lets fix also
+ // the
+ // start & end times.
+ h = 0;
+ m = 0;
+ }
+ }
+
+ int startFromMinutes = (h * 60) + m;
+ dayEvent.updatePosition(startFromMinutes, range);
+
+ } else {
+ dayEvent.getElement().getStyle().setDisplay(Display.NONE);
+ }
+ }
+
+ public void addEvent(DateCellDayEvent dayEvent) {
+ Element main = getElement();
+ int index = 0;
+ List<CalendarEvent> events = new ArrayList<CalendarEvent>();
+
+ // events are the only widgets in this panel
+ // slots are just elements
+ for (; index < getWidgetCount(); index++) {
+ DateCellDayEvent dc = (DateCellDayEvent) getWidget(index);
+ dc.setDisabled(isDisabled());
+ events.add(dc.getCalendarEvent());
+ }
+ events.add(dayEvent.getCalendarEvent());
+
+ index = 0;
+ for (CalendarEvent e : weekgrid.getCalendar().sortEventsByDuration(
+ events)) {
+ if (e.equals(dayEvent.getCalendarEvent())) {
+ break;
+ }
+ index++;
+ }
+ this.insert(dayEvent, (com.google.gwt.user.client.Element) main, index,
+ true);
+ }
+
+ public void removeEvent(DateCellDayEvent dayEvent) {
+ remove(dayEvent);
+ }
+
+ /**
+ *
+ * @param event
+ * @return
+ */
+ // Date methods not deprecated in GWT
+ @SuppressWarnings("deprecation")
+ private boolean canDisplay(CalendarEvent event) {
+ Date eventStart = event.getStartTime();
+ Date eventEnd = event.getEndTime();
+
+ int eventStartHours = eventStart.getHours();
+ int eventEndHours = eventEnd.getHours();
+
+ return (eventStartHours <= lastHour) && (eventEndHours >= firstHour);
+ }
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ int keycode = event.getNativeEvent().getKeyCode();
+ if (keycode == KeyCodes.KEY_ESCAPE && eventRangeStart > -1) {
+ cancelRangeSelect();
+ }
+ }
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
+ Element e = Element.as(event.getNativeEvent().getEventTarget());
+ if (e.getClassName().contains("reserved") || isDisabled()
+ || !weekgrid.getParentCalendar().isRangeSelectAllowed()) {
+ eventRangeStart = -1;
+ } else {
+ eventRangeStart = event.getY();
+ eventRangeStop = eventRangeStart;
+ Event.setCapture(getElement());
+ setFocus(true);
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void onMouseUp(MouseUpEvent event) {
+ if (event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
+ return;
+ }
+ Event.releaseCapture(getElement());
+ setFocus(false);
+ int dragDistance = Math.abs(eventRangeStart - event.getY());
+ if (dragDistance > 0 && eventRangeStart >= 0) {
+ Element main = getElement();
+ if (eventRangeStart > eventRangeStop) {
+ if (eventRangeStop <= -1) {
+ eventRangeStop = 0;
+ }
+ int temp = eventRangeStart;
+ eventRangeStart = eventRangeStop;
+ eventRangeStop = temp;
+ }
+
+ NodeList<Node> nodes = main.getChildNodes();
+
+ int slotStart = -1;
+ int slotEnd = -1;
+
+ // iterate over all child nodes, until we find first the start,
+ // and then the end
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Element element = (Element) nodes.getItem(i);
+ boolean isRangeElement = element.getClassName().contains(
+ "v-daterange");
+
+ if (isRangeElement && slotStart == -1) {
+ slotStart = i;
+ slotEnd = i; // to catch one-slot selections
+
+ } else if (isRangeElement) {
+ slotEnd = i;
+
+ } else if (slotStart != -1 && slotEnd != -1) {
+ break;
+ }
+ }
+
+ clearSelectionRange();
+
+ int startMinutes = firstHour * 60 + slotStart * 30;
+ int endMinutes = (firstHour * 60) + (slotEnd + 1) * 30;
+ Date currentDate = getDate();
+ String yr = (currentDate.getYear() + 1900) + "-"
+ + (currentDate.getMonth() + 1) + "-"
+ + currentDate.getDate();
+ if (weekgrid.getCalendar().getRangeSelectListener() != null) {
+ weekgrid.getCalendar()
+ .getRangeSelectListener()
+ .rangeSelected(
+ yr + ":" + startMinutes + ":" + endMinutes);
+ }
+ eventRangeStart = -1;
+ } else {
+ // Click event
+ eventRangeStart = -1;
+ cancelRangeSelect();
+
+ }
+ }
+
+ @Override
+ public void onMouseMove(MouseMoveEvent event) {
+ if (event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
+ return;
+ }
+
+ if (eventRangeStart >= 0) {
+ int newY = event.getY();
+ int fromY = 0;
+ int toY = 0;
+ if (newY < eventRangeStart) {
+ fromY = newY;
+ toY = eventRangeStart;
+ } else {
+ fromY = eventRangeStart;
+ toY = newY;
+ }
+ Element main = getElement();
+ eventRangeStop = newY;
+ NodeList<Node> nodes = main.getChildNodes();
+ for (int i = 0; i < nodes.getLength(); i++) {
+ Element c = (Element) nodes.getItem(i);
+
+ if (todaybar != c) {
+
+ int elemStart = c.getOffsetTop();
+ int elemStop = elemStart + getSlotHeight();
+ if (elemStart >= fromY && elemStart <= toY) {
+ c.addClassName("v-daterange");
+ } else if (elemStop >= fromY && elemStop <= toY) {
+ c.addClassName("v-daterange");
+ } else if (elemStop >= fromY && elemStart <= toY) {
+ c.addClassName("v-daterange");
+ } else {
+ c.removeClassName("v-daterange");
+ }
+ }
+ }
+ }
+
+ event.preventDefault();
+ }
+
+ public void cancelRangeSelect() {
+ Event.releaseCapture(getElement());
+ setFocus(false);
+
+ clearSelectionRange();
+ }
+
+ private void clearSelectionRange() {
+ if (eventRangeStart > -1) {
+ // clear all "selected" class names
+ Element main = getElement();
+ NodeList<Node> nodes = main.getChildNodes();
+
+ for (int i = 0; i <= 47; i++) {
+ Element c = (Element) nodes.getItem(i);
+ if (c == null) {
+ continue;
+ }
+ c.removeClassName("v-daterange");
+ }
+
+ eventRangeStart = -1;
+ }
+ }
+
+ public void setToday(Date today, int width) {
+ this.today = today;
+ addStyleDependentName("today");
+ Element lastChild = (Element) getElement().getLastChild();
+ if (lastChild.getClassName().equals("v-calendar-current-time")) {
+ todaybar = lastChild;
+ } else {
+ todaybar = DOM.createDiv();
+ todaybar.setClassName("v-calendar-current-time");
+ getElement().appendChild(todaybar);
+ }
+
+ if (width != -1) {
+ todaybar.getStyle().setWidth(width, Unit.PX);
+ }
+
+ // position is calculated later, when we know the cell heights
+ }
+
+ public Element getTodaybarElement() {
+ return todaybar;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public void setDateColor(String styleName) {
+ this.setStyleName("v-calendar-datecell " + styleName);
+ }
+
+ public boolean isToday() {
+ return today != null;
+ }
+
+ public void addEmphasisStyle(com.google.gwt.user.client.Element elementOver) {
+ String originalStylename = getStyleName(elementOver);
+ setStyleName(elementOver, originalStylename + DRAGEMPHASISSTYLE);
+ }
+
+ public void removeEmphasisStyle(
+ com.google.gwt.user.client.Element elementOver) {
+ String originalStylename = getStyleName(elementOver);
+ setStyleName(
+ elementOver,
+ originalStylename.substring(0, originalStylename.length()
+ - DRAGEMPHASISSTYLE.length()));
+ }
+
+ @Override
+ public void onContextMenu(ContextMenuEvent event) {
+ if (weekgrid.getCalendar().getMouseEventListener() != null) {
+ event.preventDefault();
+ event.stopPropagation();
+ weekgrid.getCalendar().getMouseEventListener()
+ .contextMenu(event, DateCell.this);
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellContainer.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellContainer.java
new file mode 100644
index 0000000000..04e6bb7df6
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellContainer.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ * Internally used class by the Calendar
+ *
+ * since 7.1
+ */
+public class DateCellContainer extends FlowPanel implements MouseDownHandler,
+ MouseUpHandler {
+
+ private Date date;
+
+ private Widget clickTargetWidget;
+
+ private VCalendar calendar;
+
+ private static int borderWidth = -1;
+
+ public DateCellContainer() {
+ setStylePrimaryName("v-calendar-datecell");
+ }
+
+ public static int measureBorderWidth(DateCellContainer dc) {
+ if (borderWidth == -1) {
+ borderWidth = Util.measureHorizontalBorder(dc.getElement());
+ }
+ return borderWidth;
+ }
+
+ public void setCalendar(VCalendar calendar) {
+ this.calendar = calendar;
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public boolean hasEvent(int slotIndex) {
+ return hasDateCell(slotIndex)
+ && ((WeeklyLongEventsDateCell) getChildren().get(slotIndex))
+ .getEvent() != null;
+ }
+
+ public boolean hasDateCell(int slotIndex) {
+ return (getChildren().size() - 1) >= slotIndex;
+ }
+
+ public WeeklyLongEventsDateCell getDateCell(int slotIndex) {
+ if (!hasDateCell(slotIndex)) {
+ addEmptyEventCells(slotIndex - (getChildren().size() - 1));
+ }
+ return (WeeklyLongEventsDateCell) getChildren().get(slotIndex);
+ }
+
+ public void addEmptyEventCells(int eventCount) {
+ for (int i = 0; i < eventCount; i++) {
+ addEmptyEventCell();
+ }
+ }
+
+ public void addEmptyEventCell() {
+ WeeklyLongEventsDateCell dateCell = new WeeklyLongEventsDateCell();
+ dateCell.addMouseDownHandler(this);
+ dateCell.addMouseUpHandler(this);
+ add(dateCell);
+ }
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ clickTargetWidget = (Widget) event.getSource();
+
+ event.stopPropagation();
+ }
+
+ @Override
+ public void onMouseUp(MouseUpEvent event) {
+ if (event.getSource() == clickTargetWidget
+ && clickTargetWidget instanceof WeeklyLongEventsDateCell
+ && !calendar.isDisabledOrReadOnly()) {
+ CalendarEvent calendarEvent = ((WeeklyLongEventsDateCell) clickTargetWidget)
+ .getEvent();
+ if (calendar.getEventClickListener() != null) {
+ calendar.getEventClickListener().eventClick(calendarEvent);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
new file mode 100644
index 0000000000..c56566bf25
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java
@@ -0,0 +1,639 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.EventTarget;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ContextMenuEvent;
+import com.google.gwt.event.dom.client.ContextMenuHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.VCalendar;
+import com.vaadin.shared.ui.calendar.DateConstants;
+
+/**
+ * Internally used by the calendar
+ *
+ * @since 7.1
+ */
+public class DateCellDayEvent extends FocusableHTML implements
+ MouseDownHandler, MouseUpHandler, MouseMoveHandler, KeyDownHandler,
+ ContextMenuHandler, HasTooltipKey {
+
+ private final DateCell dateCell;
+ private Element caption = null;
+ private final Element eventContent;
+ private CalendarEvent calendarEvent = null;
+ private HandlerRegistration moveRegistration;
+ private int startY = -1;
+ private int startX = -1;
+ private String moveWidth;
+ public static final int halfHourInMilliSeconds = 1800 * 1000;
+ private Date startDatetimeFrom;
+ private Date startDatetimeTo;
+ private boolean mouseMoveStarted;
+ private int top;
+ private int startYrelative;
+ private int startXrelative;
+ private boolean disabled;
+ private final WeekGrid weekGrid;
+ private com.google.gwt.user.client.Element topResizeBar;
+ private com.google.gwt.user.client.Element bottomResizeBar;
+ private Element clickTarget;
+ private final Integer eventIndex;
+ private int slotHeight;
+ private final List<HandlerRegistration> handlers;
+ private boolean mouseMoveCanceled;
+
+ public DateCellDayEvent(DateCell dateCell, WeekGrid parent,
+ CalendarEvent event) {
+ super();
+ this.dateCell = dateCell;
+
+ handlers = new LinkedList<HandlerRegistration>();
+
+ setStylePrimaryName("v-calendar-event");
+ setCalendarEvent(event);
+
+ weekGrid = parent;
+
+ Style s = getElement().getStyle();
+ if (event.getStyleName().length() > 0) {
+ addStyleDependentName(event.getStyleName());
+ }
+ s.setPosition(Position.ABSOLUTE);
+
+ caption = DOM.createDiv();
+ caption.addClassName("v-calendar-event-caption");
+ getElement().appendChild(caption);
+
+ eventContent = DOM.createDiv();
+ eventContent.addClassName("v-calendar-event-content");
+ getElement().appendChild(eventContent);
+
+ VCalendar calendar = weekGrid.getCalendar();
+ if (weekGrid.getCalendar().isEventResizeAllowed()) {
+ topResizeBar = DOM.createDiv();
+ bottomResizeBar = DOM.createDiv();
+
+ topResizeBar.addClassName("v-calendar-event-resizetop");
+ bottomResizeBar.addClassName("v-calendar-event-resizebottom");
+
+ getElement().appendChild(topResizeBar);
+ getElement().appendChild(bottomResizeBar);
+ }
+
+ eventIndex = event.getIndex();
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ handlers.add(addMouseDownHandler(this));
+ handlers.add(addMouseUpHandler(this));
+ handlers.add(addKeyDownHandler(this));
+ handlers.add(addDomHandler(this, ContextMenuEvent.getType()));
+ }
+
+ @Override
+ protected void onDetach() {
+ for (HandlerRegistration handler : handlers) {
+ handler.removeHandler();
+ }
+ handlers.clear();
+ super.onDetach();
+ }
+
+ public void setSlotHeightInPX(int slotHeight) {
+ this.slotHeight = slotHeight;
+ }
+
+ public void updatePosition(long startFromMinutes, long durationInMinutes) {
+ if (startFromMinutes < 0) {
+ startFromMinutes = 0;
+ }
+ top = weekGrid.getPixelTopFor((int) startFromMinutes);
+
+ getElement().getStyle().setTop(top, Unit.PX);
+ if (durationInMinutes > 0) {
+ int heightMinutes = weekGrid.getPixelLengthFor(
+ (int) startFromMinutes, (int) durationInMinutes);
+ setHeight(heightMinutes);
+ } else {
+ setHeight(-1);
+ }
+
+ boolean multiRowCaption = (durationInMinutes > 30);
+ updateCaptions(multiRowCaption);
+ }
+
+ public int getTop() {
+ return top;
+ }
+
+ public void setMoveWidth(int width) {
+ moveWidth = width + "px";
+ }
+
+ public void setHeight(int h) {
+ if (h == -1) {
+ getElement().getStyle().setProperty("height", "");
+ eventContent.getStyle().setProperty("height", "");
+ } else {
+ getElement().getStyle().setHeight(h, Unit.PX);
+ // FIXME measure the border height (2px) from the DOM
+ eventContent.getStyle().setHeight(h - 2, Unit.PX);
+ }
+ }
+
+ /**
+ * @param bigMode
+ * If false, event is so small that caption must be in time-row
+ */
+ private void updateCaptions(boolean bigMode) {
+ String separator = bigMode ? "<br />" : ": ";
+ caption.setInnerHTML("<span>" + calendarEvent.getTimeAsText()
+ + "</span>" + separator
+ + Util.escapeHTML(calendarEvent.getCaption()));
+ eventContent.setInnerHTML("");
+ }
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ int keycode = event.getNativeEvent().getKeyCode();
+ if (keycode == KeyCodes.KEY_ESCAPE && mouseMoveStarted) {
+ cancelMouseMove();
+ }
+ }
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ startX = event.getClientX();
+ startY = event.getClientY();
+ if (isDisabled() || event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
+ return;
+ }
+
+ clickTarget = Element.as(event.getNativeEvent().getEventTarget());
+ mouseMoveCanceled = false;
+
+ if (weekGrid.getCalendar().isEventMoveAllowed() || clickTargetsResize()) {
+ moveRegistration = addMouseMoveHandler(this);
+ setFocus(true);
+ try {
+ startYrelative = (int) ((double) event.getRelativeY(caption) % slotHeight);
+ startXrelative = (event.getRelativeX(weekGrid.getElement()) - weekGrid.timebar
+ .getOffsetWidth()) % getDateCellWidth();
+ } catch (Exception e) {
+ GWT.log("Exception calculating relative start position", e);
+ }
+ mouseMoveStarted = false;
+ Style s = getElement().getStyle();
+ s.setZIndex(1000);
+ startDatetimeFrom = (Date) calendarEvent.getStartTime().clone();
+ startDatetimeTo = (Date) calendarEvent.getEndTime().clone();
+ Event.setCapture(getElement());
+ }
+
+ // make sure the right cursor is always displayed
+ if (clickTargetsResize()) {
+ addGlobalResizeStyle();
+ }
+
+ /*
+ * We need to stop the event propagation or else the WeekGrid range
+ * select will kick in
+ */
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+ @Override
+ public void onMouseUp(MouseUpEvent event) {
+ if (mouseMoveCanceled) {
+ return;
+ }
+
+ Event.releaseCapture(getElement());
+ setFocus(false);
+ if (moveRegistration != null) {
+ moveRegistration.removeHandler();
+ moveRegistration = null;
+ }
+ int endX = event.getClientX();
+ int endY = event.getClientY();
+ int xDiff = startX - endX;
+ int yDiff = startY - endY;
+ startX = -1;
+ startY = -1;
+ mouseMoveStarted = false;
+ Style s = getElement().getStyle();
+ s.setZIndex(1);
+ if (!clickTargetsResize()) {
+ // check if mouse has moved over threshold of 3 pixels
+ boolean mouseMoved = (xDiff < -3 || xDiff > 3 || yDiff < -3 || yDiff > 3);
+
+ if (!weekGrid.getCalendar().isDisabledOrReadOnly() && mouseMoved) {
+ // Event Move:
+ // - calendar must be enabled
+ // - calendar must not be in read-only mode
+ weekGrid.eventMoved(this);
+ } else if (!weekGrid.getCalendar().isDisabled()) {
+ // Event Click:
+ // - calendar must be enabled (read-only is allowed)
+ EventTarget et = event.getNativeEvent().getEventTarget();
+ Element e = Element.as(et);
+ if (e == caption || e == eventContent
+ || e.getParentElement() == caption) {
+ if (weekGrid.getCalendar().getEventClickListener() != null) {
+ weekGrid.getCalendar().getEventClickListener()
+ .eventClick(calendarEvent);
+ }
+ }
+ }
+
+ } else { // click targeted resize bar
+ removeGlobalResizeStyle();
+ if (weekGrid.getCalendar().getEventResizeListener() != null) {
+ weekGrid.getCalendar().getEventResizeListener()
+ .eventResized(calendarEvent);
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void onMouseMove(MouseMoveEvent event) {
+ if (startY < 0 && startX < 0) {
+ return;
+ }
+ if (isDisabled()) {
+ Event.releaseCapture(getElement());
+ mouseMoveStarted = false;
+ startY = -1;
+ startX = -1;
+ removeGlobalResizeStyle();
+ return;
+ }
+ int currentY = event.getClientY();
+ int currentX = event.getClientX();
+ int moveY = (currentY - startY);
+ int moveX = (currentX - startX);
+ if ((moveY < 5 && moveY > -6) && (moveX < 5 && moveX > -6)) {
+ return;
+ }
+ if (!mouseMoveStarted) {
+ setWidth(moveWidth);
+ getElement().getStyle().setMarginLeft(0, Unit.PX);
+ mouseMoveStarted = true;
+ }
+
+ HorizontalPanel parent = (HorizontalPanel) getParent().getParent();
+ int relativeX = event.getRelativeX(parent.getElement())
+ - weekGrid.timebar.getOffsetWidth();
+ int halfHourDiff = 0;
+ if (moveY > 0) {
+ halfHourDiff = (startYrelative + moveY) / slotHeight;
+ } else {
+ halfHourDiff = (moveY - startYrelative) / slotHeight;
+ }
+
+ int dateCellWidth = getDateCellWidth();
+ long dayDiff = 0;
+ if (moveX >= 0) {
+ dayDiff = (startXrelative + moveX) / dateCellWidth;
+ } else {
+ dayDiff = (moveX - (dateCellWidth - startXrelative))
+ / dateCellWidth;
+ }
+
+ int dayOffset = relativeX / dateCellWidth;
+
+ // sanity check for right side overflow
+ int dateCellCount = weekGrid.getDateCellCount();
+ if (dayOffset >= dateCellCount) {
+ dayOffset--;
+ dayDiff--;
+ }
+
+ int dayOffsetPx = calculateDateCellOffsetPx(dayOffset)
+ + weekGrid.timebar.getOffsetWidth();
+
+ GWT.log("DateCellWidth: " + dateCellWidth + " dayDiff: " + dayDiff
+ + " dayOffset: " + dayOffset + " dayOffsetPx: " + dayOffsetPx
+ + " startXrelative: " + startXrelative + " moveX: " + moveX);
+
+ if (relativeX < 0 || relativeX >= getDatesWidth()) {
+ return;
+ }
+
+ Style s = getElement().getStyle();
+
+ Date from = calendarEvent.getStartTime();
+ Date to = calendarEvent.getEndTime();
+ long duration = to.getTime() - from.getTime();
+
+ if (!clickTargetsResize()
+ && weekGrid.getCalendar().isEventMoveAllowed()) {
+ long daysMs = dayDiff * DateConstants.DAYINMILLIS;
+ from.setTime(startDatetimeFrom.getTime() + daysMs);
+ from.setTime(from.getTime()
+ + ((long) halfHourInMilliSeconds * halfHourDiff));
+ to.setTime((from.getTime() + duration));
+
+ calendarEvent.setStartTime(from);
+ calendarEvent.setEndTime(to);
+ calendarEvent.setStart(new Date(from.getTime()));
+ calendarEvent.setEnd(new Date(to.getTime()));
+
+ // Set new position for the event
+ long startFromMinutes = (from.getHours() * 60) + from.getMinutes();
+ long range = calendarEvent.getRangeInMinutes();
+ startFromMinutes = calculateStartFromMinute(startFromMinutes, from,
+ to, dayOffsetPx);
+ if (startFromMinutes < 0) {
+ range += startFromMinutes;
+ }
+ updatePosition(startFromMinutes, range);
+
+ s.setLeft(dayOffsetPx, Unit.PX);
+
+ if (weekGrid.getDateCellWidths() != null) {
+ s.setWidth(weekGrid.getDateCellWidths()[dayOffset], Unit.PX);
+ } else {
+ setWidth(moveWidth);
+ }
+
+ } else if (clickTarget == topResizeBar) {
+ long oldStartTime = startDatetimeFrom.getTime();
+ long newStartTime = oldStartTime
+ + ((long) halfHourInMilliSeconds * halfHourDiff);
+
+ if (!isTimeRangeTooSmall(newStartTime, startDatetimeTo.getTime())) {
+ newStartTime = startDatetimeTo.getTime() - getMinTimeRange();
+ }
+
+ from.setTime(newStartTime);
+
+ calendarEvent.setStartTime(from);
+ calendarEvent.setStart(new Date(from.getTime()));
+
+ // Set new position for the event
+ long startFromMinutes = (from.getHours() * 60) + from.getMinutes();
+ long range = calendarEvent.getRangeInMinutes();
+
+ updatePosition(startFromMinutes, range);
+
+ } else if (clickTarget == bottomResizeBar) {
+ long oldEndTime = startDatetimeTo.getTime();
+ long newEndTime = oldEndTime
+ + ((long) halfHourInMilliSeconds * halfHourDiff);
+
+ if (!isTimeRangeTooSmall(startDatetimeFrom.getTime(), newEndTime)) {
+ newEndTime = startDatetimeFrom.getTime() + getMinTimeRange();
+ }
+
+ to.setTime(newEndTime);
+
+ calendarEvent.setEndTime(to);
+ calendarEvent.setEnd(new Date(to.getTime()));
+
+ // Set new position for the event
+ long startFromMinutes = (startDatetimeFrom.getHours() * 60)
+ + startDatetimeFrom.getMinutes();
+ long range = calendarEvent.getRangeInMinutes();
+ startFromMinutes = calculateStartFromMinute(startFromMinutes, from,
+ to, dayOffsetPx);
+ if (startFromMinutes < 0) {
+ range += startFromMinutes;
+ }
+ updatePosition(startFromMinutes, range);
+ }
+ }
+
+ private void cancelMouseMove() {
+ mouseMoveCanceled = true;
+
+ // reset and remove everything related to the event handling
+ Event.releaseCapture(getElement());
+ setFocus(false);
+
+ if (moveRegistration != null) {
+ moveRegistration.removeHandler();
+ moveRegistration = null;
+ }
+
+ mouseMoveStarted = false;
+ removeGlobalResizeStyle();
+
+ Style s = getElement().getStyle();
+ s.setZIndex(1);
+
+ // reset the position of the event
+ int dateCellWidth = getDateCellWidth();
+ int dayOffset = startXrelative / dateCellWidth;
+ s.clearLeft();
+
+ calendarEvent.setStartTime(startDatetimeFrom);
+ calendarEvent.setEndTime(startDatetimeTo);
+
+ long startFromMinutes = (startDatetimeFrom.getHours() * 60)
+ + startDatetimeFrom.getMinutes();
+ long range = calendarEvent.getRangeInMinutes();
+
+ startFromMinutes = calculateStartFromMinute(startFromMinutes,
+ startDatetimeFrom, startDatetimeTo, dayOffset);
+ if (startFromMinutes < 0) {
+ range += startFromMinutes;
+ }
+
+ updatePosition(startFromMinutes, range);
+
+ startY = -1;
+ startX = -1;
+
+ // to reset the event width
+ ((DateCell) getParent()).recalculateEventWidths();
+ }
+
+ // date methods are not deprecated in GWT
+ @SuppressWarnings("deprecation")
+ private long calculateStartFromMinute(long startFromMinutes, Date from,
+ Date to, int dayOffset) {
+ boolean eventStartAtDifferentDay = from.getDate() != to.getDate();
+ if (eventStartAtDifferentDay) {
+ long minutesOnPrevDay = (getTargetDateByCurrentPosition(dayOffset)
+ .getTime() - from.getTime()) / DateConstants.MINUTEINMILLIS;
+ startFromMinutes = -1 * minutesOnPrevDay;
+ }
+
+ return startFromMinutes;
+ }
+
+ /**
+ * @param dateOffset
+ * @return the amount of pixels the given date is from the left side
+ */
+ private int calculateDateCellOffsetPx(int dateOffset) {
+ int dateCellOffset = 0;
+ int[] dateWidths = weekGrid.getDateCellWidths();
+
+ if (dateWidths != null) {
+ for (int i = 0; i < dateOffset; i++) {
+ dateCellOffset += dateWidths[i] + 1;
+ }
+ } else {
+ dateCellOffset = dateOffset * weekGrid.getDateCellWidth();
+ }
+
+ return dateCellOffset;
+ }
+
+ /**
+ * Check if the given time range is too small for events
+ *
+ * @param start
+ * @param end
+ * @return
+ */
+ private boolean isTimeRangeTooSmall(long start, long end) {
+ return (end - start) >= getMinTimeRange();
+ }
+
+ /**
+ * @return the minimum amount of ms that an event must last when resized
+ */
+ private long getMinTimeRange() {
+ return DateConstants.MINUTEINMILLIS * 30;
+ }
+
+ /**
+ * Build the string for sending resize events to server
+ *
+ * @param event
+ * @return
+ */
+ private String buildResizeString(CalendarEvent event) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(event.getIndex());
+ buffer.append(",");
+ buffer.append(DateUtil.formatClientSideDate(event.getStart()));
+ buffer.append("-");
+ buffer.append(DateUtil.formatClientSideTime(event.getStartTime()));
+ buffer.append(",");
+ buffer.append(DateUtil.formatClientSideDate(event.getEnd()));
+ buffer.append("-");
+ buffer.append(DateUtil.formatClientSideTime(event.getEndTime()));
+
+ return buffer.toString();
+ }
+
+ private Date getTargetDateByCurrentPosition(int left) {
+ DateCell newParent = (DateCell) weekGrid.content
+ .getWidget((left / getDateCellWidth()) + 1);
+ Date targetDate = newParent.getDate();
+ return targetDate;
+ }
+
+ private int getDateCellWidth() {
+ return weekGrid.getDateCellWidth();
+ }
+
+ /* Returns total width of all date cells. */
+ private int getDatesWidth() {
+ if (weekGrid.width == -1) {
+ // Undefined width. Needs to be calculated by the known cell
+ // widths.
+ int count = weekGrid.content.getWidgetCount() - 1;
+ return count * getDateCellWidth();
+ }
+
+ return weekGrid.getInternalWidth();
+ }
+
+ /**
+ * @return true if the current mouse movement is resizing
+ */
+ private boolean clickTargetsResize() {
+ return weekGrid.getCalendar().isEventResizeAllowed()
+ && (clickTarget == topResizeBar || clickTarget == bottomResizeBar);
+ }
+
+ private void addGlobalResizeStyle() {
+ if (clickTarget == topResizeBar) {
+ weekGrid.getCalendar().addStyleDependentName("nresize");
+ } else if (clickTarget == bottomResizeBar) {
+ weekGrid.getCalendar().addStyleDependentName("sresize");
+ }
+ }
+
+ private void removeGlobalResizeStyle() {
+ weekGrid.getCalendar().removeStyleDependentName("nresize");
+ weekGrid.getCalendar().removeStyleDependentName("sresize");
+ }
+
+ public void setCalendarEvent(CalendarEvent calendarEvent) {
+ this.calendarEvent = calendarEvent;
+ }
+
+ public CalendarEvent getCalendarEvent() {
+ return calendarEvent;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ @Override
+ public void onContextMenu(ContextMenuEvent event) {
+ if (dateCell.weekgrid.getCalendar().getMouseEventListener() != null) {
+ event.preventDefault();
+ event.stopPropagation();
+ dateCell.weekgrid.getCalendar().getMouseEventListener()
+ .contextMenu(event, this);
+ }
+ }
+
+ @Override
+ public Object getTooltipKey() {
+ return eventIndex;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellGroup.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellGroup.java
new file mode 100644
index 0000000000..79276eab7b
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellGroup.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Internally used by the calendar
+ *
+ * @since 7.1
+ */
+public class DateCellGroup {
+ private WeekGridMinuteTimeRange range;
+ private final List<Integer> items;
+
+ public DateCellGroup(Integer index) {
+ items = new ArrayList<Integer>();
+ items.add(index);
+ }
+
+ public WeekGridMinuteTimeRange getDateRange() {
+ return range;
+ }
+
+ public Date getStart() {
+ return range.getStart();
+ }
+
+ public Date getEnd() {
+ return range.getEnd();
+ }
+
+ public void setDateRange(WeekGridMinuteTimeRange range) {
+ this.range = range;
+ }
+
+ public List<Integer> getItems() {
+ return items;
+ }
+
+ public void add(Integer index) {
+ items.add(index);
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateUtil.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateUtil.java
new file mode 100644
index 0000000000..84726327e2
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateUtil.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.vaadin.shared.ui.calendar.DateConstants;
+
+/**
+ * Utility class for {@link Date} operations
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class DateUtil {
+
+ /**
+ * Checks if dates are same day without checking datetimes.
+ *
+ * @param date1
+ * @param date2
+ * @return
+ */
+ @SuppressWarnings("deprecation")
+ public static boolean compareDate(Date date1, Date date2) {
+ if (date1.getDate() == date2.getDate()
+ && date1.getYear() == date2.getYear()
+ && date1.getMonth() == date2.getMonth()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param date
+ * the date to format
+ *
+ * @return given Date as String, for communicating to server-side
+ */
+ public static String formatClientSideDate(Date date) {
+ DateTimeFormat dateformat_date = DateTimeFormat
+ .getFormat(DateConstants.CLIENT_DATE_FORMAT);
+ return dateformat_date.format(date);
+ }
+
+ /**
+ * @param date
+ * the date to format
+ * @return given Date as String, for communicating to server-side
+ */
+ public static String formatClientSideTime(Date date) {
+ DateTimeFormat dateformat_date = DateTimeFormat
+ .getFormat(DateConstants.CLIENT_TIME_FORMAT);
+ return dateformat_date.format(date);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DayToolbar.java b/client/src/com/vaadin/client/ui/calendar/schedule/DayToolbar.java
new file mode 100644
index 0000000000..6233e8111e
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/DayToolbar.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Iterator;
+
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class DayToolbar extends HorizontalPanel implements ClickHandler {
+ private int width = 0;
+ protected static final int MARGINLEFT = 50;
+ protected static final int MARGINRIGHT = 20;
+ protected Button backLabel;
+ protected Button nextLabel;
+ private boolean verticalSized;
+ private boolean horizontalSized;
+ private VCalendar calendar;
+
+ public DayToolbar(VCalendar vcalendar) {
+ calendar = vcalendar;
+
+ setStylePrimaryName("v-calendar-header-week");
+ backLabel = new Button();
+ backLabel.setStylePrimaryName("v-calendar-back");
+ nextLabel = new Button();
+ nextLabel.addClickHandler(this);
+ nextLabel.setStylePrimaryName("v-calendar-next");
+ backLabel.addClickHandler(this);
+ setBorderWidth(0);
+ setSpacing(0);
+ }
+
+ public void setWidthPX(int width) {
+ this.width = (width - MARGINLEFT) - MARGINRIGHT;
+ // super.setWidth(this.width + "px");
+ if (getWidgetCount() == 0) {
+ return;
+ }
+ updateCellWidths();
+ }
+
+ public void updateCellWidths() {
+ int count = getWidgetCount();
+ if (count > 0) {
+ setCellWidth(backLabel, MARGINLEFT + "px");
+ setCellWidth(nextLabel, MARGINRIGHT + "px");
+ setCellHorizontalAlignment(nextLabel, ALIGN_RIGHT);
+ int cellw = width / (count - 2);
+ int remain = width % (count - 2);
+ int cellw2 = cellw + 1;
+ if (cellw > 0) {
+ int[] cellWidths = VCalendar
+ .distributeSize(width, count - 2, 0);
+ for (int i = 1; i < count - 1; i++) {
+ Widget widget = getWidget(i);
+ // if (remain > 0) {
+ // setCellWidth(widget, cellw2 + "px");
+ // remain--;
+ // } else {
+ // setCellWidth(widget, cellw + "px");
+ // }
+ setCellWidth(widget, cellWidths[i - 1] + "px");
+ widget.setWidth(cellWidths[i - 1] + "px");
+ }
+ }
+ }
+ }
+
+ public void add(String dayName, final String date,
+ String localized_date_format, String extraClass) {
+ Label l = new Label(dayName + " " + localized_date_format);
+ l.setStylePrimaryName("v-calendar-header-day");
+
+ if (extraClass != null) {
+ l.addStyleDependentName(extraClass);
+ }
+
+ if (verticalSized) {
+ l.addStyleDependentName("Vsized");
+ }
+ if (horizontalSized) {
+ l.addStyleDependentName("Hsized");
+ }
+
+ l.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ if (calendar.getDateClickListener() != null) {
+ calendar.getDateClickListener().dateClick(date);
+ }
+ }
+ });
+
+ add(l);
+ }
+
+ public void addBackButton() {
+ if (!calendar.isBackwardNavigationEnabled()) {
+ nextLabel.getElement().getStyle().setHeight(0, Unit.PX);
+ }
+ add(backLabel);
+ }
+
+ public void addNextButton() {
+ if (!calendar.isForwardNavigationEnabled()) {
+ backLabel.getElement().getStyle().setHeight(0, Unit.PX);
+ }
+ add(nextLabel);
+ }
+
+ @Override
+ public void onClick(ClickEvent event) {
+ if (!calendar.isDisabledOrReadOnly()) {
+ if (event.getSource() == nextLabel) {
+ if (calendar.getForwardListener() != null) {
+ calendar.getForwardListener().forward();
+ }
+ } else if (event.getSource() == backLabel) {
+ if (calendar.getBackwardListener() != null) {
+ calendar.getBackwardListener().backward();
+ }
+ }
+ }
+ }
+
+ public void setVerticalSized(boolean sized) {
+ verticalSized = sized;
+ updateDayLabelSizedStyleNames();
+ }
+
+ public void setHorizontalSized(boolean sized) {
+ horizontalSized = sized;
+ updateDayLabelSizedStyleNames();
+ }
+
+ private void updateDayLabelSizedStyleNames() {
+ Iterator<Widget> it = iterator();
+ while (it.hasNext()) {
+ updateWidgetSizedStyleName(it.next());
+ }
+ }
+
+ private void updateWidgetSizedStyleName(Widget w) {
+ if (verticalSized) {
+ w.addStyleDependentName("Vsized");
+ } else {
+ w.removeStyleDependentName("VSized");
+ }
+ if (horizontalSized) {
+ w.addStyleDependentName("Hsized");
+ } else {
+ w.removeStyleDependentName("HSized");
+ }
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/FocusableComplexPanel.java b/client/src/com/vaadin/client/ui/calendar/schedule/FocusableComplexPanel.java
new file mode 100644
index 0000000000..6b42caec10
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/FocusableComplexPanel.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasBlurHandlers;
+import com.google.gwt.event.dom.client.HasFocusHandlers;
+import com.google.gwt.event.dom.client.HasKeyDownHandlers;
+import com.google.gwt.event.dom.client.HasKeyPressHandlers;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.impl.FocusImpl;
+import com.vaadin.client.Focusable;
+
+/**
+ * A ComplexPanel that can be focused
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class FocusableComplexPanel extends ComplexPanel implements
+ HasFocusHandlers, HasBlurHandlers, HasKeyDownHandlers,
+ HasKeyPressHandlers, Focusable {
+
+ protected void makeFocusable() {
+ // make focusable, as we don't need access key magic we don't need to
+ // use FocusImpl.createFocusable
+ getElement().setTabIndex(0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.
+ * google.gwt.event.dom.client.FocusHandler)
+ */
+ @Override
+ public HandlerRegistration addFocusHandler(FocusHandler handler) {
+ return addDomHandler(handler, FocusEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasBlurHandlers#addBlurHandler(com.google
+ * .gwt.event.dom.client.BlurHandler)
+ */
+ @Override
+ public HandlerRegistration addBlurHandler(BlurHandler handler) {
+ return addDomHandler(handler, BlurEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasKeyDownHandlers#addKeyDownHandler(
+ * com.google.gwt.event.dom.client.KeyDownHandler)
+ */
+ @Override
+ public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
+ return addDomHandler(handler, KeyDownEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasKeyPressHandlers#addKeyPressHandler
+ * (com.google.gwt.event.dom.client.KeyPressHandler)
+ */
+ @Override
+ public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
+ return addDomHandler(handler, KeyPressEvent.getType());
+ }
+
+ /**
+ * Sets/Removes the keyboard focus to the panel.
+ *
+ * @param focus
+ * If set to true then the focus is moved to the panel, if set to
+ * false the focus is removed
+ */
+ public void setFocus(boolean focus) {
+ if (focus) {
+ FocusImpl.getFocusImplForPanel().focus(getElement());
+ } else {
+ FocusImpl.getFocusImplForPanel().blur(getElement());
+ }
+ }
+
+ /**
+ * Focus the panel
+ */
+ @Override
+ public void focus() {
+ setFocus(true);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/FocusableGrid.java b/client/src/com/vaadin/client/ui/calendar/schedule/FocusableGrid.java
new file mode 100644
index 0000000000..b40f1c3652
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/FocusableGrid.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasBlurHandlers;
+import com.google.gwt.event.dom.client.HasFocusHandlers;
+import com.google.gwt.event.dom.client.HasKeyDownHandlers;
+import com.google.gwt.event.dom.client.HasKeyPressHandlers;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.impl.FocusImpl;
+import com.vaadin.client.Focusable;
+
+/**
+ * A Grid that can be focused
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class FocusableGrid extends Grid implements HasFocusHandlers,
+ HasBlurHandlers, HasKeyDownHandlers, HasKeyPressHandlers, Focusable {
+
+ /**
+ * Constructor
+ */
+ public FocusableGrid() {
+ super();
+ makeFocusable();
+ }
+
+ public FocusableGrid(int rows, int columns) {
+ super(rows, columns);
+ makeFocusable();
+ }
+
+ protected void makeFocusable() {
+ // make focusable, as we don't need access key magic we don't need to
+ // use FocusImpl.createFocusable
+ getElement().setTabIndex(0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.
+ * google.gwt.event.dom.client.FocusHandler)
+ */
+ @Override
+ public HandlerRegistration addFocusHandler(FocusHandler handler) {
+ return addDomHandler(handler, FocusEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasBlurHandlers#addBlurHandler(com.google
+ * .gwt.event.dom.client.BlurHandler)
+ */
+ @Override
+ public HandlerRegistration addBlurHandler(BlurHandler handler) {
+ return addDomHandler(handler, BlurEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasKeyDownHandlers#addKeyDownHandler(
+ * com.google.gwt.event.dom.client.KeyDownHandler)
+ */
+ @Override
+ public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
+ return addDomHandler(handler, KeyDownEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasKeyPressHandlers#addKeyPressHandler
+ * (com.google.gwt.event.dom.client.KeyPressHandler)
+ */
+ @Override
+ public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
+ return addDomHandler(handler, KeyPressEvent.getType());
+ }
+
+ /**
+ * Sets/Removes the keyboard focus to the panel.
+ *
+ * @param focus
+ * If set to true then the focus is moved to the panel, if set to
+ * false the focus is removed
+ */
+ public void setFocus(boolean focus) {
+ if (focus) {
+ FocusImpl.getFocusImplForPanel().focus(getElement());
+ } else {
+ FocusImpl.getFocusImplForPanel().blur(getElement());
+ }
+ }
+
+ /**
+ * Focus the panel
+ */
+ @Override
+ public void focus() {
+ setFocus(true);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/FocusableHTML.java b/client/src/com/vaadin/client/ui/calendar/schedule/FocusableHTML.java
new file mode 100644
index 0000000000..31d810608a
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/FocusableHTML.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.HasBlurHandlers;
+import com.google.gwt.event.dom.client.HasFocusHandlers;
+import com.google.gwt.event.dom.client.HasKeyDownHandlers;
+import com.google.gwt.event.dom.client.HasKeyPressHandlers;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.KeyPressEvent;
+import com.google.gwt.event.dom.client.KeyPressHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.impl.FocusImpl;
+import com.vaadin.client.Focusable;
+
+/**
+ * A HTML widget that can be focused
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class FocusableHTML extends HTML implements HasFocusHandlers,
+ HasBlurHandlers, HasKeyDownHandlers, HasKeyPressHandlers, Focusable {
+
+ /**
+ * Constructor
+ */
+ public FocusableHTML() {
+ // make focusable, as we don't need access key magic we don't need to
+ // use FocusImpl.createFocusable
+ getElement().setTabIndex(0);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasFocusHandlers#addFocusHandler(com.
+ * google.gwt.event.dom.client.FocusHandler)
+ */
+ @Override
+ public HandlerRegistration addFocusHandler(FocusHandler handler) {
+ return addDomHandler(handler, FocusEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasBlurHandlers#addBlurHandler(com.google
+ * .gwt.event.dom.client.BlurHandler)
+ */
+ @Override
+ public HandlerRegistration addBlurHandler(BlurHandler handler) {
+ return addDomHandler(handler, BlurEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasKeyDownHandlers#addKeyDownHandler(
+ * com.google.gwt.event.dom.client.KeyDownHandler)
+ */
+ @Override
+ public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
+ return addDomHandler(handler, KeyDownEvent.getType());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.HasKeyPressHandlers#addKeyPressHandler
+ * (com.google.gwt.event.dom.client.KeyPressHandler)
+ */
+ @Override
+ public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
+ return addDomHandler(handler, KeyPressEvent.getType());
+ }
+
+ /**
+ * Sets/Removes the keyboard focus to the panel.
+ *
+ * @param focus
+ * If set to true then the focus is moved to the panel, if set to
+ * false the focus is removed
+ */
+ public void setFocus(boolean focus) {
+ if (focus) {
+ FocusImpl.getFocusImplForPanel().focus(getElement());
+ } else {
+ FocusImpl.getFocusImplForPanel().blur(getElement());
+ }
+ }
+
+ /**
+ * Focus the panel
+ */
+ @Override
+ public void focus() {
+ setFocus(true);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/HasTooltipKey.java b/client/src/com/vaadin/client/ui/calendar/schedule/HasTooltipKey.java
new file mode 100644
index 0000000000..5827068840
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/HasTooltipKey.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+/**
+ * For Calendar client-side internal use only.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public interface HasTooltipKey {
+ /**
+ * Gets the key associated for the Widget implementing this interface. This
+ * key is used for getting a tooltip title identified by the key
+ *
+ * @return the tooltip key
+ */
+ Object getTooltipKey();
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java b/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java
new file mode 100644
index 0000000000..b7f6ee7a3c
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/MonthEventLabel.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ * The label in a month cell
+ *
+ * @since 7.1
+ */
+public class MonthEventLabel extends HTML implements HasTooltipKey {
+
+ private static final String STYLENAME = "v-calendar-event";
+
+ private boolean timeSpecificEvent = false;
+ private Integer eventIndex;
+ private VCalendar calendar;
+ private String caption;
+ private Date time;
+
+ /**
+ * Default constructor
+ */
+ public MonthEventLabel() {
+ setStylePrimaryName(STYLENAME);
+ }
+
+ /**
+ * Set the time of the event label
+ *
+ * @param date
+ * The date object that specifies the time
+ */
+ public void setTime(Date date) {
+ time = date;
+ renderCaption();
+ }
+
+ /**
+ * Set the caption of the event label
+ *
+ * @param caption
+ * The caption string, can be HTML
+ */
+ public void setCaption(String caption) {
+ this.caption = caption;
+ renderCaption();
+ }
+
+ /**
+ * Renders the caption in the DIV element
+ */
+ private void renderCaption() {
+ StringBuilder html = new StringBuilder();
+ if (caption != null && time != null) {
+ html.append("<span class=\"" + STYLENAME + "-time\">");
+ html.append(calendar.getTimeFormat().format(time));
+ html.append("</span> ");
+ html.append(caption);
+ } else if (caption != null) {
+ html.append(caption);
+ } else if (time != null) {
+ html.append("<span class=\"" + STYLENAME + "-time\">");
+ html.append(calendar.getTimeFormat().format(time));
+ html.append("</span>");
+ }
+ super.setHTML(html.toString());
+ }
+
+ /**
+ * Set the (server side) index of the event
+ *
+ * @param index
+ * The integer index
+ */
+ public void setEventIndex(int index) {
+ eventIndex = index;
+ }
+
+ /**
+ * Set the Calendar instance this label belongs to
+ *
+ * @param calendar
+ * The calendar instance
+ */
+ public void setCalendar(VCalendar calendar) {
+ this.calendar = calendar;
+ }
+
+ /**
+ * Is the event bound to a specific time
+ *
+ * @return
+ */
+ public boolean isTimeSpecificEvent() {
+ return timeSpecificEvent;
+ }
+
+ /**
+ * Is the event bound to a specific time
+ *
+ * @param timeSpecificEvent
+ * True if the event is bound to a time, false if it is only
+ * bound to the day
+ */
+ public void setTimeSpecificEvent(boolean timeSpecificEvent) {
+ this.timeSpecificEvent = timeSpecificEvent;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.google.gwt.user.client.ui.HTML#setHTML(java.lang.String)
+ */
+ @Override
+ public void setHTML(String html) {
+ throw new UnsupportedOperationException(
+ "Use setCaption() and setTime() instead");
+ }
+
+ @Override
+ public Object getTooltipKey() {
+ return eventIndex;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/MonthGrid.java b/client/src/com/vaadin/client/ui/calendar/schedule/MonthGrid.java
new file mode 100644
index 0000000000..df9bc42d2a
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/MonthGrid.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class MonthGrid extends FocusableGrid implements KeyDownHandler {
+
+ private SimpleDayCell selectionStart;
+ private SimpleDayCell selectionEnd;
+ private final VCalendar calendar;
+ private boolean rangeSelectDisabled;
+ private boolean disabled;
+ private boolean enabled = true;
+ private final HandlerRegistration keyDownHandler;
+
+ public MonthGrid(VCalendar parent, int rows, int columns) {
+ super(rows, columns);
+ calendar = parent;
+ setCellSpacing(0);
+ setCellPadding(0);
+ setStylePrimaryName("v-calendar-month");
+
+ keyDownHandler = addKeyDownHandler(this);
+ }
+
+ @Override
+ protected void onUnload() {
+ keyDownHandler.removeHandler();
+ super.onUnload();
+ }
+
+ public void setSelectionEnd(SimpleDayCell simpleDayCell) {
+ selectionEnd = simpleDayCell;
+ updateSelection();
+ }
+
+ public void setSelectionStart(SimpleDayCell simpleDayCell) {
+ if (!rangeSelectDisabled && isEnabled()) {
+ selectionStart = simpleDayCell;
+ setFocus(true);
+ }
+
+ }
+
+ private void updateSelection() {
+ if (selectionStart == null) {
+ return;
+ }
+ if (selectionStart != null && selectionEnd != null) {
+ Date startDate = selectionStart.getDate();
+ Date endDate = selectionEnd.getDate();
+ for (int row = 0; row < getRowCount(); row++) {
+ for (int cell = 0; cell < getCellCount(row); cell++) {
+ SimpleDayCell sdc = (SimpleDayCell) getWidget(row, cell);
+ if (sdc == null) {
+ return;
+ }
+ Date d = sdc.getDate();
+ if (startDate.compareTo(d) <= 0
+ && endDate.compareTo(d) >= 0) {
+ sdc.addStyleDependentName("selected");
+ } else if (startDate.compareTo(d) >= 0
+ && endDate.compareTo(d) <= 0) {
+ sdc.addStyleDependentName("selected");
+ } else {
+ sdc.removeStyleDependentName("selected");
+ }
+ }
+ }
+ }
+ }
+
+ public void setSelectionReady() {
+ if (selectionStart != null && selectionEnd != null) {
+ String value = "";
+ Date startDate = selectionStart.getDate();
+ Date endDate = selectionEnd.getDate();
+ if (startDate.compareTo(endDate) > 0) {
+ Date temp = startDate;
+ startDate = endDate;
+ endDate = temp;
+ }
+
+ if (calendar.getRangeSelectListener() != null) {
+ value = calendar.getDateFormat().format(startDate) + "TO"
+ + calendar.getDateFormat().format(endDate);
+ calendar.getRangeSelectListener().rangeSelected(value);
+ }
+ selectionStart = null;
+ selectionEnd = null;
+ setFocus(false);
+ }
+ }
+
+ public void cancelRangeSelection() {
+ if (selectionStart != null && selectionEnd != null) {
+ for (int row = 0; row < getRowCount(); row++) {
+ for (int cell = 0; cell < getCellCount(row); cell++) {
+ SimpleDayCell sdc = (SimpleDayCell) getWidget(row, cell);
+ if (sdc == null) {
+ return;
+ }
+ sdc.removeStyleDependentName("selected");
+ }
+ }
+ }
+ setFocus(false);
+ selectionStart = null;
+ }
+
+ public void updateCellSizes(int totalWidthPX, int totalHeightPX) {
+ boolean setHeight = totalHeightPX > 0;
+ boolean setWidth = totalWidthPX > 0;
+ int rows = getRowCount();
+ int cells = getCellCount(0);
+ int cellWidth = (totalWidthPX / cells) - 1;
+ int widthRemainder = totalWidthPX % cells;
+ // Division for cells might not be even. Distribute it evenly to
+ // will whole space.
+ int heightPX = totalHeightPX;
+ int cellHeight = heightPX / rows;
+ int heightRemainder = heightPX % rows;
+
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cells; j++) {
+ SimpleDayCell sdc = (SimpleDayCell) getWidget(i, j);
+
+ if (setWidth) {
+ if (widthRemainder > 0) {
+ sdc.setWidth(cellWidth + 1 + "px");
+ widthRemainder--;
+
+ } else {
+ sdc.setWidth(cellWidth + "px");
+ }
+ }
+
+ if (setHeight) {
+ if (heightRemainder > 0) {
+ sdc.setHeightPX(cellHeight + 1, true);
+
+ } else {
+ sdc.setHeightPX(cellHeight, true);
+ }
+ } else {
+ sdc.setHeightPX(-1, true);
+ }
+ }
+ heightRemainder--;
+ }
+ }
+
+ /**
+ * Disable or enable possibility to select ranges
+ */
+ public void setRangeSelect(boolean b) {
+ rangeSelectDisabled = !b;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ int keycode = event.getNativeKeyCode();
+ if (KeyCodes.KEY_ESCAPE == keycode && selectionStart != null) {
+ cancelRangeSelection();
+ }
+ }
+
+ public int getDayCellIndex(SimpleDayCell dayCell) {
+ int rows = getRowCount();
+ int cells = getCellCount(0);
+ for (int i = 0; i < rows; i++) {
+ for (int j = 0; j < cells; j++) {
+ SimpleDayCell sdc = (SimpleDayCell) getWidget(i, j);
+ if (dayCell == sdc) {
+ return i * cells + j;
+ }
+ }
+ }
+
+ return -1;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java
new file mode 100644
index 0000000000..a2bd008d01
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java
@@ -0,0 +1,701 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseMoveHandler;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+import com.google.gwt.event.dom.client.MouseOverHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ui.FocusableFlowPanel;
+import com.vaadin.client.ui.VCalendar;
+import com.vaadin.shared.ui.calendar.DateConstants;
+
+/**
+ * A class representing a single cell within the calendar in month-view
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class SimpleDayCell extends FocusableFlowPanel implements
+ MouseUpHandler, MouseDownHandler, MouseOverHandler, MouseMoveHandler {
+
+ private static int BOTTOMSPACERHEIGHT = -1;
+ private static int EVENTHEIGHT = -1;
+ private static final int BORDERPADDINGSIZE = 1;
+
+ private final VCalendar calendar;
+ private Date date;
+ private int intHeight;
+ private final HTML bottomspacer;
+ private final Label caption;
+ private final CalendarEvent[] events = new CalendarEvent[10];
+ private final int cell;
+ private final int row;
+ private boolean monthNameVisible;
+ private HandlerRegistration mouseUpRegistration;
+ private HandlerRegistration mouseDownRegistration;
+ private HandlerRegistration mouseOverRegistration;
+ private boolean monthEventMouseDown;
+ private boolean labelMouseDown;
+ private int eventCount = 0;
+
+ private int startX = -1;
+ private int startY = -1;
+ private int startYrelative;
+ private int startXrelative;
+ private Date startDateFrom;
+ private Date startDateTo;
+ private int prevDayDiff = 0;
+ private int prevWeekDiff = 0;
+ private HandlerRegistration moveRegistration;
+ private CalendarEvent moveEvent;
+ private Widget clickedWidget;
+ private HandlerRegistration bottomSpacerMouseDownHandler;
+ private boolean scrollable = false;
+ private boolean eventCanceled;
+ private MonthGrid monthGrid;
+ private HandlerRegistration keyDownHandler;
+
+ public SimpleDayCell(VCalendar calendar, int row, int cell) {
+ this.calendar = calendar;
+ this.row = row;
+ this.cell = cell;
+ setStylePrimaryName("v-calendar-month-day");
+ caption = new Label();
+ bottomspacer = new HTML();
+ bottomspacer.setStyleName("v-calendar-bottom-spacer-empty");
+ bottomspacer.setWidth(3 + "em");
+ caption.setStyleName("v-calendar-day-number");
+ add(caption);
+ add(bottomspacer);
+ caption.addMouseDownHandler(this);
+ caption.addMouseUpHandler(this);
+ }
+
+ @Override
+ public void onLoad() {
+ BOTTOMSPACERHEIGHT = bottomspacer.getOffsetHeight();
+ EVENTHEIGHT = BOTTOMSPACERHEIGHT;
+ }
+
+ public void setMonthGrid(MonthGrid monthGrid) {
+ this.monthGrid = monthGrid;
+ }
+
+ public MonthGrid getMonthGrid() {
+ return monthGrid;
+ }
+
+ @SuppressWarnings("deprecation")
+ public void setDate(Date date) {
+ int dateOfMonth = date.getDate();
+ if (monthNameVisible) {
+ caption.setText(dateOfMonth + " "
+ + calendar.getMonthNames()[date.getMonth()]);
+ } else {
+ caption.setText("" + dateOfMonth);
+ }
+ this.date = date;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void reDraw(boolean clear) {
+ setHeightPX(intHeight + BORDERPADDINGSIZE, clear);
+ }
+
+ /*
+ * Events and whole cell content are drawn by this method. By the
+ * clear-argument, you can choose to clear all old content. Notice that
+ * clearing will also remove all element's event handlers.
+ */
+ public void setHeightPX(int px, boolean clear) {
+ // measure from DOM if needed
+ if (px < 0) {
+ intHeight = getOffsetHeight() - BORDERPADDINGSIZE;
+ } else {
+ intHeight = px - BORDERPADDINGSIZE;
+ }
+
+ // Couldn't measure height or it ended up negative. Don't bother
+ // continuing
+ if (intHeight == -1) {
+ return;
+ }
+
+ if (clear) {
+ while (getWidgetCount() > 1) {
+ remove(1);
+ }
+ }
+
+ // How many events can be shown in UI
+ int slots = 0;
+ if (scrollable) {
+ for (int i = 0; i < events.length; i++) {
+ if (events[i] != null) {
+ slots = i + 1;
+ }
+ }
+ setHeight(intHeight + "px"); // Fixed height
+ } else {
+ // Dynamic height by the content
+ DOM.removeElementAttribute(getElement(), "height");
+ slots = (intHeight - caption.getOffsetHeight() - BOTTOMSPACERHEIGHT)
+ / EVENTHEIGHT;
+ if (slots > 10) {
+ slots = 10;
+ }
+ }
+
+ updateEvents(slots, clear);
+
+ }
+
+ public void updateEvents(int slots, boolean clear) {
+ int eventsAdded = 0;
+
+ for (int i = 0; i < slots; i++) {
+ CalendarEvent e = events[i];
+ if (e == null) {
+ // Empty slot
+ HTML slot = new HTML();
+ slot.setStyleName("v-calendar-spacer");
+ if (!clear) {
+ remove(i + 1);
+ insert(slot, i + 1);
+ } else {
+ add(slot);
+ }
+ } else {
+ // Event slot
+ eventsAdded++;
+ if (!clear) {
+ Widget w = getWidget(i + 1);
+ if (!(w instanceof MonthEventLabel)) {
+ remove(i + 1);
+ insert(createMonthEventLabel(e), i + 1);
+ }
+ } else {
+ add(createMonthEventLabel(e));
+ }
+ }
+ }
+
+ int remainingSpace = intHeight
+ - ((slots * EVENTHEIGHT) + BOTTOMSPACERHEIGHT + caption
+ .getOffsetHeight());
+ int newHeight = remainingSpace + BOTTOMSPACERHEIGHT;
+ if (newHeight < 0) {
+ newHeight = EVENTHEIGHT;
+ }
+ bottomspacer.setHeight(newHeight + "px");
+
+ if (clear) {
+ add(bottomspacer);
+ }
+
+ int more = eventCount - eventsAdded;
+ if (more > 0) {
+ if (bottomSpacerMouseDownHandler == null) {
+ bottomSpacerMouseDownHandler = bottomspacer
+ .addMouseDownHandler(this);
+ }
+ bottomspacer.setStyleName("v-calendar-bottom-spacer");
+ bottomspacer.setText("+ " + more);
+ } else {
+ if (!scrollable && bottomSpacerMouseDownHandler != null) {
+ bottomSpacerMouseDownHandler.removeHandler();
+ bottomSpacerMouseDownHandler = null;
+ }
+
+ if (scrollable) {
+ bottomspacer.setText("[ - ]");
+ } else {
+ bottomspacer.setStyleName("v-calendar-bottom-spacer-empty");
+ bottomspacer.setText("");
+ }
+ }
+ }
+
+ private MonthEventLabel createMonthEventLabel(CalendarEvent e) {
+ long rangeInMillis = e.getRangeInMilliseconds();
+ boolean timeEvent = rangeInMillis <= DateConstants.DAYINMILLIS
+ && !e.isAllDay();
+ Date fromDatetime = e.getStartTime();
+
+ // Create a new MonthEventLabel
+ MonthEventLabel eventDiv = new MonthEventLabel();
+ eventDiv.addStyleDependentName("month");
+ eventDiv.addMouseDownHandler(this);
+ eventDiv.addMouseUpHandler(this);
+ eventDiv.setCalendar(calendar);
+ eventDiv.setEventIndex(e.getIndex());
+
+ if (timeEvent) {
+ eventDiv.setTimeSpecificEvent(true);
+ if (e.getStyleName() != null) {
+ eventDiv.addStyleDependentName(e.getStyleName());
+ }
+ eventDiv.setCaption(e.getCaption());
+ eventDiv.setTime(fromDatetime);
+
+ } else {
+ eventDiv.setTimeSpecificEvent(false);
+ Date from = e.getStart();
+ Date to = e.getEnd();
+ if (e.getStyleName().length() > 0) {
+ eventDiv.addStyleName("month-event " + e.getStyleName());
+ } else {
+ eventDiv.addStyleName("month-event");
+ }
+ int fromCompareToDate = from.compareTo(date);
+ int toCompareToDate = to.compareTo(date);
+ eventDiv.addStyleDependentName("all-day");
+ if (fromCompareToDate == 0) {
+ eventDiv.addStyleDependentName("start");
+ eventDiv.setCaption(e.getCaption());
+
+ } else if (fromCompareToDate < 0 && cell == 0) {
+ eventDiv.addStyleDependentName("continued-from");
+ eventDiv.setCaption(e.getCaption());
+ }
+ if (toCompareToDate == 0) {
+ eventDiv.addStyleDependentName("end");
+ } else if (toCompareToDate > 0
+ && (cell + 1) == getMonthGrid().getCellCount(row)) {
+ eventDiv.addStyleDependentName("continued-to");
+ }
+ if (e.getStyleName() != null) {
+ eventDiv.addStyleDependentName(e.getStyleName() + "-all-day");
+ }
+ }
+
+ return eventDiv;
+ }
+
+ private void setUnlimitedCellHeight() {
+ scrollable = true;
+ addStyleDependentName("scrollable");
+ }
+
+ private void setLimitedCellHeight() {
+ scrollable = false;
+ removeStyleDependentName("scrollable");
+ }
+
+ public void addCalendarEvent(CalendarEvent e) {
+ eventCount++;
+ int slot = e.getSlotIndex();
+ if (slot == -1) {
+ for (int i = 0; i < events.length; i++) {
+ if (events[i] == null) {
+ events[i] = e;
+ e.setSlotIndex(i);
+ break;
+ }
+ }
+ } else {
+ events[slot] = e;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ public void setMonthNameVisible(boolean b) {
+ monthNameVisible = b;
+ int dateOfMonth = date.getDate();
+ caption.setText(dateOfMonth + " "
+ + calendar.getMonthNames()[date.getMonth()]);
+ }
+
+ public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
+ return addDomHandler(handler, MouseMoveEvent.getType());
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ mouseUpRegistration = addDomHandler(this, MouseUpEvent.getType());
+ mouseDownRegistration = addDomHandler(this, MouseDownEvent.getType());
+ mouseOverRegistration = addDomHandler(this, MouseOverEvent.getType());
+ }
+
+ @Override
+ protected void onDetach() {
+ mouseUpRegistration.removeHandler();
+ mouseDownRegistration.removeHandler();
+ mouseOverRegistration.removeHandler();
+ super.onDetach();
+ }
+
+ @Override
+ public void onMouseUp(MouseUpEvent event) {
+ if (event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
+ return;
+ }
+
+ Widget w = (Widget) event.getSource();
+ if (moveRegistration != null) {
+ Event.releaseCapture(getElement());
+ moveRegistration.removeHandler();
+ moveRegistration = null;
+ keyDownHandler.removeHandler();
+ keyDownHandler = null;
+ }
+
+ if (w == bottomspacer && monthEventMouseDown) {
+ GWT.log("Mouse up over bottomspacer");
+
+ } else if (clickedWidget instanceof MonthEventLabel
+ && monthEventMouseDown) {
+ MonthEventLabel mel = (MonthEventLabel) clickedWidget;
+
+ int endX = event.getClientX();
+ int endY = event.getClientY();
+ int xDiff = startX - endX;
+ int yDiff = startY - endY;
+ startX = -1;
+ startY = -1;
+ prevDayDiff = 0;
+ prevWeekDiff = 0;
+
+ if (!mel.isTimeSpecificEvent()
+ && (xDiff < -3 || xDiff > 3 || yDiff < -3 || yDiff > 3)) {
+ eventMoved(moveEvent);
+
+ } else if (calendar.getEventClickListener() != null) {
+ CalendarEvent e = getEventByWidget(mel);
+ calendar.getEventClickListener().eventClick(e);
+ }
+
+ moveEvent = null;
+ } else if (w == this) {
+ getMonthGrid().setSelectionReady();
+
+ } else if (w instanceof Label && labelMouseDown) {
+ String clickedDate = calendar.getDateFormat().format(date);
+ if (calendar.getDateClickListener() != null) {
+ calendar.getDateClickListener().dateClick(clickedDate);
+ }
+ }
+ monthEventMouseDown = false;
+ labelMouseDown = false;
+ clickedWidget = null;
+ }
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ if (calendar.isDisabled()
+ || event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
+ return;
+ }
+
+ Widget w = (Widget) event.getSource();
+ clickedWidget = w;
+
+ if (w instanceof MonthEventLabel) {
+ // event clicks should be allowed even when read-only
+ monthEventMouseDown = true;
+
+ if (w instanceof MonthEventLabel) {
+ startCalendarEventDrag(event, (MonthEventLabel) w);
+ }
+ } else if (!calendar.isReadOnly()) {
+ // these are not allowed when in read-only
+ if (w == bottomspacer) {
+ if (scrollable) {
+ setLimitedCellHeight();
+ } else {
+ setUnlimitedCellHeight();
+ }
+ reDraw(true);
+
+ } else if (w == this && !scrollable) {
+ MonthGrid grid = getMonthGrid();
+ if (grid.isEnabled() && calendar.isRangeSelectAllowed()) {
+ grid.setSelectionStart(this);
+ grid.setSelectionEnd(this);
+ }
+ } else if (w instanceof Label) {
+ labelMouseDown = true;
+ }
+ }
+
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+ @Override
+ public void onMouseOver(MouseOverEvent event) {
+ event.preventDefault();
+ getMonthGrid().setSelectionEnd(this);
+ }
+
+ @Override
+ public void onMouseMove(MouseMoveEvent event) {
+ if (clickedWidget instanceof MonthEventLabel && !monthEventMouseDown
+ || (startY < 0 && startX < 0)) {
+ return;
+ }
+
+ MonthEventLabel w = (MonthEventLabel) clickedWidget;
+
+ if (calendar.isDisabledOrReadOnly()) {
+ Event.releaseCapture(getElement());
+ monthEventMouseDown = false;
+ startY = -1;
+ startX = -1;
+ return;
+ }
+
+ int currentY = event.getClientY();
+ int currentX = event.getClientX();
+ int moveY = (currentY - startY);
+ int moveX = (currentX - startX);
+ if ((moveY < 5 && moveY > -6) && (moveX < 5 && moveX > -6)) {
+ return;
+ }
+
+ int dateCellWidth = getWidth();
+ int dateCellHeigth = getHeigth();
+
+ Element parent = getMonthGrid().getElement();
+ int relativeX = event.getRelativeX(parent);
+ int relativeY = event.getRelativeY(parent);
+ int weekDiff = 0;
+ if (moveY > 0) {
+ weekDiff = (startYrelative + moveY) / dateCellHeigth;
+ } else {
+ weekDiff = (moveY - (dateCellHeigth - startYrelative))
+ / dateCellHeigth;
+ }
+
+ int dayDiff = 0;
+ if (moveX >= 0) {
+ dayDiff = (startXrelative + moveX) / dateCellWidth;
+ } else {
+ dayDiff = (moveX - (dateCellWidth - startXrelative))
+ / dateCellWidth;
+ }
+ // Check boundaries
+ if (relativeY < 0
+ || relativeY >= (calendar.getMonthGrid().getRowCount() * dateCellHeigth)
+ || relativeX < 0
+ || relativeX >= (calendar.getMonthGrid().getColumnCount() * dateCellWidth)) {
+ return;
+ }
+
+ GWT.log("Event moving delta: " + weekDiff + " weeks " + dayDiff
+ + " days" + " (" + getCell() + "," + getRow() + ")");
+
+ CalendarEvent e = moveEvent;
+ if (e == null) {
+ e = getEventByWidget(w);
+ }
+
+ Date from = e.getStart();
+ Date to = e.getEnd();
+ long duration = to.getTime() - from.getTime();
+
+ long daysMs = dayDiff * DateConstants.DAYINMILLIS;
+ long weeksMs = weekDiff * DateConstants.WEEKINMILLIS;
+ from.setTime(startDateFrom.getTime() + weeksMs + daysMs);
+ to.setTime((from.getTime() + duration));
+ e.setStart(from);
+ e.setEnd(to);
+ e.setStartTime(new Date(from.getTime()));
+ e.setEndTime(new Date(to.getTime()));
+
+ updateDragPosition(w, dayDiff, weekDiff);
+ }
+
+ private void eventMoved(CalendarEvent e) {
+ calendar.updateEventToMonthGrid(e);
+ if (calendar.getEventMovedListener() != null) {
+ calendar.getEventMovedListener().eventMoved(e);
+ }
+ }
+
+ public void startCalendarEventDrag(MouseDownEvent event,
+ final MonthEventLabel w) {
+ if (w.isTimeSpecificEvent()) {
+ return;
+ }
+
+ moveRegistration = addMouseMoveHandler(this);
+ startX = event.getClientX();
+ startY = event.getClientY();
+ startYrelative = event.getRelativeY(w.getParent().getElement())
+ % getHeigth();
+ startXrelative = event.getRelativeX(w.getParent().getElement())
+ % getWidth();
+
+ CalendarEvent e = getEventByWidget(w);
+ startDateFrom = (Date) e.getStart().clone();
+ startDateTo = (Date) e.getEnd().clone();
+
+ Event.setCapture(getElement());
+ keyDownHandler = addKeyDownHandler(new KeyDownHandler() {
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ if (event.getNativeKeyCode() == KeyCodes.KEY_ESCAPE) {
+ cancelEventDrag(w);
+ }
+ }
+
+ });
+
+ focus();
+
+ GWT.log("Start drag");
+ }
+
+ protected void cancelEventDrag(MonthEventLabel w) {
+ if (moveRegistration != null) {
+ // reset position
+ if (moveEvent == null) {
+ moveEvent = getEventByWidget(w);
+ }
+
+ moveEvent.setStart(startDateFrom);
+ moveEvent.setEnd(startDateTo);
+ calendar.updateEventToMonthGrid(moveEvent);
+
+ // reset drag-related properties
+ Event.releaseCapture(getElement());
+ moveRegistration.removeHandler();
+ moveRegistration = null;
+ keyDownHandler.removeHandler();
+ keyDownHandler = null;
+ setFocus(false);
+ monthEventMouseDown = false;
+ startY = -1;
+ startX = -1;
+ moveEvent = null;
+ labelMouseDown = false;
+ clickedWidget = null;
+ }
+ }
+
+ public void updateDragPosition(MonthEventLabel w, int dayDiff, int weekDiff) {
+ // Draw event to its new position only when position has changed
+ if (dayDiff == prevDayDiff && weekDiff == prevWeekDiff) {
+ return;
+ }
+
+ prevDayDiff = dayDiff;
+ prevWeekDiff = weekDiff;
+
+ if (moveEvent == null) {
+ moveEvent = getEventByWidget(w);
+ }
+
+ calendar.updateEventToMonthGrid(moveEvent);
+ }
+
+ public int getRow() {
+ return row;
+ }
+
+ public int getCell() {
+ return cell;
+ }
+
+ public int getHeigth() {
+ return intHeight + BORDERPADDINGSIZE;
+ }
+
+ public int getWidth() {
+ return getOffsetWidth() - BORDERPADDINGSIZE;
+ }
+
+ public void setToday(boolean today) {
+ if (today) {
+ addStyleDependentName("today");
+ } else {
+ removeStyleDependentName("today");
+ }
+ }
+
+ public boolean removeEvent(CalendarEvent targetEvent,
+ boolean reDrawImmediately) {
+ int slot = targetEvent.getSlotIndex();
+ if (slot < 0) {
+ return false;
+ }
+
+ CalendarEvent e = getCalendarEvent(slot);
+ if (targetEvent.equals(e)) {
+ events[slot] = null;
+ eventCount--;
+ if (reDrawImmediately) {
+ reDraw(moveEvent == null);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private CalendarEvent getEventByWidget(MonthEventLabel eventWidget) {
+ int index = getWidgetIndex(eventWidget);
+ return getCalendarEvent(index - 1);
+ }
+
+ public CalendarEvent getCalendarEvent(int i) {
+ return events[i];
+ }
+
+ public CalendarEvent[] getEvents() {
+ return events;
+ }
+
+ public int getEventCount() {
+ return eventCount;
+ }
+
+ public CalendarEvent getMoveEvent() {
+ return moveEvent;
+ }
+
+ public void addEmphasisStyle() {
+ addStyleDependentName("dragemphasis");
+ }
+
+ public void removeEmphasisStyle() {
+ removeStyleDependentName("dragemphasis");
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayToolbar.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayToolbar.java
new file mode 100644
index 0000000000..fc75136b93
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayToolbar.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ *
+ */
+public class SimpleDayToolbar extends HorizontalPanel {
+ private int width = 0;
+ private boolean isWidthUndefined = false;
+
+ public SimpleDayToolbar() {
+ setStylePrimaryName("v-calendar-header-month");
+ }
+
+ public void setDayNames(String[] dayNames) {
+ clear();
+ for (int i = 0; i < dayNames.length; i++) {
+ Label l = new Label(dayNames[i]);
+ l.setStylePrimaryName("v-calendar-header-day");
+ add(l);
+ }
+ updateCellWidth();
+ }
+
+ public void setWidthPX(int width) {
+ this.width = width;
+
+ setWidthUndefined(width == -1);
+
+ if (!isWidthUndefined()) {
+ super.setWidth(this.width + "px");
+ if (getWidgetCount() == 0) {
+ return;
+ }
+ }
+ updateCellWidth();
+ }
+
+ private boolean isWidthUndefined() {
+ return isWidthUndefined;
+ }
+
+ private void setWidthUndefined(boolean isWidthUndefined) {
+ this.isWidthUndefined = isWidthUndefined;
+
+ if (isWidthUndefined) {
+ addStyleDependentName("Hsized");
+
+ } else {
+ removeStyleDependentName("Hsized");
+ }
+ }
+
+ private void updateCellWidth() {
+ int cellw = -1;
+ int widgetCount = getWidgetCount();
+ if (widgetCount <= 0) {
+ return;
+ }
+ if (isWidthUndefined()) {
+ Widget widget = getWidget(0);
+ String w = widget.getElement().getStyle().getWidth();
+ if (w.length() > 2) {
+ cellw = Integer.parseInt(w.substring(0, w.length() - 2));
+ }
+ } else {
+ cellw = width / getWidgetCount();
+ }
+ if (cellw > 0) {
+ for (int i = 0; i < getWidgetCount(); i++) {
+ Widget widget = getWidget(i);
+ setCellWidth(widget, cellw + "px");
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleWeekToolbar.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleWeekToolbar.java
new file mode 100644
index 0000000000..59902811cd
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleWeekToolbar.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class SimpleWeekToolbar extends FlexTable implements ClickHandler {
+ private int height;
+ private VCalendar calendar;
+ private boolean isHeightUndefined;
+
+ public SimpleWeekToolbar(VCalendar parent) {
+ calendar = parent;
+ setCellSpacing(0);
+ setCellPadding(0);
+ setStyleName("v-calendar-week-numbers");
+ }
+
+ public void addWeek(int week, int year) {
+ WeekLabel l = new WeekLabel(week + "", week, year);
+ l.addClickHandler(this);
+ int rowCount = getRowCount();
+ insertRow(rowCount);
+ setWidget(rowCount, 0, l);
+ updateCellHeights();
+ }
+
+ public void updateCellHeights() {
+ if (!isHeightUndefined()) {
+ int rowCount = getRowCount();
+ if (rowCount == 0) {
+ return;
+ }
+ int cellheight = (height / rowCount) - 1;
+ int remainder = height % rowCount;
+ if (cellheight < 0) {
+ cellheight = 0;
+ }
+ for (int i = 0; i < rowCount; i++) {
+ if (remainder > 0) {
+ getWidget(i, 0).setHeight(cellheight + 1 + "px");
+ } else {
+ getWidget(i, 0).setHeight(cellheight + "px");
+ }
+ getWidget(i, 0).getElement().getStyle()
+ .setProperty("lineHeight", cellheight + "px");
+ remainder--;
+ }
+ } else {
+ for (int i = 0; i < getRowCount(); i++) {
+ getWidget(i, 0).setHeight("");
+ getWidget(i, 0).getElement().getStyle()
+ .setProperty("lineHeight", "");
+ }
+ }
+ }
+
+ public void setHeightPX(int intHeight) {
+ setHeightUndefined(intHeight == -1);
+ height = intHeight;
+ updateCellHeights();
+ }
+
+ public boolean isHeightUndefined() {
+ return isHeightUndefined;
+ }
+
+ public void setHeightUndefined(boolean isHeightUndefined) {
+ this.isHeightUndefined = isHeightUndefined;
+
+ if (isHeightUndefined) {
+ addStyleDependentName("Vsized");
+
+ } else {
+ removeStyleDependentName("Vsized");
+ }
+ }
+
+ @Override
+ public void onClick(ClickEvent event) {
+ WeekLabel wl = (WeekLabel) event.getSource();
+ if (calendar.getWeekClickListener() != null) {
+ calendar.getWeekClickListener().weekClick(
+ wl.getYear() + "w" + wl.getWeek());
+ }
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/WeekGrid.java b/client/src/com/vaadin/client/ui/calendar/schedule/WeekGrid.java
new file mode 100644
index 0000000000..450ea29549
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/WeekGrid.java
@@ -0,0 +1,678 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.event.dom.client.ScrollEvent;
+import com.google.gwt.event.dom.client.ScrollHandler;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.DateTimeService;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class WeekGrid extends SimplePanel {
+
+ int width = 0;
+ private int height = 0;
+ final HorizontalPanel content;
+ private VCalendar calendar;
+ private boolean disabled;
+ final Timebar timebar;
+ private Panel wrapper;
+ private boolean verticalScrollEnabled;
+ private boolean horizontalScrollEnabled;
+ private int[] cellHeights;
+ private final int slotInMinutes = 30;
+ private int dateCellBorder;
+ private DateCell dateCellOfToday;
+ private int[] cellWidths;
+ private int firstHour;
+ private int lastHour;
+
+ public WeekGrid(VCalendar parent, boolean format24h) {
+ setCalendar(parent);
+ content = new HorizontalPanel();
+ timebar = new Timebar(format24h);
+ content.add(timebar);
+
+ wrapper = new SimplePanel();
+ wrapper.setStylePrimaryName("v-calendar-week-wrapper");
+ wrapper.add(content);
+
+ setWidget(wrapper);
+ }
+
+ private void setVerticalScroll(boolean isVerticalScrollEnabled) {
+ if (isVerticalScrollEnabled && !(isVerticalScrollable())) {
+ verticalScrollEnabled = true;
+ horizontalScrollEnabled = false;
+ wrapper.remove(content);
+
+ final ScrollPanel scrollPanel = new ScrollPanel();
+ scrollPanel.setStylePrimaryName("v-calendar-week-wrapper");
+ scrollPanel.setWidget(content);
+
+ scrollPanel.addScrollHandler(new ScrollHandler() {
+ @Override
+ public void onScroll(ScrollEvent event) {
+ if (calendar.getScrollListener() != null) {
+ calendar.getScrollListener().scroll(
+ scrollPanel.getVerticalScrollPosition());
+ }
+ }
+ });
+
+ setWidget(scrollPanel);
+ wrapper = scrollPanel;
+
+ } else if (!isVerticalScrollEnabled && (isVerticalScrollable())) {
+ verticalScrollEnabled = false;
+ horizontalScrollEnabled = false;
+ wrapper.remove(content);
+
+ SimplePanel simplePanel = new SimplePanel();
+ simplePanel.setStylePrimaryName("v-calendar-week-wrapper");
+ simplePanel.setWidget(content);
+
+ setWidget(simplePanel);
+ wrapper = simplePanel;
+ }
+ }
+
+ public void setVerticalScrollPosition(int verticalScrollPosition) {
+ if (isVerticalScrollable()) {
+ ((ScrollPanel) wrapper)
+ .setVerticalScrollPosition(verticalScrollPosition);
+ }
+ }
+
+ public int getInternalWidth() {
+ return width;
+ }
+
+ public void addDate(Date d) {
+ final DateCell dc = new DateCell(this, d);
+ dc.setDisabled(isDisabled());
+ dc.setHorizontalSized(isHorizontalScrollable() || width < 0);
+ dc.setVerticalSized(isVerticalScrollable());
+ content.add(dc);
+ }
+
+ /**
+ * @param dateCell
+ * @return get the index of the given date cell in this week, starting from
+ * 0
+ */
+ public int getDateCellIndex(DateCell dateCell) {
+ return content.getWidgetIndex(dateCell) - 1;
+ }
+
+ /**
+ * @return get the slot border in pixels
+ */
+ public int getDateSlotBorder() {
+ return ((DateCell) content.getWidget(1)).getSlotBorder();
+ }
+
+ private boolean isVerticalScrollable() {
+ return verticalScrollEnabled;
+ }
+
+ private boolean isHorizontalScrollable() {
+ return horizontalScrollEnabled;
+ }
+
+ public void setWidthPX(int width) {
+ if (isHorizontalScrollable()) {
+ updateCellWidths();
+
+ // Otherwise the scroll wrapper is somehow too narrow = horizontal
+ // scroll
+ wrapper.setWidth(content.getOffsetWidth()
+ + Util.getNativeScrollbarSize() + "px");
+
+ this.width = content.getOffsetWidth() - timebar.getOffsetWidth();
+
+ } else {
+ this.width = (width == -1) ? width : width
+ - timebar.getOffsetWidth();
+
+ if (isVerticalScrollable() && width != -1) {
+ this.width = this.width - Util.getNativeScrollbarSize();
+ }
+ updateCellWidths();
+ }
+ }
+
+ public void setHeightPX(int intHeight) {
+ height = intHeight;
+
+ setVerticalScroll(height <= -1);
+
+ // if not scrollable, use any height given
+ if (!isVerticalScrollable() && height > 0) {
+
+ content.setHeight(height + "px");
+ setHeight(height + "px");
+ wrapper.setHeight(height + "px");
+ wrapper.removeStyleDependentName("Vsized");
+ updateCellHeights();
+ timebar.setCellHeights(cellHeights);
+ timebar.setHeightPX(height);
+
+ } else if (isVerticalScrollable()) {
+ updateCellHeights();
+ wrapper.addStyleDependentName("Vsized");
+ timebar.setCellHeights(cellHeights);
+ timebar.setHeightPX(height);
+ }
+ }
+
+ public void clearDates() {
+ while (content.getWidgetCount() > 1) {
+ content.remove(1);
+ }
+
+ dateCellOfToday = null;
+ }
+
+ /**
+ * @return true if this weekgrid contains a date that is today
+ */
+ public boolean hasToday() {
+ return dateCellOfToday != null;
+ }
+
+ public void updateCellWidths() {
+ if (!isHorizontalScrollable() && width != -1) {
+ int count = content.getWidgetCount();
+ int datesWidth = width;
+ if (datesWidth > 0 && count > 1) {
+ cellWidths = VCalendar
+ .distributeSize(datesWidth, count - 1, -1);
+
+ for (int i = 1; i < count; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ dc.setHorizontalSized(isHorizontalScrollable() || width < 0);
+ dc.setWidthPX(cellWidths[i - 1]);
+ if (dc.isToday()) {
+ dc.setTimeBarWidth(getOffsetWidth());
+ }
+ }
+ }
+
+ } else {
+ int count = content.getWidgetCount();
+ if (count > 1) {
+ for (int i = 1; i < count; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ dc.setHorizontalSized(isHorizontalScrollable() || width < 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * @return an int-array containing the widths of the cells (days)
+ */
+ public int[] getDateCellWidths() {
+ return cellWidths;
+ }
+
+ public void updateCellHeights() {
+ if (!isVerticalScrollable()) {
+ int count = content.getWidgetCount();
+ if (count > 1) {
+ DateCell first = (DateCell) content.getWidget(1);
+ dateCellBorder = first.getSlotBorder();
+ cellHeights = VCalendar.distributeSize(height,
+ first.getNumberOfSlots(), -dateCellBorder);
+ for (int i = 1; i < count; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ dc.setHeightPX(height, cellHeights);
+ }
+ }
+
+ } else {
+ int count = content.getWidgetCount();
+ if (count > 1) {
+ DateCell first = (DateCell) content.getWidget(1);
+ dateCellBorder = first.getSlotBorder();
+ int dateHeight = (first.getOffsetHeight() / first
+ .getNumberOfSlots()) - dateCellBorder;
+ cellHeights = new int[48];
+ Arrays.fill(cellHeights, dateHeight);
+
+ for (int i = 1; i < count; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ dc.setVerticalSized(isVerticalScrollable());
+ }
+ }
+ }
+ }
+
+ public void addEvent(CalendarEvent e) {
+ int dateCount = content.getWidgetCount();
+ Date from = e.getStart();
+ Date toTime = e.getEndTime();
+ for (int i = 1; i < dateCount; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ Date dcDate = dc.getDate();
+ int comp = dcDate.compareTo(from);
+ int comp2 = dcDate.compareTo(toTime);
+ if (comp >= 0
+ && comp2 < 0
+ || (comp == 0 && comp2 == 0 && VCalendar
+ .isZeroLengthMidnightEvent(e))) {
+ // Same event may be over two DateCells if event's date
+ // range floats over one day. It can't float over two days,
+ // because event which range is over 24 hours, will be handled
+ // as a "fullDay" event.
+ dc.addEvent(dcDate, e);
+ }
+ }
+ }
+
+ public int getPixelLengthFor(int startFromMinutes, int durationInMinutes) {
+ int pixelLength = 0;
+ int currentSlot = 0;
+
+ int firstHourInMinutes = firstHour * 60;
+
+ if (firstHourInMinutes > startFromMinutes) {
+ startFromMinutes = 0;
+ } else {
+ startFromMinutes -= firstHourInMinutes;
+ }
+
+ // calculate full slots to event
+ int slotsTillEvent = startFromMinutes / slotInMinutes;
+ int startOverFlowTime = slotInMinutes
+ - (startFromMinutes % slotInMinutes);
+ if (startOverFlowTime == slotInMinutes) {
+ startOverFlowTime = 0;
+ currentSlot = slotsTillEvent;
+ } else {
+ currentSlot = slotsTillEvent + 1;
+ }
+
+ int durationInSlots = 0;
+ int endOverFlowTime = 0;
+
+ if (startOverFlowTime > 0) {
+ durationInSlots = (durationInMinutes - startOverFlowTime)
+ / slotInMinutes;
+ endOverFlowTime = (durationInMinutes - startOverFlowTime)
+ % slotInMinutes;
+
+ } else {
+ durationInSlots = durationInMinutes / slotInMinutes;
+ endOverFlowTime = durationInMinutes % slotInMinutes;
+ }
+
+ // calculate slot overflow at start
+ if (startOverFlowTime > 0 && currentSlot < cellHeights.length) {
+ int lastSlotHeight = cellHeights[currentSlot] + dateCellBorder;
+ pixelLength += (int) (((double) lastSlotHeight / (double) slotInMinutes) * startOverFlowTime);
+ }
+
+ // calculate length in full slots
+ int lastFullSlot = currentSlot + durationInSlots;
+ for (; currentSlot < lastFullSlot && currentSlot < cellHeights.length; currentSlot++) {
+ pixelLength += cellHeights[currentSlot] + dateCellBorder;
+ }
+
+ // calculate overflow at end
+ if (endOverFlowTime > 0 && currentSlot < cellHeights.length) {
+ int lastSlotHeight = cellHeights[currentSlot] + dateCellBorder;
+ pixelLength += (int) (((double) lastSlotHeight / (double) slotInMinutes) * endOverFlowTime);
+ }
+
+ // reduce possible underflow at end
+ if (endOverFlowTime < 0) {
+ int lastSlotHeight = cellHeights[currentSlot] + dateCellBorder;
+ pixelLength += (int) (((double) lastSlotHeight / (double) slotInMinutes) * endOverFlowTime);
+ }
+
+ return pixelLength;
+ }
+
+ public int getPixelTopFor(int startFromMinutes) {
+ int pixelsToTop = 0;
+ int slotIndex = 0;
+
+ int firstHourInMinutes = firstHour * 60;
+
+ if (firstHourInMinutes > startFromMinutes) {
+ startFromMinutes = 0;
+ } else {
+ startFromMinutes -= firstHourInMinutes;
+ }
+
+ // calculate full slots to event
+ int slotsTillEvent = startFromMinutes / slotInMinutes;
+ int overFlowTime = startFromMinutes % slotInMinutes;
+ if (slotsTillEvent > 0) {
+ for (slotIndex = 0; slotIndex < slotsTillEvent; slotIndex++) {
+ pixelsToTop += cellHeights[slotIndex] + dateCellBorder;
+ }
+ }
+
+ // calculate lengths less than one slot
+ if (overFlowTime > 0) {
+ int lastSlotHeight = cellHeights[slotIndex] + dateCellBorder;
+ pixelsToTop += ((double) lastSlotHeight / (double) slotInMinutes)
+ * overFlowTime;
+ }
+
+ return pixelsToTop;
+ }
+
+ public void eventMoved(DateCellDayEvent dayEvent) {
+ Style s = dayEvent.getElement().getStyle();
+ int left = Integer.parseInt(s.getLeft().substring(0,
+ s.getLeft().length() - 2));
+ DateCell previousParent = (DateCell) dayEvent.getParent();
+ DateCell newParent = (DateCell) content
+ .getWidget((left / getDateCellWidth()) + 1);
+ CalendarEvent se = dayEvent.getCalendarEvent();
+ previousParent.removeEvent(dayEvent);
+ newParent.addEvent(dayEvent);
+ if (!previousParent.equals(newParent)) {
+ previousParent.recalculateEventWidths();
+ }
+ newParent.recalculateEventWidths();
+ if (calendar.getEventMovedListener() != null) {
+ calendar.getEventMovedListener().eventMoved(se);
+ }
+ }
+
+ public void setToday(Date todayDate, Date todayTimestamp) {
+ int count = content.getWidgetCount();
+ if (count > 1) {
+ for (int i = 1; i < count; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ if (dc.getDate().getTime() == todayDate.getTime()) {
+ if (isVerticalScrollable()) {
+ dc.setToday(todayTimestamp, -1);
+ } else {
+ dc.setToday(todayTimestamp, getOffsetWidth());
+ }
+ }
+ dateCellOfToday = dc;
+ }
+ }
+ }
+
+ public DateCell getDateCellOfToday() {
+ return dateCellOfToday;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public Timebar getTimeBar() {
+ return timebar;
+ }
+
+ public void setDateColor(Date when, Date to, String styleName) {
+ int dateCount = content.getWidgetCount();
+ for (int i = 1; i < dateCount; i++) {
+ DateCell dc = (DateCell) content.getWidget(i);
+ Date dcDate = dc.getDate();
+ int comp = dcDate.compareTo(when);
+ int comp2 = dcDate.compareTo(to);
+ if (comp >= 0 && comp2 <= 0) {
+ dc.setDateColor(styleName);
+ }
+ }
+ }
+
+ /**
+ * @param calendar
+ * the calendar to set
+ */
+ public void setCalendar(VCalendar calendar) {
+ this.calendar = calendar;
+ }
+
+ /**
+ * @return the calendar
+ */
+ public VCalendar getCalendar() {
+ return calendar;
+ }
+
+ /**
+ * Get width of the single date cell
+ *
+ * @return Date cell width
+ */
+ public int getDateCellWidth() {
+ int count = content.getWidgetCount() - 1;
+ int cellWidth = -1;
+ if (count <= 0) {
+ return cellWidth;
+ }
+
+ if (width == -1) {
+ Widget firstWidget = content.getWidget(1);
+ cellWidth = firstWidget.getElement().getOffsetWidth();
+ } else {
+ cellWidth = getInternalWidth() / count;
+ }
+ return cellWidth;
+ }
+
+ /**
+ * @return the number of day cells in this week
+ */
+ public int getDateCellCount() {
+ return content.getWidgetCount() - 1;
+ }
+
+ public void setFirstHour(int firstHour) {
+ this.firstHour = firstHour;
+ timebar.setFirstHour(firstHour);
+ }
+
+ public void setLastHour(int lastHour) {
+ this.lastHour = lastHour;
+ timebar.setLastHour(lastHour);
+ }
+
+ public int getFirstHour() {
+ return firstHour;
+ }
+
+ public int getLastHour() {
+ return lastHour;
+ }
+
+ public static class Timebar extends HTML {
+
+ private static final int[] timesFor12h = { 12, 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11 };
+
+ private int height;
+
+ private final int verticalPadding = 7; // FIXME measure this from DOM
+
+ private int[] slotCellHeights;
+
+ private int firstHour;
+
+ private int lastHour;
+
+ public Timebar(boolean format24h) {
+ createTimeBar(format24h);
+ }
+
+ public void setLastHour(int lastHour) {
+ this.lastHour = lastHour;
+ }
+
+ public void setFirstHour(int firstHour) {
+ this.firstHour = firstHour;
+
+ }
+
+ public void setCellHeights(int[] cellHeights) {
+ slotCellHeights = cellHeights;
+ }
+
+ private void createTimeBar(boolean format24h) {
+ setStylePrimaryName("v-calendar-times");
+
+ // Fist "time" is empty
+ Element e = DOM.createDiv();
+ setStyleName(e, "v-calendar-time");
+ e.setInnerText("");
+ getElement().appendChild(e);
+
+ DateTimeService dts = new DateTimeService();
+
+ if (format24h) {
+ for (int i = firstHour + 1; i <= lastHour; i++) {
+ e = DOM.createDiv();
+ setStyleName(e, "v-calendar-time");
+ String delimiter = dts.getClockDelimeter();
+ e.setInnerHTML("<span>" + i + "</span>" + delimiter + "00");
+ getElement().appendChild(e);
+ }
+ } else {
+ // FIXME Use dts.getAmPmStrings(); and make sure that
+ // DateTimeService has a some Locale set.
+ String[] ampm = new String[] { "AM", "PM" };
+
+ int amStop = (lastHour < 11) ? lastHour : 11;
+ int pmStart = (firstHour > 11) ? firstHour % 11 : 0;
+
+ if (firstHour < 12) {
+ for (int i = firstHour + 1; i <= amStop; i++) {
+ e = DOM.createDiv();
+ setStyleName(e, "v-calendar-time");
+ e.setInnerHTML("<span>" + timesFor12h[i] + "</span>"
+ + " " + ampm[0]);
+ getElement().appendChild(e);
+ }
+ }
+
+ if (lastHour > 11) {
+ for (int i = pmStart; i < lastHour - 11; i++) {
+ e = DOM.createDiv();
+ setStyleName(e, "v-calendar-time");
+ e.setInnerHTML("<span>" + timesFor12h[i] + "</span>"
+ + " " + ampm[1]);
+ getElement().appendChild(e);
+ }
+ }
+ }
+ }
+
+ public void updateTimeBar(boolean format24h) {
+ clear();
+ createTimeBar(format24h);
+ }
+
+ private void clear() {
+ while (getElement().getChildCount() > 0) {
+ getElement().removeChild(getElement().getChild(0));
+ }
+ }
+
+ public void setHeightPX(int pixelHeight) {
+ height = pixelHeight;
+
+ if (pixelHeight > -1) {
+ // as the negative margins on children pulls the whole element
+ // upwards, we must compensate. otherwise the element would be
+ // too short
+ super.setHeight((height + verticalPadding) + "px");
+ removeStyleDependentName("Vsized");
+ updateChildHeights();
+
+ } else {
+ addStyleDependentName("Vsized");
+ updateChildHeights();
+ }
+ }
+
+ private void updateChildHeights() {
+ int childCount = getElement().getChildCount();
+
+ if (height != -1) {
+
+ // 23 hours + first is empty
+ // we try to adjust the height of time labels to the distributed
+ // heights of the time slots
+ int hoursPerDay = lastHour - firstHour + 1;
+
+ int slotsPerHour = slotCellHeights.length / hoursPerDay;
+ int[] cellHeights = new int[slotCellHeights.length
+ / slotsPerHour];
+
+ int slotHeightPosition = 0;
+ for (int i = 0; i < cellHeights.length; i++) {
+ for (int j = slotHeightPosition; j < slotHeightPosition
+ + slotsPerHour; j++) {
+ cellHeights[i] += slotCellHeights[j] + 1;
+ // 1px more for borders
+ // FIXME measure from DOM
+ }
+ slotHeightPosition += slotsPerHour;
+ }
+
+ for (int i = 0; i < childCount; i++) {
+ Element e = (Element) getElement().getChild(i);
+ e.getStyle().setHeight(cellHeights[i], Unit.PX);
+ }
+
+ } else {
+ for (int i = 0; i < childCount; i++) {
+ Element e = (Element) getElement().getChild(i);
+ e.getStyle().setProperty("height", "");
+ }
+ }
+ }
+ }
+
+ public VCalendar getParentCalendar() {
+ return calendar;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/WeekGridMinuteTimeRange.java b/client/src/com/vaadin/client/ui/calendar/schedule/WeekGridMinuteTimeRange.java
new file mode 100644
index 0000000000..e634735be7
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/WeekGridMinuteTimeRange.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+/**
+ * Internally used by the calendar
+ *
+ * @since 7.1
+ */
+public class WeekGridMinuteTimeRange {
+ private final Date start;
+ private final Date end;
+
+ /**
+ * Creates a Date time range between start and end date. Drops seconds from
+ * the range.
+ *
+ * @param start
+ * Start time of the range
+ * @param end
+ * End time of the range
+ * @param clearSeconds
+ * Boolean Indicates, if seconds should be dropped from the range
+ * start and end
+ */
+ public WeekGridMinuteTimeRange(Date start, Date end) {
+ this.start = new Date(start.getTime());
+ this.end = new Date(end.getTime());
+ this.start.setSeconds(0);
+ this.end.setSeconds(0);
+ }
+
+ public Date getStart() {
+ return start;
+ }
+
+ public Date getEnd() {
+ return end;
+ }
+
+ public static boolean doesOverlap(WeekGridMinuteTimeRange a,
+ WeekGridMinuteTimeRange b) {
+ boolean overlaps = a.getStart().compareTo(b.getEnd()) < 0
+ && a.getEnd().compareTo(b.getStart()) > 0;
+ return overlaps;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/WeekLabel.java b/client/src/com/vaadin/client/ui/calendar/schedule/WeekLabel.java
new file mode 100644
index 0000000000..bde8675435
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/WeekLabel.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import com.google.gwt.user.client.ui.Label;
+
+/**
+ * A label in the {@link SimpleWeekToolbar}
+ *
+ * @since 7.1
+ */
+public class WeekLabel extends Label {
+ private int week;
+ private int year;
+
+ public WeekLabel(String string, int week2, int year2) {
+ super(string);
+ setStylePrimaryName("v-calendar-week-number");
+ week = week2;
+ year = year2;
+ }
+
+ public int getWeek() {
+ return week;
+ }
+
+ public void setWeek(int week) {
+ this.week = week;
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public void setYear(int year) {
+ this.year = year;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java b/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java
new file mode 100644
index 0000000000..f7c5c0dac4
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEvents.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+import java.util.List;
+
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public class WeeklyLongEvents extends HorizontalPanel implements HasTooltipKey {
+
+ public static final int EVENT_HEIGTH = 15;
+
+ public static final int EVENT_MARGIN = 1;
+
+ private int rowCount = 0;
+
+ private VCalendar calendar;
+
+ private boolean undefinedWidth;
+
+ public WeeklyLongEvents(VCalendar calendar) {
+ setStylePrimaryName("v-calendar-weekly-longevents");
+ this.calendar = calendar;
+ }
+
+ public void addDate(Date d) {
+ DateCellContainer dcc = new DateCellContainer();
+ dcc.setDate(d);
+ dcc.setCalendar(calendar);
+ add(dcc);
+ }
+
+ public void setWidthPX(int width) {
+ if (getWidgetCount() == 0) {
+ return;
+ }
+ undefinedWidth = (width < 0);
+
+ updateCellWidths();
+ }
+
+ public void addEvents(List<CalendarEvent> events) {
+ for (CalendarEvent e : events) {
+ addEvent(e);
+ }
+ }
+
+ public void addEvent(CalendarEvent calendarEvent) {
+ updateEventSlot(calendarEvent);
+
+ int dateCount = getWidgetCount();
+ Date from = calendarEvent.getStart();
+ Date to = calendarEvent.getEnd();
+ boolean started = false;
+ for (int i = 0; i < dateCount; i++) {
+ DateCellContainer dc = (DateCellContainer) getWidget(i);
+ Date dcDate = dc.getDate();
+ int comp = dcDate.compareTo(from);
+ int comp2 = dcDate.compareTo(to);
+ WeeklyLongEventsDateCell eventLabel = dc.getDateCell(calendarEvent
+ .getSlotIndex());
+ eventLabel.setStylePrimaryName("v-calendar-event");
+ if (comp >= 0 && comp2 <= 0) {
+ eventLabel.setEvent(calendarEvent);
+ eventLabel.setCalendar(calendar);
+
+ eventLabel.addStyleDependentName("all-day");
+ if (comp == 0) {
+ eventLabel.addStyleDependentName("start");
+ }
+ if (comp2 == 0) {
+ eventLabel.addStyleDependentName("end");
+ }
+ if (!started && comp > 0 && comp2 <= 0) {
+ eventLabel.addStyleDependentName("continued-from");
+ } else if (i == (dateCount - 1)) {
+ eventLabel.addStyleDependentName("continued-to");
+ }
+ final String extraStyle = calendarEvent.getStyleName();
+ if (extraStyle != null && extraStyle.length() > 0) {
+ eventLabel.addStyleDependentName(extraStyle + "-all-day");
+ }
+ if (!started) {
+ eventLabel.setText(calendarEvent.getCaption());
+ started = true;
+ }
+ }
+ }
+ }
+
+ private void updateEventSlot(CalendarEvent e) {
+ boolean foundFreeSlot = false;
+ int slot = 0;
+ while (!foundFreeSlot) {
+ if (isSlotFree(slot, e.getStart(), e.getEnd())) {
+ e.setSlotIndex(slot);
+ foundFreeSlot = true;
+
+ } else {
+ slot++;
+ }
+ }
+ }
+
+ private boolean isSlotFree(int slot, Date start, Date end) {
+ int dateCount = getWidgetCount();
+
+ // Go over all dates this week
+ for (int i = 0; i < dateCount; i++) {
+ DateCellContainer dc = (DateCellContainer) getWidget(i);
+ Date dcDate = dc.getDate();
+ int comp = dcDate.compareTo(start);
+ int comp2 = dcDate.compareTo(end);
+
+ // check if the date is in the range we need
+ if (comp >= 0 && comp2 <= 0) {
+
+ // check if the slot is taken
+ if (dc.hasEvent(slot)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public int getRowCount() {
+ return rowCount;
+ }
+
+ public void updateCellWidths() {
+ int cells = getWidgetCount();
+ if (cells <= 0) {
+ return;
+ }
+
+ int cellWidth = -1;
+
+ // if width is undefined, use the width of the first cell
+ // otherwise use distributed sizes
+ if (undefinedWidth) {
+ cellWidth = calendar.getWeekGrid().getDateCellWidth()
+ - calendar.getWeekGrid().getDateSlotBorder();
+ }
+
+ for (int i = 0; i < cells; i++) {
+ DateCellContainer dc = (DateCellContainer) getWidget(i);
+
+ if (undefinedWidth) {
+ dc.setWidth(cellWidth + "px");
+
+ } else {
+ dc.setWidth(calendar.getWeekGrid().getDateCellWidths()[i]
+ + "px");
+ }
+ }
+ }
+
+ @Override
+ public String getTooltipKey() {
+ return null;
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEventsDateCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEventsDateCell.java
new file mode 100644
index 0000000000..a97d352e81
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/WeeklyLongEventsDateCell.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule;
+
+import java.util.Date;
+
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.client.ui.VCalendar;
+
+/**
+ * Represents a cell used in {@link WeeklyLongEvents}
+ *
+ * @since 7.1
+ */
+public class WeeklyLongEventsDateCell extends HTML implements HasTooltipKey {
+ private Date date;
+ private CalendarEvent calendarEvent;
+ private VCalendar calendar;
+
+ public WeeklyLongEventsDateCell() {
+ }
+
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+
+ public void setEvent(CalendarEvent event) {
+ calendarEvent = event;
+ }
+
+ public CalendarEvent getEvent() {
+ return calendarEvent;
+ }
+
+ public void setCalendar(VCalendar calendar) {
+ this.calendar = calendar;
+ }
+
+ public VCalendar getCalendar() {
+ return calendar;
+ }
+
+ @Override
+ public Object getTooltipKey() {
+ if (calendarEvent != null) {
+ return calendarEvent.getIndex();
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java
new file mode 100644
index 0000000000..aab9ca9c38
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarDropHandler.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule.dd;
+
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.ui.calendar.CalendarConnector;
+import com.vaadin.client.ui.dd.VAbstractDropHandler;
+
+/**
+ * Abstract base class for calendar drop handlers.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public abstract class CalendarDropHandler extends VAbstractDropHandler {
+
+ protected CalendarConnector calendarConnector;
+
+ /**
+ * Set the calendar instance
+ *
+ * @param calendarPaintable
+ */
+ public void setConnector(CalendarConnector calendarConnector) {
+ this.calendarConnector = calendarConnector;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#getConnector()
+ */
+ @Override
+ public CalendarConnector getConnector() {
+ return calendarConnector;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VDropHandler#getApplicationConnection
+ * ()
+ */
+ @Override
+ public ApplicationConnection getApplicationConnection() {
+ return calendarConnector.getClient();
+ }
+
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java
new file mode 100644
index 0000000000..913477ee14
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarMonthDropHandler.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule.dd;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.calendar.schedule.SimpleDayCell;
+import com.vaadin.client.ui.dd.VAcceptCallback;
+import com.vaadin.client.ui.dd.VDragEvent;
+
+/**
+ * Handles DD when the monthly view is showing in the Calendar. In the monthly
+ * view, drops are only allowed in the the day cells. Only the day index is
+ * included in the drop details sent to the server.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class CalendarMonthDropHandler extends CalendarDropHandler {
+
+ private Element currentTargetElement;
+ private SimpleDayCell currentTargetDay;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragAccepted
+ * (com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ protected void dragAccepted(VDragEvent drag) {
+ deEmphasis();
+ currentTargetElement = drag.getElementOver();
+ currentTargetDay = Util.findWidget(currentTargetElement,
+ SimpleDayCell.class);
+ emphasis();
+ }
+
+ /**
+ * Removed the emphasis CSS style name from the currently emphasized day
+ */
+ private void deEmphasis() {
+ if (currentTargetElement != null && currentTargetDay != null) {
+ currentTargetDay.removeEmphasisStyle();
+ currentTargetElement = null;
+ }
+ }
+
+ /**
+ * Add CSS style name for the currently emphasized day
+ */
+ private void emphasis() {
+ if (currentTargetElement != null && currentTargetDay != null) {
+ currentTargetDay.addEmphasisStyle();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragOver(com
+ * .vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public void dragOver(final VDragEvent drag) {
+ if (isLocationValid(drag.getElementOver())) {
+ validate(new VAcceptCallback() {
+ @Override
+ public void accepted(VDragEvent event) {
+ dragAccepted(drag);
+ }
+ }, drag);
+ }
+ }
+
+ /**
+ * Checks if the one can perform a drop in a element
+ *
+ * @param elementOver
+ * The element to check
+ * @return
+ */
+ private boolean isLocationValid(
+ com.google.gwt.user.client.Element elementOver) {
+ com.google.gwt.user.client.Element monthGridElement = calendarConnector
+ .getWidget().getMonthGrid().getElement();
+
+ // drops are not allowed in:
+ // - weekday header
+ // - week number bart
+ return DOM.isOrHasChild(monthGridElement, elementOver);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragEnter(com
+ * .vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public void dragEnter(VDragEvent drag) {
+ // NOOP, we determine drag acceptance in dragOver
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#drop(com.vaadin
+ * .terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public boolean drop(VDragEvent drag) {
+ if (isLocationValid(drag.getElementOver())) {
+ updateDropDetails(drag);
+ deEmphasis();
+ return super.drop(drag);
+
+ } else {
+ deEmphasis();
+ return false;
+ }
+ }
+
+ /**
+ * Updates the drop details sent to the server
+ *
+ * @param drag
+ * The drag event
+ */
+ private void updateDropDetails(VDragEvent drag) {
+ int dayIndex = calendarConnector.getWidget().getMonthGrid()
+ .getDayCellIndex(currentTargetDay);
+
+ drag.getDropDetails().put("dropDayIndex", dayIndex);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragLeave(com
+ * .vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public void dragLeave(VDragEvent drag) {
+ deEmphasis();
+ super.dragLeave(drag);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java
new file mode 100644
index 0000000000..0ea683dc3c
--- /dev/null
+++ b/client/src/com/vaadin/client/ui/calendar/schedule/dd/CalendarWeekDropHandler.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.calendar.schedule.dd;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.vaadin.client.Util;
+import com.vaadin.client.ui.calendar.schedule.DateCell;
+import com.vaadin.client.ui.calendar.schedule.DateCellDayEvent;
+import com.vaadin.client.ui.dd.VAcceptCallback;
+import com.vaadin.client.ui.dd.VDragEvent;
+
+/**
+ * Handles DD when the weekly view is showing in the Calendar. In the weekly
+ * view, drops are only allowed in the the time slots for each day. The slot
+ * index and the day index are included in the drop details sent to the server.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class CalendarWeekDropHandler extends CalendarDropHandler {
+
+ private com.google.gwt.user.client.Element currentTargetElement;
+ private DateCell currentTargetDay;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragAccepted
+ * (com.vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ protected void dragAccepted(VDragEvent drag) {
+ deEmphasis();
+ currentTargetElement = drag.getElementOver();
+ currentTargetDay = Util
+ .findWidget(currentTargetElement, DateCell.class);
+ emphasis();
+ }
+
+ /**
+ * Removes the CSS style name from the emphasized element
+ */
+ private void deEmphasis() {
+ if (currentTargetElement != null) {
+ currentTargetDay.removeEmphasisStyle(currentTargetElement);
+ currentTargetElement = null;
+ }
+ }
+
+ /**
+ * Add a CSS stylen name to current target element
+ */
+ private void emphasis() {
+ currentTargetDay.addEmphasisStyle(currentTargetElement);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragOver(com
+ * .vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public void dragOver(final VDragEvent drag) {
+ if (isLocationValid(drag.getElementOver())) {
+ validate(new VAcceptCallback() {
+ @Override
+ public void accepted(VDragEvent event) {
+ dragAccepted(drag);
+ }
+ }, drag);
+ }
+ }
+
+ /**
+ * Checks if the location is a valid drop location
+ *
+ * @param elementOver
+ * The element to check
+ * @return
+ */
+ private boolean isLocationValid(
+ com.google.gwt.user.client.Element elementOver) {
+ com.google.gwt.user.client.Element weekGridElement = calendarConnector
+ .getWidget().getWeekGrid().getElement();
+ com.google.gwt.user.client.Element timeBarElement = calendarConnector
+ .getWidget().getWeekGrid().getTimeBar().getElement();
+
+ com.google.gwt.user.client.Element todayBarElement = null;
+ if (calendarConnector.getWidget().getWeekGrid().hasToday()) {
+ todayBarElement = (Element) calendarConnector.getWidget()
+ .getWeekGrid().getDateCellOfToday().getTodaybarElement();
+ }
+
+ // drops are not allowed in:
+ // - weekday header
+ // - allday event list
+ // - todaybar
+ // - timebar
+ // - events
+ return DOM.isOrHasChild(weekGridElement, elementOver)
+ && !DOM.isOrHasChild(timeBarElement, elementOver)
+ && todayBarElement != elementOver
+ && (Util.findWidget(elementOver, DateCellDayEvent.class) == null);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragEnter(com
+ * .vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public void dragEnter(VDragEvent drag) {
+ // NOOP, we determine drag acceptance in dragOver
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#drop(com.vaadin
+ * .terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public boolean drop(VDragEvent drag) {
+ if (isLocationValid(drag.getElementOver())) {
+ updateDropDetails(drag);
+ deEmphasis();
+ return super.drop(drag);
+
+ } else {
+ deEmphasis();
+ return false;
+ }
+ }
+
+ /**
+ * Update the drop details sent to the server
+ *
+ * @param drag
+ * The drag event
+ */
+ private void updateDropDetails(VDragEvent drag) {
+ int slotIndex = currentTargetDay.getSlotIndex(currentTargetElement);
+ int dayIndex = calendarConnector.getWidget().getWeekGrid()
+ .getDateCellIndex(currentTargetDay);
+
+ drag.getDropDetails().put("dropDayIndex", dayIndex);
+ drag.getDropDetails().put("dropSlotIndex", slotIndex);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.terminal.gwt.client.ui.dd.VAbstractDropHandler#dragLeave(com
+ * .vaadin.terminal.gwt.client.ui.dd.VDragEvent)
+ */
+ @Override
+ public void dragLeave(VDragEvent drag) {
+ deEmphasis();
+ super.dragLeave(drag);
+ }
+}
diff --git a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
index 772419e730..85e4e5ee8b 100644
--- a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
+++ b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java
@@ -69,6 +69,8 @@ public class CheckBoxConnector extends AbstractFieldConnector implements
blurHandlerRegistration);
if (null != getState().errorMessage) {
+ getWidget().setAriaInvalid(true);
+
if (getWidget().errorIndicatorElement == null) {
getWidget().errorIndicatorElement = DOM.createSpan();
getWidget().errorIndicatorElement.setInnerHTML("&nbsp;");
@@ -85,8 +87,11 @@ public class CheckBoxConnector extends AbstractFieldConnector implements
} else if (getWidget().errorIndicatorElement != null) {
DOM.setStyleAttribute(getWidget().errorIndicatorElement, "display",
"none");
+
+ getWidget().setAriaInvalid(false);
}
+ getWidget().setAriaRequired(isRequired());
if (isReadOnly()) {
getWidget().setEnabled(false);
}
diff --git a/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java
index beff3eaa72..2fb40b3cdb 100644
--- a/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java
+++ b/client/src/com/vaadin/client/ui/datefield/InlineDateFieldConnector.java
@@ -114,6 +114,8 @@ public class InlineDateFieldConnector extends AbstractDateFieldConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
getWidget().setTabIndex(getState().tabIndex);
+ getWidget().calendarPanel.setRangeStart(getState().rangeStart);
+ getWidget().calendarPanel.setRangeEnd(getState().rangeEnd);
}
@Override
diff --git a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
index 7246c27b6b..b3bb481658 100644
--- a/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
+++ b/client/src/com/vaadin/client/ui/datefield/PopupDateFieldConnector.java
@@ -119,6 +119,8 @@ public class PopupDateFieldConnector extends TextualDateConnector {
+ "-button-readonly");
}
+ getWidget().setDescriptionForAssistiveDevices(
+ getState().descriptionForAssistiveDevices);
getWidget().calendarToggle.setEnabled(true);
}
@@ -136,6 +138,8 @@ public class PopupDateFieldConnector extends TextualDateConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
getWidget().setTextFieldEnabled(getState().textFieldEnabled);
+ getWidget().setRangeStart(getState().rangeStart);
+ getWidget().setRangeEnd(getState().rangeEnd);
}
@Override
diff --git a/client/src/com/vaadin/client/ui/form/FormConnector.java b/client/src/com/vaadin/client/ui/form/FormConnector.java
index 22277b6974..acd0e917fc 100644
--- a/client/src/com/vaadin/client/ui/form/FormConnector.java
+++ b/client/src/com/vaadin/client/ui/form/FormConnector.java
@@ -231,4 +231,9 @@ public class FormConnector extends AbstractComponentContainerConnector
// as a part of the actual layout
return null;
}
+
+ @Override
+ public boolean hasTooltip() {
+ return false;
+ }
}
diff --git a/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java b/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java
index 1a952959f3..c65f689f7a 100644
--- a/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java
+++ b/client/src/com/vaadin/client/ui/formlayout/FormLayoutConnector.java
@@ -141,4 +141,13 @@ public class FormLayoutConnector extends AbstractLayoutConnector {
return info;
}
+ @Override
+ public boolean hasTooltip() {
+ /*
+ * Tooltips are fetched from child connectors -> there's no quick way of
+ * checking whether there might a tooltip hiding somewhere
+ */
+ return true;
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/menubar/MenuBarConnector.java b/client/src/com/vaadin/client/ui/menubar/MenuBarConnector.java
index d8ca73a401..3e22ebb05b 100644
--- a/client/src/com/vaadin/client/ui/menubar/MenuBarConnector.java
+++ b/client/src/com/vaadin/client/ui/menubar/MenuBarConnector.java
@@ -209,4 +209,14 @@ public class MenuBarConnector extends AbstractComponentConnector implements
return info;
}
+
+ @Override
+ public boolean hasTooltip() {
+ /*
+ * Item tooltips are not processed until updateFromUIDL, so we can't be
+ * sure that there are no tooltips during onStateChange when this method
+ * is used.
+ */
+ return true;
+ }
}
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
index 50de8e0936..cb6ad25e97 100644
--- a/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
+++ b/client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java
@@ -31,6 +31,7 @@ import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler;
import com.vaadin.client.ui.AbstractFieldConnector;
import com.vaadin.client.ui.AbstractLayoutConnector;
import com.vaadin.client.ui.LayoutClickEventHandler;
+import com.vaadin.client.ui.aria.AriaHelper;
import com.vaadin.client.ui.layout.ElementResizeEvent;
import com.vaadin.client.ui.layout.ElementResizeListener;
import com.vaadin.shared.AbstractFieldState;
@@ -258,6 +259,10 @@ public abstract class AbstractOrderedLayoutConnector extends
slot.setCaption(caption, iconUrlString, styles, error, showError,
required, enabled);
+ AriaHelper.handleInputRequired(child.getWidget(), required);
+ AriaHelper.handleInputInvalid(child.getWidget(), showError);
+ AriaHelper.bindCaption(child.getWidget(), slot.getCaptionElement());
+
if (slot.hasCaption()) {
CaptionPosition pos = slot.getCaptionPosition();
getLayoutManager().addElementResizeListener(
diff --git a/client/src/com/vaadin/client/ui/orderedlayout/Slot.java b/client/src/com/vaadin/client/ui/orderedlayout/Slot.java
index 5fab131c65..00ff5bbc5a 100644
--- a/client/src/com/vaadin/client/ui/orderedlayout/Slot.java
+++ b/client/src/com/vaadin/client/ui/orderedlayout/Slot.java
@@ -18,6 +18,7 @@ package com.vaadin.client.ui.orderedlayout;
import java.util.List;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
@@ -507,6 +508,11 @@ public final class Slot extends SimplePanel {
// character)
requiredIcon.setInnerHTML("*");
requiredIcon.setClassName("v-required-field-indicator");
+
+ // The star should not be read by the screen reader, as it is
+ // purely visual. Required state is set at the element level for
+ // the screen reader.
+ Roles.getTextboxRole().setAriaHiddenState(requiredIcon, true);
}
caption.appendChild(requiredIcon);
} else if (requiredIcon != null) {
diff --git a/client/src/com/vaadin/client/ui/table/TableConnector.java b/client/src/com/vaadin/client/ui/table/TableConnector.java
index 6e50bab9ab..36587ffe4d 100644
--- a/client/src/com/vaadin/client/ui/table/TableConnector.java
+++ b/client/src/com/vaadin/client/ui/table/TableConnector.java
@@ -395,6 +395,16 @@ public class TableConnector extends AbstractHasComponentsConnector implements
}
@Override
+ public boolean hasTooltip() {
+ /*
+ * Tooltips for individual rows and cells are not processed until
+ * updateFromUIDL, so we can't be sure that there are no tooltips during
+ * onStateChange when this method is used.
+ */
+ return true;
+ }
+
+ @Override
public void onConnectorHierarchyChange(
ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) {
// TODO Move code from updateFromUIDL to this method
diff --git a/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java b/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java
index f1ad5e792a..04a514738d 100644
--- a/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java
+++ b/client/src/com/vaadin/client/ui/tabsheet/TabsheetConnector.java
@@ -138,6 +138,16 @@ public class TabsheetConnector extends TabsheetBaseConnector implements
}
@Override
+ public boolean hasTooltip() {
+ /*
+ * Tab tooltips are not processed until updateFromUIDL, so we can't be
+ * sure that there are no tooltips during onStateChange when this method
+ * is used.
+ */
+ return true;
+ }
+
+ @Override
public void onConnectorHierarchyChange(
ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) {
// TODO Move code from updateFromUIDL to this method
diff --git a/client/src/com/vaadin/client/ui/tree/TreeConnector.java b/client/src/com/vaadin/client/ui/tree/TreeConnector.java
index d6d1cef8cc..ef016c31b7 100644
--- a/client/src/com/vaadin/client/ui/tree/TreeConnector.java
+++ b/client/src/com/vaadin/client/ui/tree/TreeConnector.java
@@ -19,6 +19,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
@@ -26,6 +27,7 @@ import com.vaadin.client.Paintable;
import com.vaadin.client.TooltipInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
+import com.vaadin.client.VConsole;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.VTree;
@@ -93,7 +95,7 @@ public class TreeConnector extends AbstractComponentConnector implements
}
childTree = getWidget().new TreeNode();
getConnection().getVTooltip().connectHandlersToWidget(childTree);
- updateNodeFromUIDL(childTree, childUidl);
+ updateNodeFromUIDL(childTree, childUidl, 1);
getWidget().body.add(childTree);
childTree.addStyleDependentName("root");
childTree.childNodeContainer.addStyleDependentName("root");
@@ -108,6 +110,9 @@ public class TreeConnector extends AbstractComponentConnector implements
getWidget().isMultiselect = "multi".equals(selectMode);
if (getWidget().isMultiselect) {
+ Roles.getTreeRole().setAriaMultiselectableProperty(
+ getWidget().getElement(), true);
+
if (BrowserInfo.get().isTouchDevice()) {
// Always use the simple mode for touch devices that do not have
// shift/ctrl keys (#8595)
@@ -116,6 +121,9 @@ public class TreeConnector extends AbstractComponentConnector implements
getWidget().multiSelectMode = MultiSelectMode.valueOf(uidl
.getStringAttribute("multiselectmode"));
}
+ } else {
+ Roles.getTreeRole().setAriaMultiselectableProperty(
+ getWidget().getElement(), false);
}
getWidget().selectedIds = uidl.getStringArrayVariableAsSet("selected");
@@ -169,7 +177,18 @@ public class TreeConnector extends AbstractComponentConnector implements
// expanding node happened server side
rootNode.setState(true, false);
}
- renderChildNodes(rootNode, (Iterator) uidl.getChildIterator());
+ String levelPropertyString = Roles.getTreeitemRole()
+ .getAriaLevelProperty(rootNode.getElement());
+ int levelProperty;
+ try {
+ levelProperty = Integer.valueOf(levelPropertyString);
+ } catch (NumberFormatException e) {
+ levelProperty = 1;
+ VConsole.error(e);
+ }
+
+ renderChildNodes(rootNode, (Iterator) uidl.getChildIterator(),
+ levelProperty + 1);
}
}
@@ -196,7 +215,10 @@ public class TreeConnector extends AbstractComponentConnector implements
}
- public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl) {
+ public void updateNodeFromUIDL(TreeNode treeNode, UIDL uidl, int level) {
+ Roles.getTreeitemRole().setAriaLevelProperty(treeNode.getElement(),
+ level);
+
String nodeKey = uidl.getStringAttribute("key");
treeNode.setText(uidl
.getStringAttribute(TreeConstants.ATTRIBUTE_NODE_CAPTION));
@@ -212,7 +234,8 @@ public class TreeConnector extends AbstractComponentConnector implements
if (uidl.getChildCount() == 0) {
treeNode.childNodeContainer.setVisible(false);
} else {
- renderChildNodes(treeNode, (Iterator) uidl.getChildIterator());
+ renderChildNodes(treeNode, (Iterator) uidl.getChildIterator(),
+ level + 1);
treeNode.childrenLoaded = true;
}
} else {
@@ -239,11 +262,14 @@ public class TreeConnector extends AbstractComponentConnector implements
getWidget().selectedIds.add(nodeKey);
}
- treeNode.setIcon(uidl
- .getStringAttribute(TreeConstants.ATTRIBUTE_NODE_ICON));
+ String iconUrl = uidl
+ .getStringAttribute(TreeConstants.ATTRIBUTE_NODE_ICON);
+ String iconAltText = uidl
+ .getStringAttribute(TreeConstants.ATTRIBUTE_NODE_ICON_ALT);
+ treeNode.setIcon(iconUrl, iconAltText);
}
- void renderChildNodes(TreeNode containerNode, Iterator<UIDL> i) {
+ void renderChildNodes(TreeNode containerNode, Iterator<UIDL> i, int level) {
containerNode.childNodeContainer.clear();
containerNode.childNodeContainer.setVisible(true);
while (i.hasNext()) {
@@ -256,7 +282,7 @@ public class TreeConnector extends AbstractComponentConnector implements
}
final TreeNode childTree = getWidget().new TreeNode();
getConnection().getVTooltip().connectHandlersToWidget(childTree);
- updateNodeFromUIDL(childTree, childUidl);
+ updateNodeFromUIDL(childTree, childUidl, level);
containerNode.childNodeContainer.add(childTree);
if (!i.hasNext()) {
childTree
@@ -306,4 +332,14 @@ public class TreeConnector extends AbstractComponentConnector implements
return info;
}
+ @Override
+ public boolean hasTooltip() {
+ /*
+ * Item tooltips are not processed until updateFromUIDL, so we can't be
+ * sure that there are no tooltips during onStateChange when this method
+ * is used.
+ */
+ return true;
+ }
+
}
diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java
index 593aa0d793..643d687f1d 100644
--- a/client/src/com/vaadin/client/ui/ui/UIConnector.java
+++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java
@@ -21,9 +21,13 @@ import java.util.List;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.HeadElement;
+import com.google.gwt.dom.client.LinkElement;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
+import com.google.gwt.dom.client.StyleInjector;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.event.logical.shared.ResizeEvent;
@@ -34,6 +38,7 @@ 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.RootPanel;
import com.google.gwt.user.client.ui.Widget;
@@ -45,7 +50,6 @@ import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.Focusable;
import com.vaadin.client.Paintable;
-import com.vaadin.client.TooltipInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.VConsole;
import com.vaadin.client.communication.StateChangeEvent;
@@ -57,12 +61,16 @@ import com.vaadin.client.ui.VNotification;
import com.vaadin.client.ui.VUI;
import com.vaadin.client.ui.layout.MayScrollChildren;
import com.vaadin.client.ui.window.WindowConnector;
+import com.vaadin.server.Page.Styles;
import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.communication.MethodInvocation;
import com.vaadin.shared.ui.ComponentStateUtil;
import com.vaadin.shared.ui.Connect;
import com.vaadin.shared.ui.Connect.LoadStyle;
import com.vaadin.shared.ui.ui.PageClientRpc;
+import com.vaadin.shared.ui.ui.PageState;
import com.vaadin.shared.ui.ui.ScrollClientRpc;
+import com.vaadin.shared.ui.ui.UIClientRpc;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
@@ -91,6 +99,12 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
public void setTitle(String title) {
com.google.gwt.user.client.Window.setTitle(title);
}
+
+ @Override
+ public void reload() {
+ Window.Location.reload();
+
+ }
});
registerRpc(ScrollClientRpc.class, new ScrollClientRpc() {
@Override
@@ -103,13 +117,29 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getWidget().getElement().setScrollLeft(scrollLeft);
}
});
+ registerRpc(UIClientRpc.class, new UIClientRpc() {
+ @Override
+ public void uiClosed(final boolean sessionExpired) {
+ Scheduler.get().scheduleDeferred(new ScheduledCommand() {
+ @Override
+ public void execute() {
+ if (sessionExpired) {
+ getConnection().showSessionExpiredError(null);
+ } else {
+ getState().enabled = false;
+ updateEnabledState(getState().enabled);
+ }
+ }
+ });
+ }
+ });
getWidget().addResizeHandler(new ResizeHandler() {
@Override
public void onResize(ResizeEvent event) {
getRpcProxy(UIServerRpc.class).resize(event.getHeight(),
event.getWidth(), Window.getClientWidth(),
Window.getClientHeight());
- if (getState().immediate) {
+ if (getState().immediate || getPageState().hasResizeListeners) {
getConnection().sendPendingVariableChanges();
}
}
@@ -257,6 +287,8 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
final UIDL notification = (UIDL) it.next();
VNotification.showNotification(client, notification);
}
+ } else if (tag == "css-injections") {
+ injectCSS(childUidl);
}
}
@@ -326,6 +358,47 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
getWidget().rendering = false;
}
+ /**
+ * Reads CSS strings and resources injected by {@link Styles#inject} from
+ * the UIDL stream.
+ *
+ * @param uidl
+ * The uidl which contains "css-resource" and "css-string" tags
+ */
+ private void injectCSS(UIDL uidl) {
+
+ final HeadElement head = HeadElement.as(Document.get()
+ .getElementsByTagName(HeadElement.TAG).getItem(0));
+
+ /*
+ * Search the UIDL stream for CSS resources and strings to be injected.
+ */
+ for (Iterator<?> it = uidl.getChildIterator(); it.hasNext();) {
+ UIDL cssInjectionsUidl = (UIDL) it.next();
+
+ // Check if we have resources to inject
+ if (cssInjectionsUidl.getTag().equals("css-resource")) {
+ String url = getWidget().connection
+ .translateVaadinUri(cssInjectionsUidl
+ .getStringAttribute("url"));
+ LinkElement link = LinkElement.as(DOM
+ .createElement(LinkElement.TAG));
+ link.setRel("stylesheet");
+ link.setHref(url);
+ link.setType("text/css");
+ head.appendChild(link);
+
+ // Check if we have CSS string to inject
+ } else if (cssInjectionsUidl.getTag().equals("css-string")) {
+ for (Iterator<?> it2 = cssInjectionsUidl.getChildIterator(); it2
+ .hasNext();) {
+ StyleInjector.injectAtEnd((String) it2.next());
+ StyleInjector.flush();
+ }
+ }
+ }
+ }
+
public void init(String rootPanelId,
ApplicationConnection applicationConnection) {
DOM.sinkEvents(getWidget().getElement(), Event.ONKEYDOWN
@@ -339,8 +412,6 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
String themeName = applicationConnection.getConfiguration()
.getThemeName();
- // Remove chars that are not suitable for style names
- themeName = themeName.replaceAll("[^a-zA-Z0-9]", "");
root.addStyleName(themeName);
root.add(getWidget());
@@ -368,6 +439,8 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
};
+ private Timer pollTimer = null;
+
@Override
public void updateCaption(ComponentConnector component) {
// NOP The main view never draws caption for its layout
@@ -432,6 +505,23 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
return (UIState) super.getState();
}
+ /**
+ * Returns the state of the Page associated with the UI.
+ * <p>
+ * Note that state is considered an internal part of the connector. You
+ * should not rely on the state object outside of the connector who owns it.
+ * If you depend on the state of other connectors you should use their
+ * public API instead of their state object directly. The page state might
+ * not be an independent state object but can be embedded in UI state.
+ * </p>
+ *
+ * @since 7.1
+ * @return state object of the page
+ */
+ public PageState getPageState() {
+ return getState().pageState;
+ }
+
@Override
public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
ComponentConnector oldChild = null;
@@ -477,13 +567,13 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
@Override
- public TooltipInfo getTooltipInfo(com.google.gwt.dom.client.Element element) {
+ public boolean hasTooltip() {
/*
- * Override method to make AbstractComponentConnector.hasTooltip()
- * return true so there's a top level handler that takes care of hiding
- * tooltips whenever the mouse is moved somewhere else.
+ * Always return true so there's always top level tooltip handler that
+ * takes care of hiding tooltips whenever the mouse is moved somewhere
+ * else.
*/
- return super.getTooltipInfo(element);
+ return true;
}
/**
@@ -505,4 +595,74 @@ public class UIConnector extends AbstractSingleComponentContainerConnector
}
});
}
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+ if (stateChangeEvent.hasPropertyChanged("tooltipConfiguration")) {
+ getConnection().getVTooltip().setCloseTimeout(
+ getState().tooltipConfiguration.closeTimeout);
+ getConnection().getVTooltip().setOpenDelay(
+ getState().tooltipConfiguration.openDelay);
+ getConnection().getVTooltip().setQuickOpenDelay(
+ getState().tooltipConfiguration.quickOpenDelay);
+ getConnection().getVTooltip().setQuickOpenTimeout(
+ getState().tooltipConfiguration.quickOpenTimeout);
+ getConnection().getVTooltip().setMaxWidth(
+ getState().tooltipConfiguration.maxWidth);
+ }
+
+ if (stateChangeEvent
+ .hasPropertyChanged("loadingIndicatorConfiguration")) {
+ getConnection().getLoadingIndicator().setFirstDelay(
+ getState().loadingIndicatorConfiguration.firstDelay);
+ getConnection().getLoadingIndicator().setSecondDelay(
+ getState().loadingIndicatorConfiguration.secondDelay);
+ getConnection().getLoadingIndicator().setThirdDelay(
+ getState().loadingIndicatorConfiguration.thirdDelay);
+ }
+
+ if (stateChangeEvent.hasPropertyChanged("pollInterval")) {
+ configurePolling();
+ }
+
+ if (stateChangeEvent.hasPropertyChanged("pushMode")) {
+ getConnection().setPushEnabled(getState().pushMode.isEnabled());
+ }
+
+ if (stateChangeEvent.hasPropertyChanged("overlayContainerLabel")) {
+ getConnection().setOverlayContainerLabel(
+ getState().overlayContainerLabel);
+ }
+ }
+
+ private void configurePolling() {
+ if (pollTimer != null) {
+ pollTimer.cancel();
+ pollTimer = null;
+ }
+ if (getState().pollInterval >= 0) {
+ pollTimer = new Timer() {
+ @Override
+ public void run() {
+ /*
+ * Verify that polling has not recently been canceled. This
+ * is needed because Timer.cancel() does not always work
+ * properly in IE 8 until GWT issue 8101 has been fixed.
+ */
+ if (pollTimer != null) {
+ getRpcProxy(UIServerRpc.class).poll();
+ // Send changes even though poll is @Delayed
+ getConnection().sendPendingVariableChanges();
+ }
+ }
+ };
+ pollTimer.scheduleRepeating(getState().pollInterval);
+ } else {
+ // Ensure no more polls are sent as polling has been disabled
+ getConnection().removePendingInvocations(
+ new MethodInvocation(getConnectorId(), UIServerRpc.class
+ .getName(), "poll"));
+ }
+ }
}
diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java
index 8cfc25a9dc..90311e30ad 100644
--- a/client/src/com/vaadin/client/ui/window/WindowConnector.java
+++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java
@@ -20,7 +20,10 @@ import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.user.client.DOM;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.DoubleClickEvent;
+import com.google.gwt.event.dom.client.DoubleClickHandler;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.vaadin.client.ApplicationConnection;
@@ -31,6 +34,7 @@ import com.vaadin.client.LayoutManager;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
+import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.client.ui.AbstractSingleComponentContainerConnector;
import com.vaadin.client.ui.ClickEventHandler;
import com.vaadin.client.ui.PostLayoutListener;
@@ -41,6 +45,7 @@ import com.vaadin.client.ui.VWindow;
import com.vaadin.client.ui.layout.MayScrollChildren;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.window.WindowMode;
import com.vaadin.shared.ui.window.WindowServerRpc;
import com.vaadin.shared.ui.window.WindowState;
@@ -57,7 +62,32 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
}
};
- boolean minWidthChecked = false;
+ abstract class WindowEventHandler implements ClickHandler,
+ DoubleClickHandler {
+ }
+
+ private WindowEventHandler maximizeRestoreClickHandler = new WindowEventHandler() {
+
+ @Override
+ public void onClick(ClickEvent event) {
+ final Element target = event.getNativeEvent().getEventTarget()
+ .cast();
+ if (target == getWidget().maximizeRestoreBox) {
+ // Click on maximize/restore box
+ onMaximizeRestore();
+ }
+ }
+
+ @Override
+ public void onDoubleClick(DoubleClickEvent event) {
+ final Element target = event.getNativeEvent().getEventTarget()
+ .cast();
+ if (getWidget().header.isOrHasChild(target)) {
+ // Double click on header
+ onMaximizeRestore();
+ }
+ }
+ };
@Override
public boolean delegateCaptionHandling() {
@@ -68,12 +98,18 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
protected void init() {
super.init();
+ VWindow window = getWidget();
+
getLayoutManager().registerDependency(this,
- getWidget().contentPanel.getElement());
- getLayoutManager().registerDependency(this, getWidget().header);
- getLayoutManager().registerDependency(this, getWidget().footer);
+ window.contentPanel.getElement());
+ getLayoutManager().registerDependency(this, window.header);
+ getLayoutManager().registerDependency(this, window.footer);
- getWidget().setOwner(getConnection().getUIConnector().getWidget());
+ window.addHandler(maximizeRestoreClickHandler, ClickEvent.getType());
+ window.addHandler(maximizeRestoreClickHandler,
+ DoubleClickEvent.getType());
+
+ window.setOwner(getConnection().getUIConnector().getWidget());
}
@Override
@@ -87,109 +123,46 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
- getWidget().id = getConnectorId();
- getWidget().client = client;
-
- // Workaround needed for Testing Tools (GWT generates window DOM
- // slightly different in different browsers).
- DOM.setElementProperty(getWidget().closeBox, "id", getConnectorId()
- + "_window_close");
- if (isRealUpdate(uidl)) {
- if (getState().modal != getWidget().vaadinModality) {
- getWidget().setVaadinModality(!getWidget().vaadinModality);
- }
- if (!getWidget().isAttached()) {
- getWidget().setVisible(false); // hide until
- // possible centering
- getWidget().show();
- }
- if (getState().resizable != getWidget().resizable) {
- getWidget().setResizable(getState().resizable);
- }
- getWidget().resizeLazy = getState().resizeLazy;
+ VWindow window = getWidget();
+ String connectorId = getConnectorId();
- getWidget().setDraggable(getState().draggable);
+ window.id = getConnectorId();
+ window.client = client;
- // Caption must be set before required header size is measured. If
- // the caption attribute is missing the caption should be cleared.
- String iconURL = null;
- if (getIcon() != null) {
- iconURL = getIcon();
- }
- getWidget().setCaption(getState().caption, iconURL);
- }
+ // Workaround needed for Testing Tools (GWT generates window DOM
+ // slightly different in different browsers).
+ window.closeBox.setId(connectorId + "_window_close");
+ window.maximizeRestoreBox
+ .setId(connectorId + "_window_maximizerestore");
- getWidget().visibilityChangesDisabled = true;
+ window.visibilityChangesDisabled = true;
if (!isRealUpdate(uidl)) {
return;
}
- getWidget().visibilityChangesDisabled = false;
-
- clickEventHandler.handleEventHandlerRegistration();
-
- getWidget().immediate = getState().immediate;
-
- getWidget().setClosable(!isReadOnly());
-
- // Initialize the position form UIDL
- int positionx = getState().positionX;
- int positiony = getState().positionY;
- if (positionx >= 0 || positiony >= 0) {
- if (positionx < 0) {
- positionx = 0;
- }
- if (positiony < 0) {
- positiony = 0;
- }
- getWidget().setPopupPosition(positionx, positiony);
- }
-
- int childIndex = 0;
+ window.visibilityChangesDisabled = false;
// we may have actions
for (int i = 0; i < uidl.getChildCount(); i++) {
UIDL childUidl = uidl.getChildUIDL(i);
if (childUidl.getTag().equals("actions")) {
- if (getWidget().shortcutHandler == null) {
- getWidget().shortcutHandler = new ShortcutActionHandler(
- getConnectorId(), client);
+ if (window.shortcutHandler == null) {
+ window.shortcutHandler = new ShortcutActionHandler(
+ connectorId, client);
}
- getWidget().shortcutHandler.updateActionMap(childUidl);
+ window.shortcutHandler.updateActionMap(childUidl);
}
}
- // setting scrollposition must happen after children is rendered
- getWidget().contentPanel.setScrollPosition(getState().scrollTop);
- getWidget().contentPanel
- .setHorizontalScrollPosition(getState().scrollLeft);
-
- // Center this window on screen if requested
- // This had to be here because we might not know the content size before
- // everything is painted into the window
-
- // centered is this is unset on move/resize
- getWidget().centered = getState().centered;
- getWidget().setVisible(true);
-
- // ensure window is not larger than browser window
- if (getWidget().getOffsetWidth() > Window.getClientWidth()) {
- getWidget().setWidth(Window.getClientWidth() + "px");
- }
- if (getWidget().getOffsetHeight() > Window.getClientHeight()) {
- getWidget().setHeight(Window.getClientHeight() + "px");
- }
-
if (uidl.hasAttribute("bringToFront")) {
/*
* Focus as a side-effect. Will be overridden by
* ApplicationConnection if another component was focused by the
* server side.
*/
- getWidget().contentPanel.focus();
- getWidget().bringToFrontSequence = uidl
- .getIntAttribute("bringToFront");
+ window.contentPanel.focus();
+ window.bringToFrontSequence = uidl.getIntAttribute("bringToFront");
VWindow.deferOrdering();
}
}
@@ -224,26 +197,6 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
boolean hasContent = (content != null);
Element contentElement = window.contentPanel.getElement();
- if (!minWidthChecked) {
- boolean needsMinWidth = !isUndefinedWidth() || !hasContent
- || content.isRelativeWidth();
- int minWidth = window.getMinWidth();
- if (needsMinWidth && lm.getInnerWidth(contentElement) < minWidth) {
- minWidthChecked = true;
- // Use minimum width if less than a certain size
- window.setWidth(minWidth + "px");
- }
- minWidthChecked = true;
- }
-
- boolean needsMinHeight = !isUndefinedHeight() || !hasContent
- || content.isRelativeHeight();
- int minHeight = window.getMinHeight();
- if (needsMinHeight && lm.getInnerHeight(contentElement) < minHeight) {
- // Use minimum height if less than a certain size
- window.setHeight(minHeight + "px");
- }
-
Style contentStyle = window.contents.getStyle();
int headerHeight = lm.getOuterHeight(window.header);
@@ -291,9 +244,8 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
@Override
public void postLayout() {
- minWidthChecked = false;
VWindow window = getWidget();
- if (window.centered) {
+ if (window.centered && getState().windowMode != WindowMode.MAXIMIZED) {
window.center();
}
window.positionOrSizeUpdated();
@@ -304,6 +256,126 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector
return (WindowState) super.getState();
}
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ VWindow window = getWidget();
+ WindowState state = getState();
+
+ if (state.modal != window.vaadinModality) {
+ window.setVaadinModality(!window.vaadinModality);
+ }
+ if (!window.isAttached()) {
+ window.setVisible(false); // hide until possible centering
+ window.show();
+ }
+ boolean resizeable = state.resizable
+ && state.windowMode == WindowMode.NORMAL;
+ window.setResizable(resizeable);
+
+ window.resizeLazy = state.resizeLazy;
+
+ window.setDraggable(state.draggable
+ && state.windowMode == WindowMode.NORMAL);
+
+ window.updateMaximizeRestoreClassName(state.resizable, state.windowMode);
+
+ // Caption must be set before required header size is measured. If
+ // the caption attribute is missing the caption should be cleared.
+ String iconURL = null;
+ if (getIcon() != null) {
+ iconURL = getIcon();
+ }
+ window.setCaption(state.caption, iconURL);
+
+ clickEventHandler.handleEventHandlerRegistration();
+
+ window.immediate = state.immediate;
+
+ window.setClosable(!isReadOnly());
+ // initialize position from state
+ updateWindowPosition();
+
+ // setting scrollposition must happen after children is rendered
+ window.contentPanel.setScrollPosition(state.scrollTop);
+ window.contentPanel.setHorizontalScrollPosition(state.scrollLeft);
+
+ // Center this window on screen if requested
+ // This had to be here because we might not know the content size before
+ // everything is painted into the window
+
+ // centered is this is unset on move/resize
+ window.centered = state.centered;
+ window.setVisible(true);
+
+ // ensure window is not larger than browser window
+ if (window.getOffsetWidth() > Window.getClientWidth()) {
+ window.setWidth(Window.getClientWidth() + "px");
+ }
+ if (window.getOffsetHeight() > Window.getClientHeight()) {
+ window.setHeight(Window.getClientHeight() + "px");
+ }
+ }
+
+ // Need to override default because of window mode
+ @Override
+ protected void updateComponentSize() {
+ if (getState().windowMode == WindowMode.NORMAL) {
+ super.updateComponentSize();
+ } else if (getState().windowMode == WindowMode.MAXIMIZED) {
+ super.updateComponentSize("100%", "100%");
+ }
+ }
+
+ protected void updateWindowPosition() {
+ VWindow window = getWidget();
+ WindowState state = getState();
+ if (state.windowMode == WindowMode.NORMAL) {
+ // if centered, position handled in postLayout()
+ if (!state.centered
+ && (state.positionX >= 0 || state.positionY >= 0)) {
+ // If both positions are negative, then
+ // setWindowOrderAndPosition has already taken care of
+ // positioning the window so it stacks with other windows
+ window.setPopupPosition(state.positionX, state.positionY);
+ }
+ } else if (state.windowMode == WindowMode.MAXIMIZED) {
+ window.setPopupPositionNoUpdate(0, 0);
+ window.bringToFront();
+ }
+ }
+
+ protected void updateWindowMode() {
+ VWindow window = getWidget();
+ WindowState state = getState();
+
+ // update draggable on widget
+ window.setDraggable(state.draggable
+ && state.windowMode == WindowMode.NORMAL);
+ // update resizable on widget
+ window.setResizable(state.resizable
+ && state.windowMode == WindowMode.NORMAL);
+ updateComponentSize();
+ updateWindowPosition();
+ window.updateMaximizeRestoreClassName(state.resizable, state.windowMode);
+ window.updateContentsSize();
+ }
+
+ protected void onMaximizeRestore() {
+ WindowState state = getState();
+ if (state.resizable) {
+ if (state.windowMode == WindowMode.MAXIMIZED) {
+ state.windowMode = WindowMode.NORMAL;
+ } else {
+ state.windowMode = WindowMode.MAXIMIZED;
+ }
+ updateWindowMode();
+ getRpcProxy(WindowServerRpc.class).windowModeChanged(
+ state.windowMode);
+ }
+ }
+
/**
* Gives the WindowConnector an order number. As a side effect, moves the
* window according to its order number so the windows are stacked. This
diff --git a/common.xml b/common.xml
index 5b464e5047..d673273a53 100644
--- a/common.xml
+++ b/common.xml
@@ -6,9 +6,10 @@
</tstamp>
<dirname property="vaadin.basedir" file="${ant.file.common}" />
+ <property name="gwt.basedir" location="${vaadin.basedir}/../gwt" />
<property file="${vaadin.basedir}/build.properties" />
- <property name="modules.to.publish.to.maven" value="shared,server,client,client-compiler,client-compiled,theme-compiler,themes" />
+ <property name="modules.to.publish.to.maven" value="shared,server,client,client-compiler,client-compiled,theme-compiler,themes,push" />
<property name="modules.to.publish.to.download" value="${modules.to.publish.to.maven},all" />
<ivy:settings file="${vaadin.basedir}/ivysettings.xml" />
@@ -292,25 +293,25 @@
<mkdir dir="${classes}" />
</target>
- <target name="tests.run" depends="tests.compile">
+ <target name="test.run" depends="test.compile">
<fail unless="module.name" message="No module name given" />
<property name="result.dir" location="result" />
<property name="classes" location="${result.dir}/classes" />
- <property name="tests.src" location="${result.dir}/../tests/src" />
- <property name="tests.classes" location="${result.dir}/tests/classes" />
+ <property name="test.src" location="${result.dir}/../tests/src" />
+ <property name="test.classes" location="${result.dir}/tests/classes" />
<junit printsummary="withOutAndErr" fork="yes">
<formatter usefile="false" type="plain" />
<jvmarg value="-ea" />
- <classpath location="${tests.classes}" />
+ <classpath location="${test.classes}" />
<classpath location="${classes}" />
<classpath refid="classpath.compile.custom" />
- <classpath refid="classpath.tests.dependencies" />
+ <classpath refid="classpath.test.dependencies" />
<batchtest fork="yes">
- <fileset dir="${tests.src}">
+ <fileset dir="${test.src}">
<exclude name="**/Abstract*" />
<exclude name="com/vaadin/tests/data/bean/*" />
<exclude name="com/vaadin/tests/util/*" />
@@ -322,26 +323,26 @@
</junit>
</target>
- <target name="tests.compile" description="Compiles tests" depends="compile, dependencies.tests">
+ <target name="test.compile" description="Compiles tests" depends="compile, dependencies.test">
<fail unless="module.name" message="No module name given" />
<property name="result.dir" location="result" />
<property name="base.dir" location="${result.dir}/.." />
- <property name="tests.src" location="${base.dir}/tests/src" />
- <property name="tests.resources" location="${base.dir}/tests/resources" />
- <property name="tests.classes" location="${result.dir}/tests/classes" />
+ <property name="test.src" location="${base.dir}/tests/src" />
+ <property name="test.resources" location="${base.dir}/tests/resources" />
+ <property name="test.classes" location="${result.dir}/tests/classes" />
<property name="classes" location="${result.dir}/classes" />
- <mkdir dir="${tests.classes}" />
+ <mkdir dir="${test.classes}" />
- <javac srcdir="${tests.src}" destdir="${tests.classes}" source="${vaadin.java.version}" target="${vaadin.java.version}" debug="true" encoding="UTF-8" includeantruntime="false">
- <classpath refid="classpath.tests.dependencies" />
+ <javac srcdir="${test.src}" destdir="${test.classes}" source="${vaadin.java.version}" target="${vaadin.java.version}" debug="true" encoding="UTF-8" includeantruntime="false">
+ <classpath refid="classpath.test.dependencies" />
<classpath location="${classes}" />
- <classpath refid="classpath.tests.custom" />
+ <classpath refid="classpath.test.custom" />
</javac>
<!-- Copy resources -->
- <copy todir="${tests.classes}" failonerror="false">
- <fileset dir="${tests.resources}" />
+ <copy todir="${test.classes}" failonerror="false">
+ <fileset dir="${test.resources}" />
</copy>
</target>
@@ -351,9 +352,9 @@
<ivy:cachepath pathid="classpath.compile.dependencies" conf="${conf}" />
</target>
- <target name="dependencies.tests" description="Resolves dependencies needed by tests">
- <ivy:resolve resolveid="common" conf="tests" />
- <ivy:cachepath pathid="classpath.tests.dependencies" conf="tests" />
+ <target name="dependencies.test" description="Resolves dependencies needed by test">
+ <ivy:resolve resolveid="common" conf="test" />
+ <ivy:cachepath pathid="classpath.test.dependencies" conf="test" />
</target>
<target name="clean">
diff --git a/eclipse/Development Mode (vaadin).launch b/eclipse/Development Mode (vaadin).launch
new file mode 100644
index 0000000000..483ce58233
--- /dev/null
+++ b/eclipse/Development Mode (vaadin).launch
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<stringAttribute key="bad_container_name" value="\eclipse"/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/gwt-dev/core/src/com/google/gwt/dev/DevMode.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;vaadin&quot; type=&quot;1&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/shared/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/client/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/vaadin/uitest/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;gwt-dev&quot; type=&quot;1&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry path=&quot;3&quot; projectName=&quot;gwt-user&quot; type=&quot;1&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;GWT_TOOLS/lib/apache/tapestry-util-text-4.0.2.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;GWT_TOOLS/lib/junit/junit-4.8.2.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;GWT_TOOLS/lib/tomcat/servlet-api-2.5.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;GWT_TOOLS/lib/javax/validation/validation-api-1.0.0.GA-sources.jar&quot; path=&quot;3&quot; type=&quot;3&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/gwt-dev/core/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/gwt-dev/core/super&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/gwt-user/core/src&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry internalArchive=&quot;/gwt-user/core/super&quot; path=&quot;3&quot; type=&quot;2&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;amp;ivyXmlPath=client%2Fivy.xml&amp;amp;confs=ide&amp;amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;amp;loadSettingsOnDemand=false&amp;amp;propertyFiles=&quot; javaProject=&quot;vaadin&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;amp;ivyXmlPath=server%2Fivy.xml&amp;amp;confs=ide&amp;amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;amp;loadSettingsOnDemand=false&amp;amp;propertyFiles=&quot; javaProject=&quot;vaadin&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;amp;ivyXmlPath=shared%2Fivy.xml&amp;amp;confs=ide&amp;amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;amp;loadSettingsOnDemand=false&amp;amp;propertyFiles=&quot; javaProject=&quot;vaadin&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;amp;ivyXmlPath=client-compiler%2Fivy.xml&amp;amp;confs=ide&amp;amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;amp;loadSettingsOnDemand=false&amp;amp;propertyFiles=&quot; javaProject=&quot;vaadin&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;amp;ivyXmlPath=theme-compiler%2Fivy.xml&amp;amp;confs=ide&amp;amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;amp;loadSettingsOnDemand=false&amp;amp;propertyFiles=&quot; javaProject=&quot;vaadin&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
+<listEntry value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.apache.ivyde.eclipse.cpcontainer.IVYDE_CONTAINER/?project=vaadin&amp;amp;ivyXmlPath=uitest%2Fivy.xml&amp;amp;confs=ide&amp;amp;ivySettingsPath=%24%7Bworkspace_loc%3Avaadin%2Fivysettings.xml%7D&amp;amp;loadSettingsOnDemand=false&amp;amp;propertyFiles=&quot; javaProject=&quot;vaadin&quot; path=&quot;3&quot; type=&quot;4&quot;/&gt;&#13;&#10;"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.google.gwt.dev.DevMode"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-noserver -war WebContent/VAADIN/widgetsets com.vaadin.terminal.gwt.DefaultWidgetSet -startupUrl http://localhost:8888 -bindAddress 0.0.0.0"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="vaadin"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xmx512M -XX:MaxPermSize=256M"/>
+</launchConfiguration>
diff --git a/eclipse/Development Server (vaadin).launch b/eclipse/Development Server (vaadin).launch
new file mode 100644
index 0000000000..8f57c441ec
--- /dev/null
+++ b/eclipse/Development Server (vaadin).launch
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/vaadin/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="1"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="com.vaadin.launcher.DevelopmentServerLauncher"/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="vaadin"/>
+<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea"/>
+</launchConfiguration>
diff --git a/gwt-files.xml b/gwt-files.xml
index 69e6c04e70..cc4b4a1e96 100644
--- a/gwt-files.xml
+++ b/gwt-files.xml
@@ -3,7 +3,8 @@
<project name="GWT files for Vaadin" basedir=".">
<include file="common.xml" as="common" />
- <property name="gwt.lib.dir" location="${vaadin.basedir}/../gwt-libs" />
+ <property name="gwt.lib.dir" location="${gwt.basedir}/build/lib" />
+ <property name="gwt.eclipse.basedir" location="${gwt.basedir}/eclipse" />
<property name="gwt.user.jar" location="${gwt.lib.dir}/gwt-user.jar" />
<property name="gwt.dev.jar" location="${gwt.lib.dir}/gwt-dev.jar" />
@@ -15,11 +16,6 @@
<available file="${gwt.elemental.jar}" property="gwt.elemental.jar.found" />
<available file="${gwt.codeserver.jar}" property="gwt.codeserver.jar.found" />
- <fail unless="gwt.dev.jar.found" message="Could not find gwt-dev.jar at ${gwt.dev.jar}" />
- <fail unless="gwt.user.jar.found" message="Could not find gwt-user.jar at ${gwt.user.jar}" />
- <fail unless="gwt.elemental.jar.found" message="Could not find gwt-elemental.jar at ${gwt.elemental.jar}" />
- <fail unless="gwt.codeserver.jar.found" message="Could not find gwt-codeserver.jar at ${gtw.codeserver.jar}" />
-
<property name="gwt.unpack.dir" location="${vaadin.basedir}/build/gwt" />
<property name="gwt.user.jar.files" location="${gwt.unpack.dir}/gwt-user.jar" />
@@ -28,6 +24,11 @@
<property name="gwt.codeserver.jar.files" location="${gwt.unpack.dir}/gwt-codeserver.jar" />
<target name="unpack.gwt">
+ <fail unless="gwt.dev.jar.found" message="Could not find gwt-dev.jar at ${gwt.dev.jar}" />
+ <fail unless="gwt.user.jar.found" message="Could not find gwt-user.jar at ${gwt.user.jar}" />
+ <fail unless="gwt.elemental.jar.found" message="Could not find gwt-elemental.jar at ${gwt.elemental.jar}" />
+ <fail unless="gwt.codeserver.jar.found" message="Could not find gwt-codeserver.jar at ${gwt.codeserver.jar}" />
+
<delete dir="${gwt.unpack.dir}" />
<mkdir dir="${gwt.user.jar.files}" />
@@ -57,17 +58,62 @@
<!-- cssparser -->
<exclude name="com/steadystate/css/**" />
<!-- Ant & AntLauncher -->
- <exclude name="org/apache/tools/**"/>
+ <exclude name="org/apache/tools/**" />
<!-- Jetty & jetty-util -->
- <exclude name="org/mortbay/**"/>
+ <exclude name="org/mortbay/**" />
<!-- Swing Worker-->
- <exclude name="org/jdesktop/swingworker/**"/>
- <!-- Apache commons codec & io & lang -->
- <exclude name="org/apache/commons/codec/**"/>
- <exclude name="org/apache/commons/io/**"/>
- <exclude name="org/apache/commons/lang/**"/>
+ <exclude name="org/jdesktop/swingworker/**" />
+ <!-- Apache commons codec & io & lang & collections & logging -->
+ <exclude name="org/apache/commons/codec/**" />
+ <exclude name="org/apache/commons/io/**" />
+ <exclude name="org/apache/commons/lang/**" />
+ <exclude name="org/apache/commons/collections/**" />
+ <exclude name="org/apache/commons/logging/**" />
<!-- apache mime4j -->
- <exclude name="org/apache/james/mime4j/**"/>
+ <exclude name="org/apache/james/mime4j/**" />
+
+ <!-- client-compiler-deps -->
+ <exclude name="com/gargoylesoftware/" />
+ <exclude name="com/google/common/" />
+ <exclude name="com/google/debugging/" />
+ <exclude name="com/google/gwt/dev/protobuf/" />
+ <exclude name="com/google/gwt/thirdparty/debugging/" />
+ <exclude name="com/google/gwt/thirdparty/javascript/" />
+ <exclude name="com/google/gwt/thirdparty/mozilla/" />
+ <exclude name="com/ibm/" />
+ <exclude name="externs.zip" />
+ <exclude name="java_cup/" />
+ <exclude name="javax/annotation/" />
+ <exclude name="net/sourceforge/htmlunit/" />
+ <exclude name="org/apache/bcel/" />
+ <exclude name="org/apache/html/" />
+ <exclude name="org/apache/http/" />
+ <exclude name="org/apache/NOTICE" />
+ <exclude name="org/apache/regexp/" />
+ <exclude name="org/apache/tapestry/" />
+ <exclude name="org/apache/wml/" />
+ <exclude name="org/apache/xalan/" />
+ <exclude name="org/apache/xerces/" />
+ <exclude name="org/apache/xml/" />
+ <exclude name="org/apache/xmlcommons/" />
+ <exclude name="org/apache/xpath/" />
+ <exclude name="org/cyberneko/" />
+ <exclude name="org/eclipse/" />
+ <exclude name="org/kohsuke/" />
+ <exclude name="org/w3c/" />
+ <exclude name="org/xml/" />
+ <exclude name="rhino_ast/" />
+ <exclude name="rhinoDiff.txt" />
+ <exclude name="trax/" />
+ <exclude name="unicode-license.txt" />
+ <exclude name="org/json" />
+
+ <exclude name="license/NOTICE" />
+ <exclude name="license/LICENSE.dom-documentation.txt" />
+ <exclude name="license/LICENSE.dom-software.txt" />
+ <exclude name="license/LICENSE" />
+ <exclude name="license/README.dom.txt" />
+ <exclude name="license/README.sax.txt" />
<!-- Overridden in Vaadin -->
<exclude name="com/google/gwt/dev/About.properties" />
@@ -105,7 +151,7 @@
<exclude name="com/google/gwt/*/shared/**" />
<exclude name="com/google/gwt/*/*/shared/**" />
<exclude name="com/google/web/bindery/*/shared/**" />
-
+
<!-- Used by the server, in wrong package in GWT -->
<exclude name="com/google/gwt/user/client/rpc/IsSerializable.*" />
diff --git a/ivy.xml b/ivy.xml
deleted file mode 100644
index f2179255d4..0000000000
--- a/ivy.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE ivy-module [
- <!ENTITY server SYSTEM "server/ivy.xml">
- <!ENTITY client SYSTEM "client/ivy.xml">
- <!ENTITY clientCompiler SYSTEM "client-compiler/ivy.xml">
- <!ENTITY shared SYSTEM "shared/ivy.xml">
- <!ENTITY uitest SYSTEM "uitest/ivy.xml">
- <!ENTITY themeCompiler SYSTEM "theme-compiler/ivy.xml">
-]>
-<ivy-module version="2.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"
- xmlns:m="http://ant.apache.org/ivy/maven">
-
- &server;
- &client;
- &clientCompiler;
- &shared;
- &uitest;
- &themeCompiler;
-
-</ivy-module> \ No newline at end of file
diff --git a/ivysettings.xml b/ivysettings.xml
index e1e2e45b3d..288eae9036 100644
--- a/ivysettings.xml
+++ b/ivysettings.xml
@@ -17,7 +17,7 @@
</filesystem>
<dual name="custom-smartsprites">
<filesystem name="smartsprites-ivy">
- <ivy pattern="${basedir}/ivymodule/[module]-ivy-[revision].xml" />
+ <ivy pattern="${ivy.settings.dir}/theme-compiler/ivymodule/[module]-ivy-[revision].xml" />
</filesystem>
<url name="smartsprites-artifact">
<artifact
@@ -51,6 +51,8 @@
resolver="build-temp" />
<module organisation="com.vaadin" name="vaadin-themes"
resolver="build-temp" />
+ <module organisation="com.vaadin" name="vaadin-push"
+ resolver="build-temp" />
</modules>
diff --git a/push/build.xml b/push/build.xml
new file mode 100644
index 0000000000..95284e6e37
--- /dev/null
+++ b/push/build.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0"?>
+
+<project name="vaadin-push" basedir="." default="publish-local" xmlns:ivy="antlib:org.apache.ivy.ant">
+ <description>
+ Meta package which defines dependencies needed for push
+ </description>
+ <include file="../build.xml" as="vaadin" />
+ <include file="../common.xml" as="common" />
+
+ <property name="module.name" value="vaadin-push" />
+ <property name="module.symbolic" value="com.vaadin.push" />
+ <property name="result.dir" location="result" />
+ <property name="vaadinPush.js" location="${result.dir}/js/VAADIN/vaadinPush.js" />
+ <path id="classpath.compile.custom" />
+
+ <union id="jar.includes">
+ <fileset dir="${result.dir}/js">
+ <include name="VAADIN/vaadinPush.js" />
+ </fileset>
+ </union>
+
+ <target name="vaadinPush.js">
+ <mkdir dir="${result.dir}/js/VAADIN" />
+ <property name="vaadinPush.js.output" location="${result.dir}/js/VAADIN/vaadinPush.js" />
+ <property name="vaadinPush.js.combined.output" location="${result.dir}/js/VAADIN/push.combined.js" />
+
+ <loadfile srcfile="${vaadin.basedir}/WebContent/VAADIN/jquery-1.7.2.js" property="jquery.js.contents" />
+ <loadfile srcfile="${vaadin.basedir}/WebContent/VAADIN/jquery.atmosphere.js" property="jquery.atmosphere.js.contents" />
+ <loadfile srcfile="${vaadin.basedir}/WebContent/VAADIN/vaadinPush.js.tpl" property="vaadinPush.js.contents">
+ <filterchain>
+ <replacetokens begintoken="@" endtoken="@">
+ <token key="jquery.js" value="${jquery.js.contents}" />
+ <token key="jquery.atmosphere.js" value="${jquery.atmosphere.js.contents}" />
+ </replacetokens>
+ </filterchain>
+ </loadfile>
+ <echo file="${vaadinPush.js.combined.output}">${vaadinPush.js.contents}</echo>
+
+ <!-- Minify -->
+ <ivy:retrieve organisation="com.yahoo.platform.yui" module="yuicompressor" revision="2.4.7" inline="true" type="jar" pattern="${result.dir}/compressor.jar" />
+ <java jar="${result.dir}/compressor.jar" fork="true">
+ <arg value="-v"/>
+ <arg value="-o"/>
+ <arg file="${vaadinPush.js.output}"/>
+ <arg file="${vaadinPush.js.combined.output}"/>
+ </java>
+ </target>
+
+ <target name="jar" depends="vaadinPush.js">
+ <property name="server.osgi.import" value="" />
+ <antcall target="common.jar">
+ <param name="require-bundle" value="" />
+ <param name="import-package" value="${server.osgi.import}" />
+ <reference torefid="extra.jar.includes" refid="jar.includes" />
+ </antcall>
+ </target>
+
+ <target name="publish-local" depends="jar">
+ <antcall target="common.sources.jar">
+ <reference torefid="extra.jar.includes" refid="jar.includes" />
+ </antcall>
+ <antcall target="common.javadoc.jar" />
+ <antcall target="common.publish-local" />
+ </target>
+
+ <target name="clean">
+ <antcall target="common.clean" />
+ </target>
+ <target name="checkstyle">
+ </target>
+
+ <target name="test" depends="checkstyle">
+ </target>
+</project> \ No newline at end of file
diff --git a/push/ivy.xml b/push/ivy.xml
new file mode 100644
index 0000000000..153c02e256
--- /dev/null
+++ b/push/ivy.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ivy-module version="2.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd"
+ xmlns:m="http://ant.apache.org/ivy/maven">
+
+ <info organisation="com.vaadin" module="vaadin-push"
+ revision="${vaadin.version}" />
+
+ <configurations>
+ <conf name="build" />
+ <conf name="build-provided" />
+ <conf name="ide" visibility="private" />
+ <conf name="test" visibility="private" />
+ </configurations>
+ <publications>
+ <artifact type="jar" ext="jar" />
+ <artifact type="source" ext="jar" m:classifier="sources" />
+ <artifact type="javadoc" ext="jar" m:classifier="javadoc" />
+ <artifact type="pom" ext="pom" />
+ </publications>
+ <dependencies>
+
+
+ <!-- API DEPENDENCIES -->
+
+ <!--Servlet API version 2.4 -->
+ <dependency org="javax.servlet" name="servlet-api"
+ rev="2.4" conf="build-provided,ide,test -> default" />
+
+ <!-- Atmosphere -->
+ <dependency org="org.atmosphere" name="atmosphere-runtime" rev="1.0.12"
+ conf="build,ide,test -> default">
+ </dependency>
+ </dependencies>
+
+</ivy-module>
diff --git a/push/src/org/atmosphere/cpr/AtmosphereFramework.java b/push/src/org/atmosphere/cpr/AtmosphereFramework.java
new file mode 100644
index 0000000000..62f867fc94
--- /dev/null
+++ b/push/src/org/atmosphere/cpr/AtmosphereFramework.java
@@ -0,0 +1,1779 @@
+/*
+ * Copyright 2013 Jeanfrancois Arcand
+ *
+ * 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 org.atmosphere.cpr;
+
+import org.atmosphere.cache.UUIDBroadcasterCache;
+import org.atmosphere.config.ApplicationConfiguration;
+import org.atmosphere.config.AtmosphereHandlerConfig;
+import org.atmosphere.config.AtmosphereHandlerProperty;
+import org.atmosphere.config.FrameworkConfiguration;
+import org.atmosphere.container.BlockingIOCometSupport;
+import org.atmosphere.container.Tomcat7BIOSupportWithWebSocket;
+import org.atmosphere.di.InjectorProvider;
+import org.atmosphere.di.ServletContextHolder;
+import org.atmosphere.di.ServletContextProvider;
+import org.atmosphere.handler.AbstractReflectorAtmosphereHandler;
+import org.atmosphere.handler.ReflectorServletProcessor;
+import org.atmosphere.interceptor.AndroidAtmosphereInterceptor;
+import org.atmosphere.interceptor.JSONPAtmosphereInterceptor;
+import org.atmosphere.interceptor.JavaScriptProtocol;
+import org.atmosphere.interceptor.OnDisconnectInterceptor;
+import org.atmosphere.interceptor.SSEAtmosphereInterceptor;
+import org.atmosphere.util.AtmosphereConfigReader;
+import org.atmosphere.util.IntrospectionUtils;
+import org.atmosphere.util.Version;
+import org.atmosphere.websocket.DefaultWebSocketProcessor;
+import org.atmosphere.websocket.WebSocket;
+import org.atmosphere.websocket.WebSocketProtocol;
+import org.atmosphere.websocket.protocol.SimpleHttpProtocol;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import static org.atmosphere.cpr.ApplicationConfig.ALLOW_QUERYSTRING_AS_REQUEST;
+import static org.atmosphere.cpr.ApplicationConfig.ATMOSPHERE_HANDLER;
+import static org.atmosphere.cpr.ApplicationConfig.ATMOSPHERE_HANDLER_MAPPING;
+import static org.atmosphere.cpr.ApplicationConfig.ATMOSPHERE_HANDLER_PATH;
+import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_CACHE;
+import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_CLASS;
+import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_FACTORY;
+import static org.atmosphere.cpr.ApplicationConfig.BROADCASTER_LIFECYCLE_POLICY;
+import static org.atmosphere.cpr.ApplicationConfig.BROADCAST_FILTER_CLASSES;
+import static org.atmosphere.cpr.ApplicationConfig.DISABLE_ONSTATE_EVENT;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_ATMOSPHERE_XML;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_BLOCKING_COMETSUPPORT;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_COMET_SUPPORT;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_NATIVE_COMETSUPPORT;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_SERVLET_MAPPING;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_SESSION_SUPPORT;
+import static org.atmosphere.cpr.ApplicationConfig.PROPERTY_USE_STREAM;
+import static org.atmosphere.cpr.ApplicationConfig.RESUME_AND_KEEPALIVE;
+import static org.atmosphere.cpr.ApplicationConfig.SUSPENDED_ATMOSPHERE_RESOURCE_UUID;
+import static org.atmosphere.cpr.ApplicationConfig.WEBSOCKET_PROCESSOR;
+import static org.atmosphere.cpr.ApplicationConfig.WEBSOCKET_PROTOCOL;
+import static org.atmosphere.cpr.ApplicationConfig.WEBSOCKET_SUPPORT;
+import static org.atmosphere.cpr.FrameworkConfig.ATMOSPHERE_CONFIG;
+import static org.atmosphere.cpr.FrameworkConfig.HAZELCAST_BROADCASTER;
+import static org.atmosphere.cpr.FrameworkConfig.JERSEY_BROADCASTER;
+import static org.atmosphere.cpr.FrameworkConfig.JERSEY_CONTAINER;
+import static org.atmosphere.cpr.FrameworkConfig.JGROUPS_BROADCASTER;
+import static org.atmosphere.cpr.FrameworkConfig.JMS_BROADCASTER;
+import static org.atmosphere.cpr.FrameworkConfig.REDIS_BROADCASTER;
+import static org.atmosphere.cpr.FrameworkConfig.WRITE_HEADERS;
+import static org.atmosphere.cpr.FrameworkConfig.XMPP_BROADCASTER;
+import static org.atmosphere.cpr.HeaderConfig.ATMOSPHERE_POST_BODY;
+import static org.atmosphere.cpr.HeaderConfig.X_ATMOSPHERE_TRACKING_ID;
+import static org.atmosphere.websocket.WebSocket.WEBSOCKET_SUSPEND;
+
+/**
+ * The {@link AtmosphereFramework} is the entry point for the framework. This class can be used to from Servlet/filter
+ * to dispatch {@link AtmosphereRequest} and {@link AtmosphereResponse}. The framework can also be configured using
+ * the setXXX method. The life cycle of this class is
+ * <blockquote><pre>
+ * AtmosphereFramework f = new AtmosphereFramework();
+ * f.init();
+ * f.doCometSupport(AtmosphereRequest, AtmosphereResource);
+ * f.destroy();
+ * </pre></blockquote>
+ *
+ * @author Jeanfrancois Arcand
+ */
+public class AtmosphereFramework implements ServletContextProvider {
+ public static final String DEFAULT_ATMOSPHERE_CONFIG_PATH = "/META-INF/atmosphere.xml";
+ public static final String DEFAULT_LIB_PATH = "/WEB-INF/lib/";
+ public static final String MAPPING_REGEX = "[a-zA-Z0-9-&.*=@~;\\?]+";
+
+ protected static final Logger logger = LoggerFactory.getLogger(AtmosphereFramework.class);
+
+ protected final List<String> broadcasterFilters = new ArrayList<String>();
+ protected final List<AsyncSupportListener> asyncSupportListeners = new ArrayList<AsyncSupportListener>();
+ protected final ArrayList<String> possibleComponentsCandidate = new ArrayList<String>();
+ protected final HashMap<String, String> initParams = new HashMap<String, String>();
+ protected final AtmosphereConfig config;
+ protected final AtomicBoolean isCometSupportConfigured = new AtomicBoolean(false);
+ protected final boolean isFilter;
+ protected final Map<String, AtmosphereHandlerWrapper> atmosphereHandlers = new ConcurrentHashMap<String, AtmosphereHandlerWrapper>();
+ protected final ConcurrentLinkedQueue<String> broadcasterTypes = new ConcurrentLinkedQueue<String>();
+
+ protected boolean useNativeImplementation = false;
+ protected boolean useBlockingImplementation = false;
+ protected boolean useStreamForFlushingComments = false;
+ protected AsyncSupport asyncSupport;
+ protected String broadcasterClassName = DefaultBroadcaster.class.getName();
+ protected boolean isCometSupportSpecified = false;
+ protected boolean isBroadcasterSpecified = false;
+ protected boolean isSessionSupportSpecified = false;
+ protected BroadcasterFactory broadcasterFactory;
+ protected String broadcasterFactoryClassName;
+ protected String broadcasterCacheClassName;
+ protected boolean webSocketEnabled = true;
+ protected String broadcasterLifeCyclePolicy = "NEVER";
+ protected String webSocketProtocolClassName = SimpleHttpProtocol.class.getName();
+ protected WebSocketProtocol webSocketProtocol;
+ protected String handlersPath = "/WEB-INF/classes/";
+ protected ServletConfig servletConfig;
+ protected boolean autoDetectHandlers = true;
+ private boolean hasNewWebSocketProtocol = false;
+ protected String atmosphereDotXmlPath = DEFAULT_ATMOSPHERE_CONFIG_PATH;
+ protected final LinkedList<AtmosphereInterceptor> interceptors = new LinkedList<AtmosphereInterceptor>();
+ protected boolean scanDone = false;
+ protected String annotationProcessorClassName = "org.atmosphere.cpr.DefaultAnnotationProcessor";
+ protected final List<BroadcasterListener> broadcasterListeners = new ArrayList<BroadcasterListener>();
+ protected String webSocketProcessorClassName = DefaultWebSocketProcessor.class.getName();
+ protected String libPath = DEFAULT_LIB_PATH;
+ protected boolean isInit;
+ protected boolean sharedThreadPools = true;
+
+ public static final class AtmosphereHandlerWrapper {
+
+ public final AtmosphereHandler atmosphereHandler;
+ public Broadcaster broadcaster;
+ public String mapping;
+ public List<AtmosphereInterceptor> interceptors = Collections.<AtmosphereInterceptor>emptyList();
+
+ public AtmosphereHandlerWrapper(BroadcasterFactory broadcasterFactory, AtmosphereHandler atmosphereHandler, String mapping) {
+ this.atmosphereHandler = atmosphereHandler;
+ try {
+ if (broadcasterFactory != null) {
+ this.broadcaster = broadcasterFactory.lookup(mapping, true);
+ } else {
+ this.mapping = mapping;
+ }
+ } catch (Exception t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ public AtmosphereHandlerWrapper(AtmosphereHandler atmosphereHandler, Broadcaster broadcaster) {
+ this.atmosphereHandler = atmosphereHandler;
+ this.broadcaster = broadcaster;
+ }
+
+ @Override
+ public String toString() {
+ return "AtmosphereHandlerWrapper{ atmosphereHandler=" + atmosphereHandler + ", broadcaster=" +
+ broadcaster + " }";
+ }
+ }
+
+ /**
+ * Create an AtmosphereFramework.
+ */
+ public AtmosphereFramework() {
+ this(false, true);
+ }
+
+ /**
+ * Create an AtmosphereFramework and initialize it via {@link AtmosphereFramework#init(javax.servlet.ServletConfig)}
+ */
+ public AtmosphereFramework(ServletConfig sc) throws ServletException {
+ this(false, true);
+ init(sc);
+ }
+
+ /**
+ * Create an AtmosphereFramework.
+ *
+ * @param isFilter true if this instance is used as an {@link AtmosphereFilter}
+ */
+ public AtmosphereFramework(boolean isFilter, boolean autoDetectHandlers) {
+ this.isFilter = isFilter;
+ this.autoDetectHandlers = autoDetectHandlers;
+ readSystemProperties();
+ populateBroadcasterType();
+ config = new AtmosphereConfig(this);
+ }
+
+ /**
+ * The order of addition is quite important here.
+ */
+ private void populateBroadcasterType() {
+ broadcasterTypes.add(HAZELCAST_BROADCASTER);
+ broadcasterTypes.add(XMPP_BROADCASTER);
+ broadcasterTypes.add(REDIS_BROADCASTER);
+ broadcasterTypes.add(JGROUPS_BROADCASTER);
+ broadcasterTypes.add(JMS_BROADCASTER);
+ }
+
+ /**
+ * Add an {@link AtmosphereHandler} serviced by the {@link Servlet}
+ * This API is exposed to allow embedding an Atmosphere application.
+ *
+ * @param mapping The servlet mapping (servlet path)
+ * @param h implementation of an {@link AtmosphereHandler}
+ * @param l An attay of {@link AtmosphereInterceptor}
+ */
+ public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, List<AtmosphereInterceptor> l) {
+ if (!mapping.startsWith("/")) {
+ mapping = "/" + mapping;
+ }
+
+ AtmosphereHandlerWrapper w = new AtmosphereHandlerWrapper(broadcasterFactory, h, mapping);
+ w.interceptors = l;
+ addMapping(mapping, w);
+
+ logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", h.getClass().getName(), mapping);
+ if (l.size() > 0) {
+ logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, h.getClass().getName());
+ }
+ return this;
+ }
+
+ /**
+ * Add an {@link AtmosphereHandler} serviced by the {@link Servlet}
+ * This API is exposed to allow embedding an Atmosphere application.
+ *
+ * @param mapping The servlet mapping (servlet path)
+ * @param h implementation of an {@link AtmosphereHandler}
+ */
+ public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h) {
+ addAtmosphereHandler(mapping, h, Collections.<AtmosphereInterceptor>emptyList());
+ return this;
+ }
+
+ private AtmosphereFramework addMapping(String path, AtmosphereHandlerWrapper w) {
+ // We are using JAXRS mapping algorithm.
+ if (path.contains("*")) {
+ path = path.replace("*", MAPPING_REGEX);
+ }
+
+ if (path.endsWith("/")) {
+ path = path + MAPPING_REGEX;
+ }
+
+ InjectorProvider.getInjector().inject(w.atmosphereHandler);
+ atmosphereHandlers.put(path, w);
+ return this;
+ }
+
+ /**
+ * Add an {@link AtmosphereHandler} serviced by the {@link Servlet}
+ * This API is exposed to allow embedding an Atmosphere application.
+ *
+ * @param mapping The servlet mapping (servlet path)
+ * @param h implementation of an {@link AtmosphereHandler}
+ * @param broadcasterId The {@link Broadcaster#getID} value.
+ * @param l An attay of {@link AtmosphereInterceptor}
+ */
+ public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, String broadcasterId, List<AtmosphereInterceptor> l) {
+ if (!mapping.startsWith("/")) {
+ mapping = "/" + mapping;
+ }
+
+ AtmosphereHandlerWrapper w = new AtmosphereHandlerWrapper(broadcasterFactory, h, mapping);
+ w.broadcaster.setID(broadcasterId);
+ w.interceptors = l;
+ addMapping(mapping, w);
+ logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", h.getClass().getName(), mapping);
+ if (l.size() > 0) {
+ logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, h.getClass().getName());
+ }
+ return this;
+ }
+
+ /**
+ * Add an {@link AtmosphereHandler} serviced by the {@link Servlet}
+ * This API is exposed to allow embedding an Atmosphere application.
+ *
+ * @param mapping The servlet mapping (servlet path)
+ * @param h implementation of an {@link AtmosphereHandler}
+ * @param broadcasterId The {@link Broadcaster#getID} value.
+ */
+ public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, String broadcasterId) {
+ addAtmosphereHandler(mapping, h, broadcasterId, Collections.<AtmosphereInterceptor>emptyList());
+ return this;
+ }
+
+ /**
+ * Add an {@link AtmosphereHandler} serviced by the {@link Servlet}
+ * This API is exposed to allow embedding an Atmosphere application.
+ *
+ * @param mapping The servlet mapping (servlet path)
+ * @param h implementation of an {@link AtmosphereHandler}
+ * @param broadcaster The {@link Broadcaster} associated with AtmosphereHandler.
+ * @param l An attay of {@link AtmosphereInterceptor}
+ */
+ public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, Broadcaster broadcaster, List<AtmosphereInterceptor> l) {
+ if (!mapping.startsWith("/")) {
+ mapping = "/" + mapping;
+ }
+
+ AtmosphereHandlerWrapper w = new AtmosphereHandlerWrapper(h, broadcaster);
+ w.interceptors = l;
+
+ addMapping(mapping, w);
+ logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", h.getClass().getName(), mapping);
+ if (l.size() > 0) {
+ logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, h.getClass().getName());
+ }
+ return this;
+ }
+
+ /**
+ * Add an {@link AtmosphereHandler} serviced by the {@link Servlet}
+ * This API is exposed to allow embedding an Atmosphere application.
+ *
+ * @param mapping The servlet mapping (servlet path)
+ * @param h implementation of an {@link AtmosphereHandler}
+ * @param broadcaster The {@link Broadcaster} associated with AtmosphereHandler.
+ */
+ public AtmosphereFramework addAtmosphereHandler(String mapping, AtmosphereHandler h, Broadcaster broadcaster) {
+ addAtmosphereHandler(mapping, h, broadcaster, Collections.<AtmosphereInterceptor>emptyList());
+ return this;
+ }
+
+ /**
+ * Remove an {@link AtmosphereHandler}
+ *
+ * @param mapping the mapping used when invoking {@link #addAtmosphereHandler(String, AtmosphereHandler)};
+ * @return true if removed
+ */
+ public AtmosphereFramework removeAtmosphereHandler(String mapping) {
+
+ if (mapping.endsWith("/")) {
+ mapping += MAPPING_REGEX;
+ }
+
+ atmosphereHandlers.remove(mapping);
+ return this;
+ }
+
+ /**
+ * Remove all {@link AtmosphereHandler}
+ */
+ public AtmosphereFramework removeAllAtmosphereHandler() {
+ atmosphereHandlers.clear();
+ return this;
+ }
+
+ /**
+ * Remove all init parameters.
+ */
+ public AtmosphereFramework removeAllInitParams() {
+ initParams.clear();
+ return this;
+ }
+
+ /**
+ * Add init-param like if they were defined in web.xml
+ *
+ * @param name The name
+ * @param value The value
+ */
+ public AtmosphereFramework addInitParameter(String name, String value) {
+ initParams.put(name, value);
+ return this;
+ }
+
+ protected void readSystemProperties() {
+ if (System.getProperty(PROPERTY_NATIVE_COMETSUPPORT) != null) {
+ useNativeImplementation = Boolean
+ .parseBoolean(System.getProperty(PROPERTY_NATIVE_COMETSUPPORT));
+ isCometSupportSpecified = true;
+ }
+
+ if (System.getProperty(PROPERTY_BLOCKING_COMETSUPPORT) != null) {
+ useBlockingImplementation = Boolean
+ .parseBoolean(System.getProperty(PROPERTY_BLOCKING_COMETSUPPORT));
+ isCometSupportSpecified = true;
+ }
+ atmosphereDotXmlPath = System.getProperty(PROPERTY_ATMOSPHERE_XML, atmosphereDotXmlPath);
+
+ if (System.getProperty(DISABLE_ONSTATE_EVENT) != null) {
+ initParams.put(DISABLE_ONSTATE_EVENT, System.getProperty(DISABLE_ONSTATE_EVENT));
+ }
+ }
+
+ /**
+ * Path specific container using their own property.
+ */
+ public void patchContainer() {
+ System.setProperty("org.apache.catalina.STRICT_SERVLET_COMPLIANCE", "false");
+ }
+
+ /**
+ * Initialize the AtmosphereFramework. Invoke that method after having properly configured this class using the setter.
+ */
+ public AtmosphereFramework init() {
+ try {
+ init(new ServletConfig() {
+
+ @Override
+ public String getServletName() {
+ return "AtmosphereFramework";
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return (ServletContext) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{ServletContext.class},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ logger.trace("Method {} not supported", method.getName());
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public String getInitParameter(String name) {
+ return initParams.get(name);
+ }
+
+ @Override
+ public Enumeration<String> getInitParameterNames() {
+ return Collections.enumeration(initParams.values());
+ }
+ });
+ } catch (ServletException e) {
+ logger.error("", e);
+ }
+ return this;
+ }
+
+ /**
+ * Initialize the AtmosphereFramework using the {@link ServletContext}
+ *
+ * @param sc the {@link ServletContext}
+ */
+ public AtmosphereFramework init(final ServletConfig sc) throws ServletException {
+
+ if (isInit) return this;
+
+ try {
+ ServletContextHolder.register(this);
+
+ ServletConfig scFacade = new ServletConfig() {
+
+ public String getServletName() {
+ return sc.getServletName();
+ }
+
+ public ServletContext getServletContext() {
+ return sc.getServletContext();
+ }
+
+ public String getInitParameter(String name) {
+ String param = initParams.get(name);
+ if (param == null) {
+ return sc.getInitParameter(name);
+ }
+ return param;
+ }
+
+ public Enumeration<String> getInitParameterNames() {
+ Enumeration en = sc.getInitParameterNames();
+ while (en.hasMoreElements()) {
+ String name = (String) en.nextElement();
+ if (!initParams.containsKey(name)) {
+ initParams.put(name, sc.getInitParameter(name));
+ }
+ }
+ return Collections.enumeration(initParams.keySet());
+ }
+ };
+ this.servletConfig = scFacade;
+ asyncSupportListener(new AsyncSupportListenerAdapter());
+
+ autoConfigureService(scFacade.getServletContext());
+ patchContainer();
+ doInitParams(scFacade);
+ doInitParamsForWebSocket(scFacade);
+ configureBroadcaster();
+ loadConfiguration(scFacade);
+ initWebSocket();
+
+ autoDetectContainer();
+ configureWebDotXmlAtmosphereHandler(sc);
+ asyncSupport.init(scFacade);
+ initAtmosphereHandler(scFacade);
+ configureAtmosphereInterceptor(sc);
+
+ if (broadcasterCacheClassName == null) {
+ logger.warn("No BroadcasterCache configured. Broadcasted message between client reconnection will be LOST. " +
+ "It is recommended to configure the {}", UUIDBroadcasterCache.class.getName());
+ } else {
+ logger.info("Using BroadcasterCache: {}", broadcasterCacheClassName);
+ }
+
+ // http://java.net/jira/browse/ATMOSPHERE-157
+ if (sc.getServletContext() != null) {
+ sc.getServletContext().setAttribute(BroadcasterFactory.class.getName(), broadcasterFactory);
+ }
+
+ for (String i : broadcasterFilters) {
+ logger.info("Using BroadcastFilter: {}", i);
+ }
+
+ String s = config.getInitParameter(ApplicationConfig.BROADCASTER_SHARABLE_THREAD_POOLS);
+ if (s != null) {
+ sharedThreadPools = Boolean.parseBoolean(s);
+ }
+
+ logger.info("Shared ExecutorService supported: {}", sharedThreadPools);
+ logger.info("HttpSession supported: {}", config.isSupportSession());
+ logger.info("Using BroadcasterFactory: {}", broadcasterFactory.getClass().getName());
+ logger.info("Using WebSocketProcessor: {}", webSocketProcessorClassName);
+ logger.info("Using Broadcaster: {}", broadcasterClassName);
+ logger.info("Atmosphere Framework {} started.", Version.getRawVersion());
+
+ String showSupportMessage = config.getInitParameter("org.atmosphere.cpr.showSupportMessage");
+ if (showSupportMessage == null || Boolean.parseBoolean(showSupportMessage)) {
+ logger.info("\n\n\tFor Commercial Support, visit \n\t{} " +
+ "or send an email to {}\n", "http://www.async-io.org/", "support@async-io.org");
+ }
+ } catch (Throwable t) {
+ logger.error("Failed to initialize Atmosphere Framework", t);
+
+ if (t instanceof ServletException) {
+ throw (ServletException) t;
+ }
+
+ throw new ServletException(t);
+ }
+ isInit = true;
+ return this;
+ }
+
+ /**
+ * Configure the list of {@link AtmosphereInterceptor}.
+ *
+ * @param sc a ServletConfig
+ */
+ protected void configureAtmosphereInterceptor(ServletConfig sc) {
+ String s = sc.getInitParameter(ApplicationConfig.ATMOSPHERE_INTERCEPTORS);
+ if (s != null) {
+ String[] list = s.split(",");
+ for (String a : list) {
+ try {
+ AtmosphereInterceptor ai = (AtmosphereInterceptor) Thread.currentThread().getContextClassLoader()
+ .loadClass(a.trim()).newInstance();
+ ai.configure(config);
+ interceptor(ai);
+ } catch (InstantiationException e) {
+ logger.warn("", e);
+ } catch (IllegalAccessException e) {
+ logger.warn("", e);
+ } catch (ClassNotFoundException e) {
+ logger.warn("", e);
+ }
+ }
+ }
+
+ s = sc.getInitParameter(ApplicationConfig.DISABLE_ATMOSPHEREINTERCEPTOR);
+ if (s == null) {
+ // OnDisconnect
+ interceptors.addFirst(newAInterceptor(OnDisconnectInterceptor.class));
+ // ADD Tracking ID Handshake
+ interceptors.addFirst(newAInterceptor(JavaScriptProtocol.class));
+ // ADD JSONP support
+ interceptors.addFirst(newAInterceptor(JSONPAtmosphereInterceptor.class));
+ // Add SSE support
+ interceptors.addFirst(newAInterceptor(SSEAtmosphereInterceptor.class));
+ // Android 2.3.x streaming support
+ interceptors.addFirst(newAInterceptor(AndroidAtmosphereInterceptor.class));
+ logger.info("Installed Default AtmosphereInterceptor {}. " +
+ "Set org.atmosphere.cpr.AtmosphereInterceptor.disableDefaults in your xml to disable them.", interceptors);
+ }
+ }
+
+ protected AtmosphereInterceptor newAInterceptor(Class<? extends AtmosphereInterceptor> a) {
+ AtmosphereInterceptor ai = null;
+ try {
+ ai = (AtmosphereInterceptor) getClass().getClassLoader().loadClass(a.getName()).newInstance();
+ ai.configure(config);
+ } catch (Exception ex) {
+ logger.warn("", ex);
+ }
+ return ai;
+ }
+
+ protected void configureWebDotXmlAtmosphereHandler(ServletConfig sc) {
+ String s = sc.getInitParameter(ATMOSPHERE_HANDLER);
+ if (s != null) {
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ try {
+
+ String mapping = sc.getInitParameter(ATMOSPHERE_HANDLER_MAPPING);
+ if (mapping == null) {
+ mapping = "/*";
+ }
+ addAtmosphereHandler(mapping, (AtmosphereHandler) cl.loadClass(s).newInstance());
+ } catch (Exception ex) {
+ logger.warn("Unable to load WebSocketHandle instance", ex);
+ }
+ }
+ }
+
+ protected void configureBroadcaster() {
+
+ try {
+ // Check auto supported one
+ if (isBroadcasterSpecified == false) {
+ broadcasterClassName = lookupDefaultBroadcasterType(broadcasterClassName);
+ }
+
+ Class<? extends Broadcaster> bc =
+ (Class<? extends Broadcaster>) Thread.currentThread().getContextClassLoader()
+ .loadClass(broadcasterClassName);
+ if (broadcasterFactoryClassName != null) {
+ broadcasterFactory = (BroadcasterFactory) Thread.currentThread().getContextClassLoader()
+ .loadClass(broadcasterFactoryClassName).newInstance();
+ }
+
+ if (broadcasterFactory == null) {
+ broadcasterFactory = new DefaultBroadcasterFactory(bc, broadcasterLifeCyclePolicy, config);
+ }
+
+ for (BroadcasterListener b : broadcasterListeners) {
+ broadcasterFactory.addBroadcasterListener(b);
+ }
+
+ BroadcasterFactory.setBroadcasterFactory(broadcasterFactory, config);
+ InjectorProvider.getInjector().inject(broadcasterFactory);
+
+ Iterator<Entry<String, AtmosphereHandlerWrapper>> i = atmosphereHandlers.entrySet().iterator();
+ AtmosphereHandlerWrapper w;
+ Entry<String, AtmosphereHandlerWrapper> e;
+ while (i.hasNext()) {
+ e = i.next();
+ w = e.getValue();
+
+ if (w.broadcaster == null) {
+ w.broadcaster = broadcasterFactory.get(w.mapping);
+ } else {
+ if (broadcasterCacheClassName != null) {
+ BroadcasterCache cache = (BroadcasterCache) Thread.currentThread().getContextClassLoader()
+ .loadClass(broadcasterCacheClassName).newInstance();
+ InjectorProvider.getInjector().inject(cache);
+ w.broadcaster.getBroadcasterConfig().setBroadcasterCache(cache);
+ }
+ }
+ }
+ } catch (Exception ex) {
+ logger.error("Unable to configure Broadcaster/Factory/Cache", ex);
+ }
+ }
+
+ protected void doInitParamsForWebSocket(ServletConfig sc) {
+ String s = sc.getInitParameter(WEBSOCKET_SUPPORT);
+ if (s != null) {
+ webSocketEnabled = Boolean.parseBoolean(s);
+ sessionSupport(false);
+ }
+ s = sc.getInitParameter(WEBSOCKET_PROTOCOL);
+ if (s != null) {
+ webSocketProtocolClassName = s;
+ }
+
+ s = sc.getInitParameter(WEBSOCKET_PROCESSOR);
+ if (s != null) {
+ webSocketProcessorClassName = s;
+ }
+ }
+
+ /**
+ * Read init param from web.xml and apply them.
+ *
+ * @param sc {@link ServletConfig}
+ */
+ protected void doInitParams(ServletConfig sc) {
+ String s = sc.getInitParameter(PROPERTY_NATIVE_COMETSUPPORT);
+ if (s != null) {
+ useNativeImplementation = Boolean.parseBoolean(s);
+ if (useNativeImplementation) isCometSupportSpecified = true;
+ }
+ s = sc.getInitParameter(PROPERTY_BLOCKING_COMETSUPPORT);
+ if (s != null) {
+ useBlockingImplementation = Boolean.parseBoolean(s);
+ if (useBlockingImplementation) isCometSupportSpecified = true;
+ }
+ s = sc.getInitParameter(PROPERTY_USE_STREAM);
+ if (s != null) {
+ useStreamForFlushingComments = Boolean.parseBoolean(s);
+ }
+ s = sc.getInitParameter(PROPERTY_COMET_SUPPORT);
+ if (s != null) {
+ asyncSupport = new DefaultAsyncSupportResolver(config).newCometSupport(s);
+ isCometSupportSpecified = true;
+ }
+ s = sc.getInitParameter(BROADCASTER_CLASS);
+ if (s != null) {
+ broadcasterClassName = s;
+ isBroadcasterSpecified = true;
+ }
+ s = sc.getInitParameter(BROADCASTER_CACHE);
+ if (s != null) {
+ broadcasterCacheClassName = s;
+ }
+ s = sc.getInitParameter(PROPERTY_SESSION_SUPPORT);
+ if (s != null) {
+ config.setSupportSession(Boolean.valueOf(s));
+ isSessionSupportSpecified = true;
+ }
+ s = sc.getInitParameter(DISABLE_ONSTATE_EVENT);
+ if (s != null) {
+ initParams.put(DISABLE_ONSTATE_EVENT, s);
+ } else {
+ initParams.put(DISABLE_ONSTATE_EVENT, "false");
+ }
+ s = sc.getInitParameter(RESUME_AND_KEEPALIVE);
+ if (s != null) {
+ initParams.put(RESUME_AND_KEEPALIVE, s);
+ }
+ s = sc.getInitParameter(BROADCAST_FILTER_CLASSES);
+ if (s != null) {
+ broadcasterFilters.addAll(Arrays.asList(s.split(",")));
+ logger.info("Installing BroadcastFilter class(es) {}", s);
+ }
+ s = sc.getInitParameter(BROADCASTER_LIFECYCLE_POLICY);
+ if (s != null) {
+ broadcasterLifeCyclePolicy = s;
+ }
+ s = sc.getInitParameter(BROADCASTER_FACTORY);
+ if (s != null) {
+ broadcasterFactoryClassName = s;
+ }
+ s = sc.getInitParameter(ATMOSPHERE_HANDLER_PATH);
+ if (s != null) {
+ handlersPath = s;
+ }
+ s = sc.getInitParameter(PROPERTY_ATMOSPHERE_XML);
+ if (s != null) {
+ atmosphereDotXmlPath = s;
+ }
+ }
+
+ public void loadConfiguration(ServletConfig sc) throws ServletException {
+
+ if (!autoDetectHandlers) return;
+
+ try {
+ URL url = sc.getServletContext().getResource(handlersPath);
+ URLClassLoader urlC = new URLClassLoader(new URL[]{url},
+ Thread.currentThread().getContextClassLoader());
+ loadAtmosphereDotXml(sc.getServletContext().
+ getResourceAsStream(atmosphereDotXmlPath), urlC);
+
+ if (atmosphereHandlers.size() == 0) {
+ autoDetectAtmosphereHandlers(sc.getServletContext(), urlC);
+
+ if (atmosphereHandlers.size() == 0) {
+ detectSupportedFramework(sc);
+ }
+ }
+
+ autoDetectWebSocketHandler(sc.getServletContext(), urlC);
+ } catch (Throwable t) {
+ throw new ServletException(t);
+ }
+ }
+
+ /**
+ * Auto-detect Jersey when no atmosphere.xml file are specified.
+ *
+ * @param sc {@link ServletConfig}
+ * @return true if Jersey classes are detected
+ * @throws ClassNotFoundException
+ */
+ protected boolean detectSupportedFramework(ServletConfig sc) throws ClassNotFoundException, IllegalAccessException,
+ InstantiationException, NoSuchMethodException, InvocationTargetException {
+
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ String broadcasterClassNameTmp = null;
+
+ try {
+ cl.loadClass(JERSEY_CONTAINER);
+
+ if (!isBroadcasterSpecified) {
+ broadcasterClassNameTmp = lookupDefaultBroadcasterType(JERSEY_BROADCASTER);
+
+ cl.loadClass(broadcasterClassNameTmp);
+ }
+ useStreamForFlushingComments = true;
+ } catch (Throwable t) {
+ logger.trace("", t);
+ return false;
+ }
+
+ logger.warn("Missing META-INF/atmosphere.xml but found the Jersey runtime. Starting Jersey");
+
+ // Jersey will handle itself the headers.
+ initParams.put(WRITE_HEADERS, "false");
+
+ ReflectorServletProcessor rsp = new ReflectorServletProcessor();
+ if (broadcasterClassNameTmp != null) broadcasterClassName = broadcasterClassNameTmp;
+ rsp.setServletClassName(JERSEY_CONTAINER);
+ sessionSupport(false);
+ initParams.put(DISABLE_ONSTATE_EVENT, "true");
+
+ String mapping = sc.getInitParameter(PROPERTY_SERVLET_MAPPING);
+ if (mapping == null) {
+ mapping = "/*";
+ }
+ Class<? extends Broadcaster> bc = (Class<? extends Broadcaster>) cl.loadClass(broadcasterClassName);
+
+
+ if (broadcasterFactory != null) {
+ broadcasterFactory.destroy();
+ }
+ broadcasterFactory = new DefaultBroadcasterFactory(bc, broadcasterLifeCyclePolicy, config);
+ BroadcasterFactory.setBroadcasterFactory(broadcasterFactory, config);
+
+ for (BroadcasterListener b : broadcasterListeners) {
+ broadcasterFactory.addBroadcasterListener(b);
+ }
+
+ Broadcaster b;
+
+ try {
+ b = broadcasterFactory.get(bc, mapping);
+ } catch (IllegalStateException ex) {
+ logger.warn("Two Broadcaster's named {}. Renaming the second one to {}", mapping, sc.getServletName() + mapping);
+ b = broadcasterFactory.get(bc, sc.getServletName() + mapping);
+ }
+
+ addAtmosphereHandler(mapping, rsp, b);
+ return true;
+ }
+
+ protected String lookupDefaultBroadcasterType(String defaultB) {
+ for (String b : broadcasterTypes) {
+ try {
+ Class.forName(b);
+ return b;
+ } catch (ClassNotFoundException e) {
+ }
+ }
+ return defaultB;
+ }
+
+ protected void sessionSupport(boolean sessionSupport) {
+ if (!isSessionSupportSpecified) {
+ config.setSupportSession(sessionSupport);
+ } else if (!config.isSupportSession()) {
+ // Don't turn off session support. Once it's on, leave it on.
+ config.setSupportSession(sessionSupport);
+ }
+ }
+
+ /**
+ * Initialize {@link AtmosphereServletProcessor}
+ *
+ * @param sc the {@link ServletConfig}
+ * @throws javax.servlet.ServletException
+ */
+ public void initAtmosphereHandler(ServletConfig sc) throws ServletException {
+ AtmosphereHandler a;
+ AtmosphereHandlerWrapper w;
+ for (Entry<String, AtmosphereHandlerWrapper> h : atmosphereHandlers.entrySet()) {
+ w = h.getValue();
+ a = w.atmosphereHandler;
+ if (a instanceof AtmosphereServletProcessor) {
+ ((AtmosphereServletProcessor) a).init(sc);
+ }
+ }
+
+ if (atmosphereHandlers.size() == 0 && !SimpleHttpProtocol.class.isAssignableFrom(webSocketProtocol.getClass())) {
+ logger.debug("Adding a void AtmosphereHandler mapped to /* to allow WebSocket application only");
+ addAtmosphereHandler("/*", new AbstractReflectorAtmosphereHandler() {
+ @Override
+ public void onRequest(AtmosphereResource r) throws IOException {
+ logger.debug("No AtmosphereHandler defined.");
+ }
+
+ @Override
+ public void destroy() {
+ }
+ });
+ }
+ }
+
+ protected void initWebSocket() {
+ if (webSocketProtocol == null) {
+ try {
+ webSocketProtocol = (WebSocketProtocol) Thread.currentThread().getContextClassLoader()
+ .loadClass(webSocketProtocolClassName).newInstance();
+ logger.info("Installed WebSocketProtocol {} ", webSocketProtocolClassName);
+ } catch (Exception ex) {
+ try {
+ webSocketProtocol = (WebSocketProtocol) AtmosphereFramework.class.getClassLoader()
+ .loadClass(webSocketProtocolClassName).newInstance();
+ logger.info("Installed WebSocketProtocol {} ", webSocketProtocolClassName);
+ } catch (Exception ex2) {
+ logger.error("Cannot load the WebSocketProtocol {}", getWebSocketProtocolClassName(), ex);
+ webSocketProtocol = new SimpleHttpProtocol();
+ }
+ }
+ }
+ webSocketProtocol.configure(config);
+ }
+
+ public AtmosphereFramework destroy() {
+ if (asyncSupport != null && AsynchronousProcessor.class.isAssignableFrom(asyncSupport.getClass())) {
+ ((AsynchronousProcessor) asyncSupport).shutdown();
+ }
+
+ // We just need one bc to shutdown the shared thread pool
+ for (Entry<String, AtmosphereHandlerWrapper> entry : atmosphereHandlers.entrySet()) {
+ AtmosphereHandlerWrapper handlerWrapper = entry.getValue();
+ handlerWrapper.atmosphereHandler.destroy();
+ }
+
+ BroadcasterFactory factory = broadcasterFactory;
+ if (factory != null) {
+ factory.destroy();
+ BroadcasterFactory.factory = null;
+ }
+ WebSocketProcessorFactory.getDefault().destroy();
+ return this;
+ }
+
+ /**
+ * Load AtmosphereHandler defined under META-INF/atmosphere.xml
+ *
+ * @param stream The input stream we read from.
+ * @param c The classloader
+ */
+ protected void loadAtmosphereDotXml(InputStream stream, URLClassLoader c)
+ throws IOException, ServletException {
+
+ if (stream == null) {
+ return;
+ }
+
+ AtmosphereConfigReader.getInstance().parse(config, stream);
+ for (AtmosphereHandlerConfig atmoHandler : config.getAtmosphereHandlerConfig()) {
+ try {
+ AtmosphereHandler handler;
+
+ if (!ReflectorServletProcessor.class.getName().equals(atmoHandler.getClassName())) {
+ handler = (AtmosphereHandler) c.loadClass(atmoHandler.getClassName()).newInstance();
+ } else {
+ handler = new ReflectorServletProcessor();
+ }
+
+ logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", handler, atmoHandler.getContextRoot());
+
+ for (ApplicationConfiguration a : atmoHandler.getApplicationConfig()) {
+ initParams.put(a.getParamName(), a.getParamValue());
+ }
+
+ for (FrameworkConfiguration a : atmoHandler.getFrameworkConfig()) {
+ initParams.put(a.getParamName(), a.getParamValue());
+ }
+
+ for (AtmosphereHandlerProperty handlerProperty : atmoHandler.getProperties()) {
+
+ if (handlerProperty.getValue() != null && handlerProperty.getValue().indexOf("jersey") != -1) {
+ initParams.put(DISABLE_ONSTATE_EVENT, "true");
+ useStreamForFlushingComments = true;
+ broadcasterClassName = lookupDefaultBroadcasterType(JERSEY_BROADCASTER);
+ broadcasterFactory = null;
+ configureBroadcaster();
+ }
+
+ IntrospectionUtils.setProperty(handler, handlerProperty.getName(), handlerProperty.getValue());
+ IntrospectionUtils.addProperty(handler, handlerProperty.getName(), handlerProperty.getValue());
+ }
+
+ sessionSupport(Boolean.valueOf(atmoHandler.getSupportSession()));
+
+ String broadcasterClass = atmoHandler.getBroadcaster();
+ Broadcaster b;
+ /**
+ * If there is more than one AtmosphereHandler defined, their Broadcaster
+ * may clash each other with the BroadcasterFactory. In that case we will use the
+ * last one defined.
+ */
+ if (broadcasterClass != null) {
+ broadcasterClassName = broadcasterClass;
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ Class<? extends Broadcaster> bc = (Class<? extends Broadcaster>) cl.loadClass(broadcasterClassName);
+ broadcasterFactory = new DefaultBroadcasterFactory(bc, broadcasterLifeCyclePolicy, config);
+ BroadcasterFactory.setBroadcasterFactory(broadcasterFactory, config);
+ }
+
+ b = broadcasterFactory.lookup(atmoHandler.getContextRoot(), true);
+
+ AtmosphereHandlerWrapper wrapper = new AtmosphereHandlerWrapper(handler, b);
+ addMapping(atmoHandler.getContextRoot(), wrapper);
+
+ String bc = atmoHandler.getBroadcasterCache();
+ if (bc != null) {
+ broadcasterCacheClassName = bc;
+ }
+
+ if (atmoHandler.getCometSupport() != null) {
+ asyncSupport = (AsyncSupport) c.loadClass(atmoHandler.getCometSupport())
+ .getDeclaredConstructor(new Class[]{AtmosphereConfig.class})
+ .newInstance(new Object[]{config});
+ }
+
+ if (atmoHandler.getBroadcastFilterClasses() != null) {
+ broadcasterFilters.addAll(atmoHandler.getBroadcastFilterClasses());
+ }
+
+ List<AtmosphereInterceptor> l = new ArrayList<AtmosphereInterceptor>();
+ if (atmoHandler.getAtmosphereInterceptorClasses() != null) {
+ for (String a : atmoHandler.getAtmosphereInterceptorClasses()) {
+ try {
+ AtmosphereInterceptor ai = (AtmosphereInterceptor) c.loadClass(a).newInstance();
+ ai.configure(config);
+ l.add(ai);
+ } catch (Throwable e) {
+ logger.warn("", e);
+ }
+ }
+ }
+ wrapper.interceptors = l;
+ if (l.size() > 0) {
+ logger.info("Installed AtmosphereInterceptor {} mapped to AtmosphereHandler {}", l, atmoHandler.getClassName());
+ }
+ } catch (Throwable t) {
+ logger.warn("Unable to load AtmosphereHandler class: " + atmoHandler.getClassName(), t);
+ throw new ServletException(t);
+ }
+
+ }
+ }
+
+ /**
+ * Set the {@link AsyncSupport} implementation. Make sure you don't set
+ * an implementation that only works on some Container. See {@link BlockingIOCometSupport}
+ * for an example.
+ *
+ * @param asyncSupport
+ */
+ public AtmosphereFramework setAsyncSupport(AsyncSupport asyncSupport) {
+ this.asyncSupport = asyncSupport;
+ return this;
+ }
+
+ /**
+ * @param asyncSupport
+ * @return
+ * @Deprecated - Use {@link #setAsyncSupport(AsyncSupport)}
+ */
+ public AtmosphereFramework setCometSupport(AsyncSupport asyncSupport) {
+ return setAsyncSupport(asyncSupport);
+ }
+
+ /**
+ * Return the current {@link AsyncSupport}
+ *
+ * @return the current {@link AsyncSupport}
+ */
+ public AsyncSupport getAsyncSupport() {
+ return asyncSupport;
+ }
+
+ /**
+ * Return the current {@link AsyncSupport}
+ *
+ * @return the current {@link AsyncSupport}
+ * @deprecated Use getAsyncSupport
+ */
+ public AsyncSupport getCometSupport() {
+ return asyncSupport;
+ }
+
+ /**
+ * Returns an instance of AsyncSupportResolver {@link AsyncSupportResolver}
+ *
+ * @return CometSupportResolver
+ */
+ protected AsyncSupportResolver createAsyncSupportResolver() {
+ return new DefaultAsyncSupportResolver(config);
+ }
+
+
+ /**
+ * Auto detect the underlying Servlet Container we are running on.
+ */
+ protected void autoDetectContainer() {
+ // Was defined in atmosphere.xml
+ if (getAsyncSupport() == null) {
+ setAsyncSupport(createAsyncSupportResolver()
+ .resolve(useNativeImplementation, useBlockingImplementation, webSocketEnabled));
+ }
+
+ logger.info("Atmosphere is using async support: {} running under container: {}",
+ getAsyncSupport().getClass().getName(), asyncSupport.getContainerName());
+ }
+
+ /**
+ * Auto detect instance of {@link AtmosphereHandler} in case META-INF/atmosphere.xml
+ * is missing.
+ *
+ * @param servletContext {@link ServletContext}
+ * @param classloader {@link URLClassLoader} to load the class.
+ * @throws java.net.MalformedURLException
+ * @throws java.net.URISyntaxException
+ */
+ public void autoDetectAtmosphereHandlers(ServletContext servletContext, URLClassLoader classloader)
+ throws MalformedURLException, URISyntaxException {
+
+ // If Handler has been added
+ if (atmosphereHandlers.size() > 0) return;
+
+ logger.info("Auto detecting atmosphere handlers {}", handlersPath);
+
+ String realPath = servletContext.getRealPath(handlersPath);
+
+ // Weblogic bug
+ if (realPath == null) {
+ URL u = servletContext.getResource(handlersPath);
+ if (u == null) return;
+ realPath = u.getPath();
+ }
+
+ loadAtmosphereHandlersFromPath(classloader, realPath);
+ }
+
+ public void loadAtmosphereHandlersFromPath(URLClassLoader classloader, String realPath) {
+ File file = new File(realPath);
+
+ if (file.isDirectory()) {
+ getFiles(file);
+ scanDone = true;
+
+ for (String className : possibleComponentsCandidate) {
+ try {
+ className = className.replace('\\', '/');
+ className = className.replaceFirst("^.*/(WEB-INF|target)(?:/scala-[^/]+)?/(test-)?classes/(.*)\\.class", "$3").replace("/", ".");
+ Class<?> clazz = classloader.loadClass(className);
+
+ if (AtmosphereHandler.class.isAssignableFrom(clazz)) {
+ AtmosphereHandler handler = (AtmosphereHandler) clazz.newInstance();
+ InjectorProvider.getInjector().inject(handler);
+ addMapping("/" + handler.getClass().getSimpleName(),
+ new AtmosphereHandlerWrapper(broadcasterFactory, handler, "/" + handler.getClass().getSimpleName()));
+ logger.info("Installed AtmosphereHandler {} mapped to context-path: {}", handler, handler.getClass().getName());
+ }
+ } catch (Throwable t) {
+ logger.trace("failed to load class as an AtmosphereHandler: " + className, t);
+ }
+ }
+ }
+ }
+
+ /**
+ * Auto detect instance of {@link org.atmosphere.websocket.WebSocketHandler} in case META-INF/atmosphere.xml
+ * is missing.
+ *
+ * @param servletContext {@link ServletContext}
+ * @param classloader {@link URLClassLoader} to load the class.
+ * @throws java.net.MalformedURLException
+ * @throws java.net.URISyntaxException
+ */
+ protected void autoDetectWebSocketHandler(ServletContext servletContext, URLClassLoader classloader)
+ throws MalformedURLException, URISyntaxException {
+
+ if (hasNewWebSocketProtocol) return;
+
+ logger.info("Auto detecting WebSocketHandler in {}", handlersPath);
+
+ String realPath = servletContext.getRealPath(handlersPath);
+
+ // Weblogic bug
+ if (realPath == null) {
+ URL u = servletContext.getResource(handlersPath);
+ if (u == null) return;
+ realPath = u.getPath();
+ }
+
+ loadWebSocketFromPath(classloader, realPath);
+ }
+
+ protected void loadWebSocketFromPath(URLClassLoader classloader, String realPath) {
+ File file = new File(realPath);
+
+ if (file.isDirectory()) {
+ getFiles(file);
+ scanDone = true;
+
+ for (String className : possibleComponentsCandidate) {
+ try {
+ className = className.replace('\\', '/');
+ className = className.replaceFirst("^.*/(WEB-INF|target)(?:/scala-[^/]+)?/(test-)?classes/(.*)\\.class", "$3").replace("/", ".");
+ Class<?> clazz = classloader.loadClass(className);
+
+ if (WebSocketProtocol.class.isAssignableFrom(clazz)) {
+ webSocketProtocol = (WebSocketProtocol) clazz.newInstance();
+ InjectorProvider.getInjector().inject(webSocketProtocol);
+ logger.info("Installed WebSocketProtocol {}", webSocketProtocol);
+ }
+ } catch (Throwable t) {
+ logger.trace("failed to load class as an WebSocketProtocol: " + className, t);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Get the list of possible candidate to load as {@link AtmosphereHandler}
+ *
+ * @param f the real path {@link File}
+ */
+ private void getFiles(File f) {
+ if (scanDone) return;
+
+ File[] files = f.listFiles();
+ for (File test : files) {
+ if (test.isDirectory()) {
+ getFiles(test);
+ } else {
+ String clazz = test.getAbsolutePath();
+ if (clazz.endsWith(".class")) {
+ possibleComponentsCandidate.add(clazz);
+ }
+ }
+ }
+ }
+
+ /**
+ * Invoke the proprietary {@link AsyncSupport}
+ *
+ * @param req
+ * @param res
+ * @return an {@link Action}
+ * @throws IOException
+ * @throws ServletException
+ */
+ public Action doCometSupport(AtmosphereRequest req, AtmosphereResponse res) throws IOException, ServletException {
+ req.setAttribute(BROADCASTER_FACTORY, broadcasterFactory);
+ req.setAttribute(PROPERTY_USE_STREAM, useStreamForFlushingComments);
+ req.setAttribute(BROADCASTER_CLASS, broadcasterClassName);
+ req.setAttribute(ATMOSPHERE_CONFIG, config);
+
+ Action a = null;
+ try {
+ boolean skip = true;
+ String s = config.getInitParameter(ALLOW_QUERYSTRING_AS_REQUEST);
+ if (s != null) {
+ skip = Boolean.valueOf(s);
+ }
+ if (!skip || req.getAttribute(WEBSOCKET_SUSPEND) == null) {
+ Map<String, String> headers = configureQueryStringAsRequest(req);
+ String body = headers.remove(ATMOSPHERE_POST_BODY);
+ if (body != null && body.isEmpty()) {
+ body = null;
+ }
+
+ req.headers(headers)
+ .method(body != null && req.getMethod().equalsIgnoreCase("GET") ? "POST" : req.getMethod());
+
+ if (body != null) {
+ req.body(body);
+ }
+ }
+
+ s = req.getHeader(X_ATMOSPHERE_TRACKING_ID);
+
+ // Lookup for websocket
+ if (s == null || s.equals("0")) {
+ String unique = config.getInitParameter(ApplicationConfig.UNIQUE_UUID_WEBSOCKET);
+ if (unique != null && Boolean.valueOf(unique)) {
+ s = (String) req.getAttribute(SUSPENDED_ATMOSPHERE_RESOURCE_UUID);
+ }
+ }
+
+ if (s == null || s.equals("0")) {
+ s = UUID.randomUUID().toString();
+ res.setHeader(X_ATMOSPHERE_TRACKING_ID, s);
+ } else {
+ // This may breaks 1.0.0 application because the WebSocket's associated AtmosphereResource will
+ // all have the same UUID, and retrieving the original one for WebSocket, so we don't set it at all.
+ // Null means it is not an HTTP request.
+ if (req.resource() == null) {
+ res.setHeader(X_ATMOSPHERE_TRACKING_ID, s);
+ } else if (req.getAttribute(WebSocket.WEBSOCKET_INITIATED) == null) {
+ // WebSocket reconnect, in case an application manually set the header
+ // (impossible to retrieve the headers normally with WebSocket or SSE)
+ res.setHeader(X_ATMOSPHERE_TRACKING_ID, s);
+ }
+ }
+
+ if (req.getAttribute(SUSPENDED_ATMOSPHERE_RESOURCE_UUID) == null) {
+ req.setAttribute(SUSPENDED_ATMOSPHERE_RESOURCE_UUID, s);
+ }
+
+ a = asyncSupport.service(req, res);
+ } catch (IllegalStateException ex) {
+ if (ex.getMessage() != null && (ex.getMessage().startsWith("Tomcat failed") || ex.getMessage().startsWith("JBoss failed"))) {
+ if (!isFilter) {
+ logger.warn("Failed using comet support: {}, error: {} Is the Nio or Apr Connector enabled?", asyncSupport.getClass().getName(),
+ ex.getMessage());
+ }
+ logger.trace(ex.getMessage(), ex);
+
+ AsyncSupport current = asyncSupport;
+ asyncSupport = asyncSupport.supportWebSocket() ? new Tomcat7BIOSupportWithWebSocket(config) : new BlockingIOCometSupport(config);
+ if (current instanceof AsynchronousProcessor) {
+ ((AsynchronousProcessor) current).shutdown();
+ }
+
+ asyncSupport.init(config.getServletConfig());
+ logger.warn("Using " + asyncSupport.getClass().getName());
+
+ a = asyncSupport.service(req, res);
+ } else {
+ logger.error("AtmosphereFramework exception", ex);
+ throw ex;
+ }
+ } finally {
+ if (a != null) {
+ notify(a.type(), req, res);
+ }
+
+ if (req != null && a != null && a.type() != Action.TYPE.SUSPEND) {
+ req.destroy();
+ res.destroy();
+ notify(Action.TYPE.DESTROYED, req, res);
+ }
+ }
+ return a;
+ }
+
+ /**
+ * Return the default {@link Broadcaster} class name.
+ *
+ * @return the broadcasterClassName
+ */
+ public String getDefaultBroadcasterClassName() {
+ return broadcasterClassName;
+ }
+
+ /**
+ * Set the default {@link Broadcaster} class name
+ *
+ * @param bccn the broadcasterClassName to set
+ */
+ public AtmosphereFramework setDefaultBroadcasterClassName(String bccn) {
+ broadcasterClassName = bccn;
+ return this;
+ }
+
+ /**
+ * <tt>true</tt> if Atmosphere uses {@link AtmosphereResponse#getOutputStream()}
+ * by default for write operation.
+ *
+ * @return the useStreamForFlushingComments
+ */
+ public boolean isUseStreamForFlushingComments() {
+ return useStreamForFlushingComments;
+ }
+
+ /**
+ * Set to <tt>true</tt> so Atmosphere uses {@link AtmosphereResponse#getOutputStream()}
+ * by default for write operation. Default is false.
+ *
+ * @param useStreamForFlushingComments the useStreamForFlushingComments to set
+ */
+ public AtmosphereFramework setUseStreamForFlushingComments(boolean useStreamForFlushingComments) {
+ this.useStreamForFlushingComments = useStreamForFlushingComments;
+ return this;
+ }
+
+ /**
+ * Get the {@link BroadcasterFactory} which is used by Atmosphere to construct
+ * {@link Broadcaster}
+ *
+ * @return {@link BroadcasterFactory}
+ */
+ public BroadcasterFactory getBroadcasterFactory() {
+ return broadcasterFactory;
+ }
+
+ /**
+ * Set the {@link BroadcasterFactory} which is used by Atmosphere to construct
+ * {@link Broadcaster}
+ *
+ * @return {@link BroadcasterFactory}
+ */
+ public AtmosphereFramework setBroadcasterFactory(final BroadcasterFactory broadcasterFactory) {
+ this.broadcasterFactory = broadcasterFactory;
+ configureBroadcaster();
+ return this;
+ }
+
+ /**
+ * Return the {@link org.atmosphere.cpr.BroadcasterCache} class name.
+ *
+ * @return the {@link org.atmosphere.cpr.BroadcasterCache} class name.
+ */
+ public String getBroadcasterCacheClassName() {
+ return broadcasterCacheClassName;
+ }
+
+ /**
+ * Set the {@link org.atmosphere.cpr.BroadcasterCache} class name.
+ *
+ * @param broadcasterCacheClassName
+ */
+ public void setBroadcasterCacheClassName(String broadcasterCacheClassName) {
+ this.broadcasterCacheClassName = broadcasterCacheClassName;
+ configureBroadcaster();
+ }
+
+ /**
+ * Add a new Broadcaster class name AtmosphereServlet can use when initializing requests, and when
+ * atmosphere.xml broadcaster element is unspecified.
+ *
+ * @param broadcasterTypeString
+ */
+ public AtmosphereFramework addBroadcasterType(String broadcasterTypeString) {
+ broadcasterTypes.add(broadcasterTypeString);
+ return this;
+ }
+
+ public String getWebSocketProtocolClassName() {
+ return webSocketProtocolClassName;
+ }
+
+ public AtmosphereFramework setWebSocketProtocolClassName(String webSocketProtocolClassName) {
+ hasNewWebSocketProtocol = true;
+ this.webSocketProtocolClassName = webSocketProtocolClassName;
+ return this;
+ }
+
+ public Map<String, AtmosphereHandlerWrapper> getAtmosphereHandlers() {
+ return atmosphereHandlers;
+ }
+
+ protected Map<String, String> configureQueryStringAsRequest(AtmosphereRequest request) {
+ Map<String, String> headers = new HashMap<String, String>();
+
+ Enumeration<String> e = request.getParameterNames();
+ String s;
+ while (e.hasMoreElements()) {
+ s = e.nextElement();
+ if (s.equalsIgnoreCase("Content-Type")) {
+ // Use the one set by the user first.
+ if (request.getContentType() == null ||
+ !request.getContentType().equalsIgnoreCase(request.getParameter(s))) {
+ request.contentType(request.getParameter(s));
+ }
+ }
+ headers.put(s, request.getParameter(s));
+ }
+ logger.trace("Query String translated to headers {}", headers);
+ return headers;
+ }
+
+ protected boolean isIECandidate(AtmosphereRequest request) {
+ String userAgent = request.getHeader("User-Agent");
+ if (userAgent == null) return false;
+
+ if (userAgent.contains("MSIE") || userAgent.contains(".NET")) {
+ // Now check the header
+ String transport = request.getHeader(HeaderConfig.X_ATMOSPHERE_TRANSPORT);
+ if (transport != null) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public WebSocketProtocol getWebSocketProtocol() {
+ // TODO: Spagetthi code, needs to rework.
+ // Make sure we initialized the WebSocketProtocol
+ initWebSocket();
+ return webSocketProtocol;
+ }
+
+ public boolean isUseNativeImplementation() {
+ return useNativeImplementation;
+ }
+
+ public AtmosphereFramework setUseNativeImplementation(boolean useNativeImplementation) {
+ this.useNativeImplementation = useNativeImplementation;
+ return this;
+ }
+
+ public boolean isUseBlockingImplementation() {
+ return useBlockingImplementation;
+ }
+
+ public AtmosphereFramework setUseBlockingImplementation(boolean useBlockingImplementation) {
+ this.useBlockingImplementation = useBlockingImplementation;
+ return this;
+ }
+
+ public String getAtmosphereDotXmlPath() {
+ return atmosphereDotXmlPath;
+ }
+
+ public AtmosphereFramework setAtmosphereDotXmlPath(String atmosphereDotXmlPath) {
+ this.atmosphereDotXmlPath = atmosphereDotXmlPath;
+ return this;
+ }
+
+ public String getHandlersPath() {
+ return handlersPath;
+ }
+
+ public AtmosphereFramework setHandlersPath(String handlersPath) {
+ this.handlersPath = handlersPath;
+ return this;
+ }
+
+ /**
+ * Return the location of the jars containing the application classes. Default is WEB-INF/lib
+ *
+ * @return the location of the jars containing the application classes. Default is WEB-INF/lib
+ */
+ public String getLibPath() {
+ return libPath;
+ }
+
+ /**
+ * Set the location of the jars containing the application.
+ *
+ * @param libPath the location of the jars containing the application.
+ * @return this
+ */
+ public AtmosphereFramework setLibPath(String libPath) {
+ this.libPath = libPath;
+ return this;
+ }
+
+ public String getWebSocketProcessorClassName() {
+ return webSocketProcessorClassName;
+ }
+
+ public AtmosphereFramework setWebsocketProcessorClassName(String webSocketProcessorClassName) {
+ this.webSocketProcessorClassName = webSocketProcessorClassName;
+ return this;
+ }
+
+ /**
+ * Add an {@link AtmosphereInterceptor} implementation. The adding order or {@link AtmosphereInterceptor} will be used, e.g
+ * the first added {@link AtmosphereInterceptor} will always be called first.
+ *
+ * @param c {@link AtmosphereInterceptor}
+ * @return this
+ */
+ public AtmosphereFramework interceptor(AtmosphereInterceptor c) {
+ boolean found = false;
+ for (AtmosphereInterceptor interceptor : interceptors) {
+ if (interceptor.getClass().equals(c.getClass())) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ interceptors.addLast(c);
+ logger.info("Installed AtmosphereInterceptor {}. ", c);
+ }
+ return this;
+ }
+
+ /**
+ * Return the list of {@link AtmosphereInterceptor}
+ *
+ * @return the list of {@link AtmosphereInterceptor}
+ */
+ public LinkedList<AtmosphereInterceptor> interceptors() {
+ return interceptors;
+ }
+
+ /**
+ * Set the {@link AnnotationProcessor} class name.
+ *
+ * @param annotationProcessorClassName the {@link AnnotationProcessor} class name.
+ * @return this
+ */
+ public AtmosphereFramework annotationProcessorClassName(String annotationProcessorClassName) {
+ this.annotationProcessorClassName = annotationProcessorClassName;
+ return this;
+ }
+
+ /**
+ * Add an {@link AsyncSupportListener}
+ *
+ * @param asyncSupportListener an {@link AsyncSupportListener}
+ * @return this;
+ */
+ public AtmosphereFramework asyncSupportListener(AsyncSupportListener asyncSupportListener) {
+ asyncSupportListeners.add(asyncSupportListener);
+ return this;
+ }
+
+ /**
+ * Return the list of an {@link AsyncSupportListener}
+ *
+ * @return
+ */
+ public List<AsyncSupportListener> asyncSupportListeners() {
+ return asyncSupportListeners;
+ }
+
+ /**
+ * Add {@link BroadcasterListener} to all created {@link Broadcaster}
+ */
+ public AtmosphereFramework addBroadcasterListener(BroadcasterListener b) {
+ if (isInit) {
+ broadcasterFactory.addBroadcasterListener(b);
+ } else {
+ broadcasterListeners.add(b);
+ }
+ return this;
+ }
+
+ /**
+ * Return a configured instance of {@link AtmosphereConfig}
+ *
+ * @return a configured instance of {@link AtmosphereConfig}
+ */
+ public AtmosphereConfig getAtmosphereConfig() {
+ return config;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return servletConfig.getServletContext();
+ }
+
+ public ServletConfig getServletConfig() {
+ return servletConfig;
+ }
+
+ /**
+ * Return the list of {@link BroadcastFilter}
+ *
+ * @return the list of {@link BroadcastFilter
+ */
+ public List<String> broadcasterFilters() {
+ return broadcasterFilters;
+ }
+
+ /**
+ * Returns true if {@link java.util.concurrent.ExecutorService} shared amongst all components.
+ *
+ * @return true if {@link java.util.concurrent.ExecutorService} shared amongst all components.
+ */
+ public boolean isShareExecutorServices() {
+ return sharedThreadPools;
+ }
+
+ /**
+ * Set to true to have a {@link java.util.concurrent.ExecutorService} shared amongst all components.
+ *
+ * @param sharedThreadPools
+ * @return this
+ */
+ public AtmosphereFramework shareExecutorServices(boolean sharedThreadPools) {
+ this.sharedThreadPools = sharedThreadPools;
+ return this;
+ }
+
+ protected void autoConfigureService(ServletContext sc) throws IOException {
+ final ClassLoader cl = Thread.currentThread().getContextClassLoader();
+
+ String path = libPath != DEFAULT_LIB_PATH ? libPath : sc.getRealPath(handlersPath);
+ try {
+ AnnotationProcessor p = (AnnotationProcessor) cl.loadClass(annotationProcessorClassName).newInstance();
+ logger.info("Atmosphere is using {} for processing annotation", annotationProcessorClassName);
+
+ p.configure(this);
+ if (path != null) {
+ p.scan(new File(path));
+ }
+
+ String pathLibs = sc.getRealPath(DEFAULT_LIB_PATH);
+ if (pathLibs != null) {
+ File libFolder = new File(pathLibs);
+ File jars[] = libFolder.listFiles(new FilenameFilter() {
+
+ @Override
+ public boolean accept(File arg0, String arg1) {
+ return arg1.endsWith(".jar");
+ }
+ });
+
+ for (File file : jars) {
+ p.scan(file);
+ }
+ }
+ } catch (Throwable e) {
+ logger.debug("Atmosphere's Service Annotation Not Supported. Please add https://github.com/rmuller/infomas-asl as dependencies or your own AnnotationProcessor to support @Service");
+ logger.trace("", e);
+ return;
+ }
+ }
+
+ protected void notify(Action.TYPE type, AtmosphereRequest request, AtmosphereResponse response) {
+ for (AsyncSupportListener l : asyncSupportListeners()) {
+ try {
+ switch (type) {
+ case TIMEOUT:
+ l.onTimeout(request, response);
+ break;
+ case CANCELLED:
+ l.onClose(request, response);
+ break;
+ case SUSPEND:
+ l.onSuspend(request, response);
+ break;
+ case RESUME:
+ l.onSuspend(request, response);
+ break;
+ case DESTROYED:
+ l.onDestroyed(request, response);
+ break;
+ }
+ } catch (Throwable t) {
+ logger.warn("", t);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/scripts/automerge7.sh b/scripts/automerge7.sh
new file mode 100755
index 0000000000..ea83b2e52c
--- /dev/null
+++ b/scripts/automerge7.sh
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+FROM=7.0
+TO=7.1
+
+FROM_HEAD=origin/$FROM
+PUSH="origin HEAD:refs/for/$TO"
+
+show() {
+ sCommit=$1
+ if [ "$sCommit" == "" ]
+ then
+ echo "show() missing commit id"
+ exit 1
+ fi
+ git show -s $sCommit
+}
+merge() {
+ mCommit=$1
+ if [ "$mCommit" == "" ]
+ then
+ echo "merge() missing commit id"
+ exit 1
+ fi
+
+# echo "merge($mCommit)"
+
+ git merge -m "Should be overwritten by merge script" $mCommit $2
+ if [ "$?" != "0" ]
+ then
+ echo "Merge failed for commit $mCommit"
+ echo "Manual merge is needed"
+ exit 2
+ fi
+ # Add a change id using git hook
+ git commit --amend --no-edit
+
+}
+
+pushMerged() {
+# echo "pushMerged()"
+ git push $PUSH
+ if [ "$?" != "0" ]
+ then
+ echo "Push failed!"
+ exit 2
+ fi
+}
+
+maybe_commit_and_push() {
+# echo "maybe_commit_and_push()"
+ cpCommit=$1
+ if [ "$cpCommit" == "" ]
+ then
+ # Nothing to merge currently
+ return
+ fi
+ cpCommitMsg=$2
+ if [ "$cpCommitMsg" == "" ]
+ then
+ echo "Internal error, no commit message passed to maybe_commit_and_push()"
+ exit 1;
+ fi
+# echo "maybe_commit_and_push: Merging $cpCommit"
+ merge $cpCommit
+ echo -e "Merge changes from $FROM_HEAD\n\n$cpCommitMsg"|git commit --amend -F -
+ pushMerged
+}
+
+nothingToCommit=`git status | grep "nothing to commit"`
+if [ "$nothingToCommit" == "" ]
+then
+ git status
+ echo "Can not merge when there are unstaged changes."
+ exit 1;
+fi
+
+git checkout $TO
+git fetch
+
+pending=`git log $TO..$FROM_HEAD --reverse|grep "^commit "|sed "s/commit //"`
+
+pendingCommit=
+pendingCommitMessage=
+for commit in $pending
+do
+ echo "Checking $commit..."
+ mergeDirective=`git log -n 1 --format=%B $commit|grep "^Merge:"|sed "s/Merge: //"`
+ commitMsg=`git log -n 1 --format=oneline --abbrev-commit $commit`
+ if [ "$mergeDirective" == "" ]
+ then
+ pendingCommit=$commit
+ pendingCommitMessage=$pendingCommitMessage"$commitMsg\n"
+ echo pendingCommitMessage: $pendingCommitMessage
+ elif [ "$mergeDirective" == "no" ]
+ then
+ maybe_commit_and_push $pendingCommit "$pendingCommitMessage"
+ pendingCommit=
+ pendingCommitMessage=
+ echo
+ echo "Doing a no-op merge because of Merge: no for $commit"
+ git log -n 1 --format=%B $commit
+ echo
+ # Do a no-op merge
+ git merge $commit -s ours
+ echo -e "No-op merge from $FROM_HEAD\n\n$commitMsg"|git commit --amend -F -
+ pushMerged
+ elif [ "$mergeDirective" == "manual" ]
+ then
+ maybe_commit_and_push $pendingCommit "$pendingCommitMessage"
+ pendingCommit=
+ pendingCommitMessage=
+ echo
+ echo "Stopping merge at $commit (merge: manual)"
+ echo "The following commit must be manually merged."
+ show $commit
+ exit 3
+ else
+ maybe_commit_and_push $pendingCommit "$pendingCommitMessage"
+ pendingCommit=
+ pendingCommitMessage=
+ echo
+ echo "Commit $commit contains an unknown merge directive, Merge: $mergeDirective"
+ echo "Stopping merge."
+ show $commit
+ exit 3
+ fi
+done
+
+# Push any pending merges
+maybe_commit_and_push $pendingCommit "$pendingCommitMessage"
diff --git a/server/build.xml b/server/build.xml
index 91526dd1c5..d61f412883 100644
--- a/server/build.xml
+++ b/server/build.xml
@@ -13,7 +13,7 @@
<property name="module.symbolic" value="com.vaadin.server" />
<property name="result.dir" value="result" />
<path id="classpath.compile.custom" />
- <path id="classpath.tests.custom" />
+ <path id="classpath.test.custom" />
<union id="jar.includes">
<union refid="server.gwt.includes" />
@@ -51,8 +51,8 @@
</antcall>
</target>
- <target name="tests" depends="checkstyle">
- <antcall target="common.tests.run" />
+ <target name="test" depends="checkstyle">
+ <antcall target="common.test.run" />
</target>
diff --git a/server/ivy.xml b/server/ivy.xml
index 6911a7054f..46d9e4c9f5 100644
--- a/server/ivy.xml
+++ b/server/ivy.xml
@@ -11,7 +11,7 @@
<conf name="build" />
<conf name="build-provided" />
<conf name="ide" visibility="private" />
- <conf name="tests" visibility="private" />
+ <conf name="test" visibility="private" />
</configurations>
<publications>
<artifact type="jar" ext="jar" />
@@ -27,47 +27,55 @@
rev="6.0.2" conf="build-provided,ide -> default" />
<!--Servlet API version 2.4 -->
<dependency org="javax.servlet" name="servlet-api"
- rev="2.4" conf="build-provided,ide,tests -> default" />
+ rev="2.4" conf="build-provided,ide,test -> default" />
<!--Portlet API version 2.0 (JSR-286) -->
<dependency org="javax.portlet" name="portlet-api"
- rev="2.0" conf="build-provided,ide,tests -> default" />
+ rev="2.0" conf="build-provided,ide,test -> default" />
<!-- Google App Engine -->
<dependency org="com.google.appengine" name="appengine-api-1.0-sdk"
- rev="1.2.1" conf="build-provided,ide,tests -> default" />
+ rev="1.2.1" conf="build-provided,ide,test -> default" />
<dependency org="javax.validation" name="validation-api"
- rev="1.0.0.GA" conf="build-provided,ide,tests -> default" />
+ rev="1.0.0.GA" conf="build-provided,ide,test -> default" />
<!-- LIBRARY DEPENDENCIES (compile time) -->
<!-- Project modules -->
<dependency org="com.vaadin" name="vaadin-shared"
- rev="${vaadin.version}" conf="build,tests" />
+ rev="${vaadin.version}" conf="build,test->build" />
<dependency org="com.vaadin" name="vaadin-theme-compiler"
- rev="${vaadin.version}" conf="build,tests" />
+ rev="${vaadin.version}" conf="build,test->build" />
+ <dependency org="com.vaadin" name="vaadin-push"
+ rev="${vaadin.version}" conf="build-provided,test->build" />
<!-- Jsoup for BootstrapHandler -->
<dependency org="org.jsoup" name="jsoup" rev="1.6.3"
- conf="build,ide,tests -> default" />
+ conf="build,ide,test -> default" />
<!-- TESTING DEPENDENCIES -->
<!-- Test frameworks & related -->
<dependency org="junit" name="junit" rev="4.5"
- conf="tests,ide -> default" />
+ conf="test,ide -> default" />
<dependency org="org.easymock" name="easymock" rev="3.0"
- conf="tests,ide-> default" transitive="true" />
+ conf="test,ide-> default" transitive="true" />
<dependency org="org.hsqldb" name="hsqldb" rev="2.2.6"
- conf="tests,ide -> default" />
- <dependency org="commons-io" name="commons-io" rev="1.4"
- conf="tests->default" />
+ conf="test,ide -> default" />
+ <dependency org="commons-io" name="commons-io" rev="2.2"
+ conf="test->default" />
<dependency org="commons-lang" name="commons-lang"
- rev="2.6" conf="tests,ide->default" />
+ rev="2.6" conf="test,ide->default" />
<!-- Bean Validation implementation -->
<dependency org="org.slf4j" name="slf4j-log4j12" rev="1.6.1"
- conf="tests -> default" />
+ conf="test -> default" />
<dependency org="org.hibernate" name="hibernate-validator"
- rev="4.2.0.Final" conf="tests -> default" />
+ rev="4.2.0.Final" conf="test -> default" />
+
+ <!-- For manual testing with PostgreSQL (see SQLTestConstants) -->
+ <!--
+ <dependency org="postgresql" name="postgresql"
+ rev="9.1-901.jdbc3" conf="test,ide->default" />
+ -->
</dependencies>
diff --git a/server/src/com/vaadin/annotations/Push.java b/server/src/com/vaadin/annotations/Push.java
new file mode 100644
index 0000000000..58e70acf21
--- /dev/null
+++ b/server/src/com/vaadin/annotations/Push.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.ui.UI;
+
+/**
+ * Configures server push for a {@link UI}. Adding <code>@Push</code> to a UI
+ * class configures the UI for automatic push. If some other push mode is
+ * desired, it can be passed as a parameter, e.g.
+ * <code>@Push(PushMode.MANUAL)</code>.
+ *
+ * @see PushMode
+ *
+ * @author Vaadin Ltd.
+ * @since 7.1
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Push {
+ /**
+ * Returns the {@link PushMode} to use for the annotated UI. The default
+ * push mode when this annotation is present is {@link PushMode#AUTOMATIC}.
+ *
+ * @return the push mode to use
+ */
+ public PushMode value() default PushMode.AUTOMATIC;
+
+}
diff --git a/server/src/com/vaadin/data/Container.java b/server/src/com/vaadin/data/Container.java
index ddeac62d6d..e93db52a35 100644
--- a/server/src/com/vaadin/data/Container.java
+++ b/server/src/com/vaadin/data/Container.java
@@ -953,6 +953,15 @@ public interface Container extends Serializable {
*/
public void removeAllContainerFilters();
+ /**
+ * Returns the filters which have been applied to the container
+ *
+ * @return A collection of filters which have been applied to the
+ * container. An empty collection if no filters have been
+ * applied.
+ * @since 7.1
+ */
+ public Collection<Filter> getContainerFilters();
}
/**
diff --git a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
index 9dc6037d83..0b4e3a8049 100644
--- a/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
+++ b/server/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java
@@ -58,6 +58,23 @@ public class BeanFieldGroup<T> extends FieldGroup {
}
}
+ @Override
+ protected Object findPropertyId(java.lang.reflect.Field memberField) {
+ String fieldName = memberField.getName();
+ Item dataSource = getItemDataSource();
+ if (dataSource != null && dataSource.getItemProperty(fieldName) != null) {
+ return fieldName;
+ } else {
+ String minifiedFieldName = minifyFieldName(fieldName);
+ try {
+ return getFieldName(beanType, minifiedFieldName);
+ } catch (SecurityException e) {
+ } catch (NoSuchFieldException e) {
+ }
+ }
+ return null;
+ }
+
private static java.lang.reflect.Field getField(Class<?> cls,
String propertyId) throws SecurityException, NoSuchFieldException {
if (propertyId.contains(".")) {
@@ -75,7 +92,7 @@ public class BeanFieldGroup<T> extends FieldGroup {
} catch (NoSuchFieldException e) {
// Try super classes until we reach Object
Class<?> superClass = cls.getSuperclass();
- if (superClass != Object.class) {
+ if (superClass != null && superClass != Object.class) {
return getField(superClass, propertyId);
} else {
throw e;
@@ -84,6 +101,22 @@ public class BeanFieldGroup<T> extends FieldGroup {
}
}
+ private static String getFieldName(Class<?> cls, String propertyId)
+ throws SecurityException, NoSuchFieldException {
+ for (java.lang.reflect.Field field1 : cls.getDeclaredFields()) {
+ if (propertyId.equals(minifyFieldName(field1.getName()))) {
+ return field1.getName();
+ }
+ }
+ // Try super classes until we reach Object
+ Class<?> superClass = cls.getSuperclass();
+ if (superClass != null && superClass != Object.class) {
+ return getFieldName(superClass, propertyId);
+ } else {
+ throw new NoSuchFieldException();
+ }
+ }
+
/**
* Helper method for setting the data source directly using a bean. This
* method wraps the bean in a {@link BeanItem} and calls
@@ -176,4 +209,4 @@ public class BeanFieldGroup<T> extends FieldGroup {
}
return beanValidationImplementationAvailable;
}
-} \ No newline at end of file
+}
diff --git a/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java b/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java
index 9ced6588f5..c1e4b4933e 100644
--- a/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java
+++ b/server/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java
@@ -15,18 +15,23 @@
*/
package com.vaadin.data.fieldgroup;
+import java.util.Date;
import java.util.EnumSet;
import com.vaadin.data.Item;
import com.vaadin.data.fieldgroup.FieldGroup.BindException;
+import com.vaadin.ui.AbstractField;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.AbstractTextField;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.DateField;
import com.vaadin.ui.Field;
+import com.vaadin.ui.InlineDateField;
import com.vaadin.ui.ListSelect;
import com.vaadin.ui.NativeSelect;
import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.PopupDateField;
import com.vaadin.ui.RichTextArea;
import com.vaadin.ui.Table;
import com.vaadin.ui.TextField;
@@ -39,6 +44,8 @@ public class DefaultFieldGroupFieldFactory implements FieldGroupFieldFactory {
public <T extends Field> T createField(Class<?> type, Class<T> fieldType) {
if (Enum.class.isAssignableFrom(type)) {
return createEnumField(type, fieldType);
+ } else if (Date.class.isAssignableFrom(type)) {
+ return createDateField(type, fieldType);
} else if (Boolean.class.isAssignableFrom(type)
|| boolean.class.isAssignableFrom(type)) {
return createBooleanField(fieldType);
@@ -70,6 +77,25 @@ public class DefaultFieldGroupFieldFactory implements FieldGroupFieldFactory {
return null;
}
+ private <T extends Field> T createDateField(Class<?> type,
+ Class<T> fieldType) {
+ AbstractField field;
+
+ if (InlineDateField.class.isAssignableFrom(fieldType)) {
+ field = new InlineDateField();
+ } else if (DateField.class.isAssignableFrom(fieldType)
+ || fieldType == Field.class) {
+ field = new PopupDateField();
+ } else if (AbstractTextField.class.isAssignableFrom(fieldType)) {
+ field = createAbstractTextField((Class<? extends AbstractTextField>) fieldType);
+ } else {
+ return null;
+ }
+
+ field.setImmediate(true);
+ return (T) field;
+ }
+
protected AbstractSelect createCompatibleSelect(
Class<? extends AbstractSelect> fieldType) {
AbstractSelect select;
diff --git a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
index dc1fdbb78d..981aea387d 100644
--- a/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
+++ b/server/src/com/vaadin/data/fieldgroup/FieldGroup.java
@@ -733,11 +733,12 @@ public class FieldGroup implements Serializable {
* 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.
+ * {@link Field} and that can be mapped to a property id. Property ids are
+ * searched in the following order: @{@link PropertyId} annotations, exact
+ * field name matches and the case-insensitive matching that ignores
+ * underscores. 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:
@@ -777,11 +778,12 @@ public class FieldGroup implements Serializable {
* 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.
+ * {@link Field} and that can be mapped to a property id. Property ids are
+ * searched in the following order: @{@link PropertyId} annotations, exact
+ * field name matches and the case-insensitive matching that ignores
+ * underscores. 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
@@ -812,7 +814,16 @@ public class FieldGroup implements Serializable {
// @PropertyId(propertyId) always overrides property id
propertyId = propertyIdAnnotation.value();
} else {
- propertyId = memberField.getName();
+ try {
+ propertyId = findPropertyId(memberField);
+ } catch (SearchException e) {
+ // Property id was not found, skip this field
+ continue;
+ }
+ if (propertyId == null) {
+ // Property id was not found, skip this field
+ continue;
+ }
}
// Ensure that the property id exists
@@ -873,6 +884,55 @@ public class FieldGroup implements Serializable {
}
}
+ /**
+ * Searches for a property id from the current itemDataSource that matches
+ * the given memberField.
+ * <p>
+ * If perfect match is not found, uses a case insensitive search that also
+ * ignores underscores. Returns null if no match is found. Throws a
+ * SearchException if no item data source has been set.
+ * </p>
+ * <p>
+ * The propertyId search logic used by
+ * {@link #buildAndBindMemberFields(Object, boolean)
+ * buildAndBindMemberFields} can easily be customized by overriding this
+ * method. No other changes are needed.
+ * </p>
+ *
+ * @param memberField
+ * The field an object id is searched for
+ * @return
+ */
+ protected Object findPropertyId(java.lang.reflect.Field memberField) {
+ String fieldName = memberField.getName();
+ if (getItemDataSource() == null) {
+ throw new SearchException(
+ "Property id type for field '"
+ + fieldName
+ + "' could not be determined. No item data source has been set.");
+ }
+ Item dataSource = getItemDataSource();
+ if (dataSource.getItemProperty(fieldName) != null) {
+ return fieldName;
+ } else {
+ String minifiedFieldName = minifyFieldName(fieldName);
+ for (Object itemPropertyId : dataSource.getItemPropertyIds()) {
+ if (itemPropertyId instanceof String) {
+ String itemPropertyName = (String) itemPropertyId;
+ if (minifiedFieldName
+ .equals(minifyFieldName(itemPropertyName))) {
+ return itemPropertyName;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ protected static String minifyFieldName(String fieldName) {
+ return fieldName.toLowerCase().replace("_", "");
+ }
+
public static class CommitException extends Exception {
public CommitException() {
@@ -909,6 +969,18 @@ public class FieldGroup implements Serializable {
}
+ public static class SearchException extends RuntimeException {
+
+ public SearchException(String message) {
+ super(message);
+ }
+
+ public SearchException(String message, Throwable t) {
+ super(message, t);
+ }
+
+ }
+
/**
* Builds a field and binds it to the given property id using the field
* binder.
diff --git a/server/src/com/vaadin/data/util/AbstractBeanContainer.java b/server/src/com/vaadin/data/util/AbstractBeanContainer.java
index db1e1afe0d..35403d6419 100644
--- a/server/src/com/vaadin/data/util/AbstractBeanContainer.java
+++ b/server/src/com/vaadin/data/util/AbstractBeanContainer.java
@@ -385,6 +385,26 @@ public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends
removeFilter(filter);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.AbstractInMemoryContainer#hasContainerFilters()
+ */
+ @Override
+ public boolean hasContainerFilters() {
+ return super.hasContainerFilters();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.AbstractInMemoryContainer#getContainerFilters()
+ */
+ @Override
+ public Collection<Filter> getContainerFilters() {
+ return super.getContainerFilters();
+ }
+
/**
* Make this container listen to the given property provided it notifies
* when its value changes.
diff --git a/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java b/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java
index 504b4081c1..84304431bc 100644
--- a/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java
+++ b/server/src/com/vaadin/data/util/AbstractInMemoryContainer.java
@@ -501,6 +501,25 @@ public abstract class AbstractInMemoryContainer<ITEMIDTYPE, PROPERTYIDCLASS, ITE
}
/**
+ * Returns true if any filters have been applied to the container.
+ *
+ * @return true if the container has filters applied, false otherwise
+ * @since 7.1
+ */
+ protected boolean hasContainerFilters() {
+ return !getContainerFilters().isEmpty();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.Container.Filterable#getContainerFilters()
+ */
+ protected Collection<Filter> getContainerFilters() {
+ return Collections.unmodifiableCollection(filters);
+ }
+
+ /**
* Remove a specific container filter and re-filter the view (if necessary).
*
* This can be used to implement
diff --git a/server/src/com/vaadin/data/util/AbstractProperty.java b/server/src/com/vaadin/data/util/AbstractProperty.java
index 499421a8b4..903f2f50f2 100644
--- a/server/src/com/vaadin/data/util/AbstractProperty.java
+++ b/server/src/com/vaadin/data/util/AbstractProperty.java
@@ -18,7 +18,6 @@ package com.vaadin.data.util;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
-import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.data.Property;
@@ -71,27 +70,33 @@ public abstract class AbstractProperty<T> implements Property<T>,
}
/**
- * Returns the value of the <code>Property</code> in human readable textual
- * format.
+ * Returns a string representation of this object. The returned string
+ * representation depends on if the legacy Property toString mode is enabled
+ * or disabled.
+ * <p>
+ * If legacy Property toString mode is enabled, returns the value of the
+ * <code>Property</code> converted to a String.
+ * </p>
+ * <p>
+ * If legacy Property toString mode is disabled, the string representation
+ * has no special meaning
+ * </p>
*
- * @return String representation of the value stored in the Property
- * @deprecated As of 7.0, use {@link #getValue()} instead and possibly
- * toString on that
+ * @see LegacyPropertyHelper#isLegacyToStringEnabled()
+ *
+ * @return A string representation of the value value stored in the Property
+ * or a string representation of the Property object.
+ * @deprecated As of 7.0. To get the property value, use {@link #getValue()}
+ * instead (and possibly toString on that)
*/
@Deprecated
@Override
public String toString() {
- getLogger()
- .log(Level.WARNING,
- "You are using Property.toString() instead of getValue() to get the value for a {0}."
- + "This will not be supported starting from Vaadin 7.1 "
- + "(your debugger might call toString() and cause this message to appear).",
- getClass().getSimpleName());
- T v = getValue();
- if (v == null) {
- return null;
+ if (!LegacyPropertyHelper.isLegacyToStringEnabled()) {
+ return super.toString();
+ } else {
+ return LegacyPropertyHelper.legacyPropertyToString(this);
}
- return v.toString();
}
/* Events */
diff --git a/server/src/com/vaadin/data/util/IndexedContainer.java b/server/src/com/vaadin/data/util/IndexedContainer.java
index 1df4dd9bfb..d7bf70caf6 100644
--- a/server/src/com/vaadin/data/util/IndexedContainer.java
+++ b/server/src/com/vaadin/data/util/IndexedContainer.java
@@ -28,7 +28,6 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.data.Container;
@@ -954,29 +953,32 @@ public class IndexedContainer extends
}
/**
- * 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.
+ * Returns a string representation of this object. The returned string
+ * representation depends on if the legacy Property toString mode is
+ * enabled or disabled.
+ * <p>
+ * If legacy Property toString mode is enabled, returns the value of the
+ * <code>Property</code> converted to a String.
+ * </p>
+ * <p>
+ * If legacy Property toString mode is disabled, the string
+ * representation has no special meaning
+ * </p>
*
- * @return <code>String</code> representation of the value stored in the
- * Property
- * @deprecated As of 7.0, use {@link #getValue()} instead and possibly
- * toString on that
+ * @return A string representation of the value value stored in the
+ * Property or a string representation of the Property object.
+ * @deprecated As of 7.0. To get the property value, use
+ * {@link #getValue()} instead (and possibly toString on
+ * that)
*/
@Deprecated
@Override
public String toString() {
- getLogger()
- .log(Level.WARNING,
- "You are using IndexedContainerProperty.toString() instead of getValue() to get the value for a {0}."
- + " This will not be supported starting from Vaadin 7.1 "
- + "(your debugger might call toString() and cause this message to appear).",
- getClass().getSimpleName());
- Object v = getValue();
- if (v == null) {
- return null;
+ if (!LegacyPropertyHelper.isLegacyToStringEnabled()) {
+ return super.toString();
+ } else {
+ return LegacyPropertyHelper.legacyPropertyToString(this);
}
- return v.toString();
}
private Logger getLogger() {
@@ -1190,4 +1192,23 @@ public class IndexedContainer extends
removeFilter(filter);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.AbstractInMemoryContainer#getContainerFilters()
+ */
+ @Override
+ public boolean hasContainerFilters() {
+ return super.hasContainerFilters();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.util.AbstractInMemoryContainer#getContainerFilters()
+ */
+ @Override
+ public Collection<Filter> getContainerFilters() {
+ return super.getContainerFilters();
+ }
}
diff --git a/server/src/com/vaadin/data/util/LegacyPropertyHelper.java b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java
new file mode 100644
index 0000000000..0276e35dbf
--- /dev/null
+++ b/server/src/com/vaadin/data/util/LegacyPropertyHelper.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.util;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.vaadin.data.Property;
+import com.vaadin.server.Constants;
+import com.vaadin.server.DeploymentConfiguration.LegacyProperyToStringMode;
+import com.vaadin.server.VaadinService;
+
+/**
+ * Helper class which provides methods for handling Property.toString in a
+ * Vaadin 6 compatible way
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ * @deprecated This is only used internally for backwards compatibility
+ */
+@Deprecated
+public class LegacyPropertyHelper {
+
+ /**
+ * Returns the property value converted to a String.
+ *
+ * @param p
+ * The property
+ * @return A string representation of the property value, compatible with
+ * how Property implementations in Vaadin 6 do it
+ */
+ public static String legacyPropertyToString(Property p) {
+ maybeLogLegacyPropertyToStringWarning(p);
+ Object value = p.getValue();
+ if (value == null) {
+ return null;
+ }
+ return value.toString();
+ }
+
+ public static void maybeLogLegacyPropertyToStringWarning(Property p) {
+ if (!logLegacyToStringWarning()) {
+ return;
+ }
+
+ getLogger().log(Level.WARNING,
+ Constants.WARNING_LEGACY_PROPERTY_TOSTRING,
+ p.getClass().getName());
+ }
+
+ /**
+ * Checks if legacy Property.toString() implementation is enabled. The
+ * legacy Property.toString() will return the value of the property somehow
+ * converted to a String. If the legacy mode is disabled, toString() will
+ * return super.toString().
+ * <p>
+ * The legacy toString mode can be toggled using the
+ * "legacyPropertyToString" init parameter
+ * </p>
+ *
+ * @return true if legacy Property.toString() mode is enabled, false
+ * otherwise
+ */
+ public static boolean isLegacyToStringEnabled() {
+ if (VaadinService.getCurrent() == null) {
+ // This should really not happen but we need to handle it somehow.
+ // IF it happens it seems more safe to use the legacy mode and log.
+ return true;
+ }
+ return VaadinService.getCurrent().getDeploymentConfiguration()
+ .getLegacyPropertyToStringMode().useLegacyMode();
+ }
+
+ private static boolean logLegacyToStringWarning() {
+ if (VaadinService.getCurrent() == null) {
+ // This should really not happen but we need to handle it somehow.
+ // IF it happens it seems more safe to use the legacy mode and log.
+ return true;
+ }
+ return VaadinService.getCurrent().getDeploymentConfiguration()
+ .getLegacyPropertyToStringMode() == LegacyProperyToStringMode.WARNING;
+
+ }
+
+ private static Logger getLogger() {
+ return Logger.getLogger(LegacyPropertyHelper.class.getName());
+ }
+
+}
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java b/server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
index 378372d044..d8448a2b50 100644
--- a/server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
+++ b/server/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java
@@ -18,10 +18,10 @@ package com.vaadin.data.util.sqlcontainer;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
-import java.util.logging.Level;
import java.util.logging.Logger;
import com.vaadin.data.Property;
+import com.vaadin.data.util.LegacyPropertyHelper;
import com.vaadin.data.util.converter.Converter.ConversionException;
/**
@@ -255,26 +255,33 @@ final public class ColumnProperty implements Property {
}
/**
- * Returns the value of the Property in human readable textual format.
+ * Returns a string representation of this object. The returned string
+ * representation depends on if the legacy Property toString mode is enabled
+ * or disabled.
+ * <p>
+ * If legacy Property toString mode is enabled, returns the value of this
+ * <code>Property</code> converted to a String.
+ * </p>
+ * <p>
+ * If legacy Property toString mode is disabled, the string representation
+ * has no special meaning
+ * </p>
*
- * @see java.lang.Object#toString()
- * @deprecated As of 7.0, use {@link #getValue()} instead and possibly
- * toString on that
+ * @see LegacyPropertyHelper#isLegacyToStringEnabled()
+ *
+ * @return A string representation of the value value stored in the Property
+ * or a string representation of the Property object.
+ * @deprecated As of 7.0. To get the property value, use {@link #getValue()}
+ * instead (and possibly toString on that)
*/
@Deprecated
@Override
public String toString() {
- getLogger()
- .log(Level.WARNING,
- "You are using ColumnProperty.toString() instead of getValue() to get the value for a {0}. "
- + "This will not be supported starting from Vaadin 7.1 (your debugger might call toString() "
- + "and cause this message to appear).",
- getClass().getSimpleName());
- Object v = getValue();
- if (v == null) {
- return null;
+ if (!LegacyPropertyHelper.isLegacyToStringEnabled()) {
+ return super.toString();
+ } else {
+ return LegacyPropertyHelper.legacyPropertyToString(this);
}
- return v.toString();
}
private static Logger getLogger() {
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
index 64c16b2798..987466cdb7 100644
--- a/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
+++ b/server/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java
@@ -590,13 +590,32 @@ public class SQLContainer implements Container, Container.Filterable,
/**
* {@inheritDoc}
*/
-
@Override
public void removeAllContainerFilters() {
filters.clear();
refresh();
}
+ /**
+ * Returns true if any filters have been applied to the container.
+ *
+ * @return true if the container has filters applied, false otherwise
+ * @since 7.1
+ */
+ public boolean hasContainerFilters() {
+ return !getContainerFilters().isEmpty();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.data.Container.Filterable#getContainerFilters()
+ */
+ @Override
+ public Collection<Filter> getContainerFilters() {
+ return Collections.unmodifiableCollection(filters);
+ }
+
/**********************************************/
/** Methods from interface Container.Indexed **/
/**********************************************/
@@ -1818,4 +1837,5 @@ public class SQLContainer implements Container, Container.Filterable,
private static final Logger getLogger() {
return Logger.getLogger(SQLContainer.class.getName());
}
+
}
diff --git a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java
index caed5526e3..39c8365076 100644
--- a/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java
+++ b/server/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java
@@ -50,9 +50,23 @@ import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper;
public class TableQuery extends AbstractTransactionalQuery implements
QueryDelegate, QueryDelegate.RowIdChangeNotifier {
- /** Table name, primary key column name(s) and version column name */
+ /**
+ * Table name (without catalog or schema information).
+ */
private String tableName;
+ private String catalogName;
+ private String schemaName;
+ /**
+ * Cached concatenated version of the table name.
+ */
+ private String fullTableName;
+ /**
+ * Primary key column name(s) in the table.
+ */
private List<String> primaryKeyColumns;
+ /**
+ * Version column name in the table.
+ */
private String versionColumn;
/** Currently set Filters and OrderBys */
@@ -70,15 +84,15 @@ public class TableQuery extends AbstractTransactionalQuery implements
/** Set to true to output generated SQL Queries to System.out */
private final boolean debug = false;
- /** Prevent no-parameters instantiation of TableQuery */
- @SuppressWarnings("unused")
- private TableQuery() {
- }
-
/**
* Creates a new TableQuery using the given connection pool, SQL generator
* and table name to fetch the data from. All parameters must be non-null.
*
+ * The table name must be a simple name with no catalog or schema
+ * information. If those are needed, use
+ * {@link #TableQuery(String, String, String, JDBCConnectionPool, SQLGenerator)}
+ * .
+ *
* @param tableName
* Name of the database table to connect to
* @param connectionPool
@@ -88,15 +102,30 @@ public class TableQuery extends AbstractTransactionalQuery implements
*/
public TableQuery(String tableName, JDBCConnectionPool connectionPool,
SQLGenerator sqlGenerator) {
- super(connectionPool);
- if (tableName == null || tableName.trim().length() < 1
- || connectionPool == null || sqlGenerator == null) {
- throw new IllegalArgumentException(
- "All parameters must be non-null and a table name must be given.");
- }
- this.tableName = tableName;
- this.sqlGenerator = sqlGenerator;
- fetchMetaData();
+ this(null, null, tableName, connectionPool, sqlGenerator);
+ }
+
+ /**
+ * Creates a new TableQuery using the given connection pool, SQL generator
+ * and table name to fetch the data from. Catalog and schema names can be
+ * null, all other parameters must be non-null.
+ *
+ * @param catalogName
+ * Name of the database catalog (can be null)
+ * @param schemaName
+ * Name of the database schema (can be null)
+ * @param tableName
+ * Name of the database table to connect to
+ * @param connectionPool
+ * Connection pool for accessing the database
+ * @param sqlGenerator
+ * SQL query generator implementation
+ * @since 7.1
+ */
+ public TableQuery(String catalogName, String schemaName, String tableName,
+ JDBCConnectionPool connectionPool, SQLGenerator sqlGenerator) {
+ this(catalogName, schemaName, tableName, connectionPool, sqlGenerator,
+ true);
}
/**
@@ -104,6 +133,11 @@ public class TableQuery extends AbstractTransactionalQuery implements
* to fetch the data from. All parameters must be non-null. The default SQL
* generator will be used for queries.
*
+ * The table name must be a simple name with no catalog or schema
+ * information. If those are needed, use
+ * {@link #TableQuery(String, String, String, JDBCConnectionPool, SQLGenerator)}
+ * .
+ *
* @param tableName
* Name of the database table to connect to
* @param connectionPool
@@ -113,6 +147,48 @@ public class TableQuery extends AbstractTransactionalQuery implements
this(tableName, connectionPool, new DefaultSQLGenerator());
}
+ /**
+ * Creates a new TableQuery using the given connection pool, SQL generator
+ * and table name to fetch the data from. Catalog and schema names can be
+ * null, all other parameters must be non-null.
+ *
+ * @param catalogName
+ * Name of the database catalog (can be null)
+ * @param schemaName
+ * Name of the database schema (can be null)
+ * @param tableName
+ * Name of the database table to connect to
+ * @param connectionPool
+ * Connection pool for accessing the database
+ * @param sqlGenerator
+ * SQL query generator implementation
+ * @param escapeNames
+ * true to escape special characters in catalog, schema and table
+ * names, false to use the names as-is
+ * @since 7.1
+ */
+ protected TableQuery(String catalogName, String schemaName,
+ String tableName, JDBCConnectionPool connectionPool,
+ SQLGenerator sqlGenerator, boolean escapeNames) {
+ super(connectionPool);
+ if (tableName == null || tableName.trim().length() < 1
+ || connectionPool == null || sqlGenerator == null) {
+ throw new IllegalArgumentException(
+ "Table name, connection pool and SQL generator parameters must be non-null and non-empty.");
+ }
+ if (escapeNames) {
+ this.catalogName = SQLUtil.escapeSQL(catalogName);
+ this.schemaName = SQLUtil.escapeSQL(schemaName);
+ this.tableName = SQLUtil.escapeSQL(tableName);
+ } else {
+ this.catalogName = catalogName;
+ this.schemaName = schemaName;
+ this.tableName = tableName;
+ }
+ this.sqlGenerator = sqlGenerator;
+ fetchMetaData();
+ }
+
/*
* (non-Javadoc)
*
@@ -121,8 +197,8 @@ public class TableQuery extends AbstractTransactionalQuery implements
@Override
public int getCount() throws SQLException {
getLogger().log(Level.FINE, "Fetching count...");
- StatementHelper sh = sqlGenerator.generateSelectQuery(tableName,
- filters, null, 0, 0, "COUNT(*)");
+ StatementHelper sh = sqlGenerator.generateSelectQuery(
+ getFullTableName(), filters, null, 0, 0, "COUNT(*)");
boolean shouldCloseTransaction = false;
if (!isInTransaction()) {
shouldCloseTransaction = true;
@@ -167,11 +243,11 @@ public class TableQuery extends AbstractTransactionalQuery implements
for (int i = 0; i < primaryKeyColumns.size(); i++) {
ob.add(new OrderBy(primaryKeyColumns.get(i), true));
}
- sh = sqlGenerator.generateSelectQuery(tableName, filters, ob,
- offset, pagelength, null);
+ sh = sqlGenerator.generateSelectQuery(getFullTableName(), filters,
+ ob, offset, pagelength, null);
} else {
- sh = sqlGenerator.generateSelectQuery(tableName, filters, orderBys,
- offset, pagelength, null);
+ sh = sqlGenerator.generateSelectQuery(getFullTableName(), filters,
+ orderBys, offset, pagelength, null);
}
return executeQuery(sh);
}
@@ -204,11 +280,11 @@ public class TableQuery extends AbstractTransactionalQuery implements
int result = 0;
if (row.getId() instanceof TemporaryRowId) {
setVersionColumnFlagInProperty(row);
- sh = sqlGenerator.generateInsertQuery(tableName, row);
+ sh = sqlGenerator.generateInsertQuery(getFullTableName(), row);
result = executeUpdateReturnKeys(sh, row);
} else {
setVersionColumnFlagInProperty(row);
- sh = sqlGenerator.generateUpdateQuery(tableName, row);
+ sh = sqlGenerator.generateUpdateQuery(getFullTableName(), row);
result = executeUpdate(sh);
}
if (versionColumn != null && result == 0) {
@@ -244,7 +320,8 @@ public class TableQuery extends AbstractTransactionalQuery implements
/* Set version column, if one is provided */
setVersionColumnFlagInProperty(row);
/* Generate query */
- StatementHelper sh = sqlGenerator.generateInsertQuery(tableName, row);
+ StatementHelper sh = sqlGenerator.generateInsertQuery(
+ getFullTableName(), row);
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet generatedKeys = null;
@@ -371,10 +448,61 @@ public class TableQuery extends AbstractTransactionalQuery implements
versionColumn = column;
}
+ /**
+ * Returns the table name for the query without catalog and schema
+ * information.
+ *
+ * @return table name, not null
+ */
public String getTableName() {
return tableName;
}
+ /**
+ * Returns the catalog name for the query.
+ *
+ * @return catalog name, can be null
+ * @since 7.1
+ */
+ public String getCatalogName() {
+ return catalogName;
+ }
+
+ /**
+ * Returns the catalog name for the query.
+ *
+ * @return catalog name, can be null
+ * @since 7.1
+ */
+ public String getSchemaName() {
+ return schemaName;
+ }
+
+ /**
+ * Returns the complete table name obtained by concatenation of the catalog
+ * and schema names (if any) and the table name.
+ *
+ * This method can be overridden if customization is needed.
+ *
+ * @return table name in the form it should be used in query and update
+ * statements
+ * @since 7.1
+ */
+ protected String getFullTableName() {
+ if (fullTableName == null) {
+ StringBuilder sb = new StringBuilder();
+ if (catalogName != null) {
+ sb.append(catalogName).append(".");
+ }
+ if (schemaName != null) {
+ sb.append(schemaName).append(".");
+ }
+ sb.append(tableName);
+ fullTableName = sb.toString();
+ }
+ return fullTableName;
+ }
+
public SQLGenerator getSqlGenerator() {
return sqlGenerator;
}
@@ -480,22 +608,28 @@ public class TableQuery extends AbstractTransactionalQuery implements
connection = getConnection();
DatabaseMetaData dbmd = connection.getMetaData();
if (dbmd != null) {
- tableName = SQLUtil.escapeSQL(tableName);
- tables = dbmd.getTables(null, null, tableName, null);
+ tables = dbmd.getTables(catalogName, schemaName, tableName,
+ null);
if (!tables.next()) {
- tables = dbmd.getTables(null, null,
+ String catalog = (catalogName != null) ? catalogName
+ .toUpperCase() : null;
+ String schema = (schemaName != null) ? schemaName
+ .toUpperCase() : null;
+ tables = dbmd.getTables(catalog, schema,
tableName.toUpperCase(), null);
if (!tables.next()) {
throw new IllegalArgumentException(
"Table with the name \""
- + tableName
+ + getFullTableName()
+ "\" was not found. Check your database contents.");
} else {
+ catalogName = catalog;
+ schemaName = schema;
tableName = tableName.toUpperCase();
}
}
tables.close();
- rs = dbmd.getPrimaryKeys(null, null, tableName);
+ rs = dbmd.getPrimaryKeys(catalogName, schemaName, tableName);
List<String> names = new ArrayList<String>();
while (rs.next()) {
names.add(rs.getString("COLUMN_NAME"));
@@ -507,7 +641,7 @@ public class TableQuery extends AbstractTransactionalQuery implements
if (primaryKeyColumns == null || primaryKeyColumns.isEmpty()) {
throw new IllegalArgumentException(
"Primary key constraints have not been defined for the table \""
- + tableName
+ + getFullTableName()
+ "\". Use FreeFormQuery to access this table.");
}
for (String colName : primaryKeyColumns) {
@@ -592,7 +726,7 @@ public class TableQuery extends AbstractTransactionalQuery implements
getLogger().log(Level.FINE, "Removing row with id: {0}",
row.getId().getId()[0]);
}
- if (executeUpdate(sqlGenerator.generateDeleteQuery(getTableName(),
+ if (executeUpdate(sqlGenerator.generateDeleteQuery(getFullTableName(),
primaryKeyColumns, versionColumn, row)) == 1) {
return true;
}
@@ -622,8 +756,8 @@ public class TableQuery extends AbstractTransactionalQuery implements
filtersAndKeys.add(new Equal(colName, keys[ix]));
ix++;
}
- StatementHelper sh = sqlGenerator.generateSelectQuery(tableName,
- filtersAndKeys, orderBys, 0, 0, "*");
+ StatementHelper sh = sqlGenerator.generateSelectQuery(
+ getFullTableName(), filtersAndKeys, orderBys, 0, 0, "*");
boolean shouldCloseTransaction = false;
if (!isInTransaction()) {
diff --git a/server/src/com/vaadin/server/AbstractClientConnector.java b/server/src/com/vaadin/server/AbstractClientConnector.java
index cf579585ea..e998b8ed55 100644
--- a/server/src/com/vaadin/server/AbstractClientConnector.java
+++ b/server/src/com/vaadin/server/AbstractClientConnector.java
@@ -134,6 +134,7 @@ public abstract class AbstractClientConnector implements ClientConnector,
/* Documentation copied from interface */
@Override
public void markAsDirty() {
+ assert getSession() == null || getSession().hasLock() : "Session must be locked when markAsDirty() is called";
UI uI = getUI();
if (uI != null) {
uI.getConnectorTracker().markDirty(this);
@@ -218,6 +219,8 @@ public abstract class AbstractClientConnector implements ClientConnector,
* @see #getState()
*/
protected SharedState getState(boolean markAsDirty) {
+ assert getSession() == null || getSession().hasLock() : "Session must be locked when getState() is called";
+
if (null == sharedState) {
sharedState = createState();
}
@@ -233,7 +236,7 @@ public abstract class AbstractClientConnector implements ClientConnector,
@Override
public JSONObject encodeState() throws JSONException {
- return AbstractCommunicationManager.encodeState(this, getState());
+ return LegacyCommunicationManager.encodeState(this, getState());
}
/**
@@ -642,17 +645,22 @@ public abstract class AbstractClientConnector implements ClientConnector,
@Override
public boolean handleConnectorRequest(VaadinRequest request,
VaadinResponse response, String path) throws IOException {
+ DownloadStream stream = null;
String[] parts = path.split("/", 2);
String key = parts[0];
- ConnectorResource resource = (ConnectorResource) getResource(key);
- if (resource != null) {
- DownloadStream stream = resource.getStream();
- stream.writeResponse(request, response);
- return true;
- } else {
- return false;
+ getSession().lock();
+ try {
+ ConnectorResource resource = (ConnectorResource) getResource(key);
+ if (resource == null) {
+ return false;
+ }
+ stream = resource.getStream();
+ } finally {
+ getSession().unlock();
}
+ stream.writeResponse(request, response);
+ return true;
}
/**
diff --git a/server/src/com/vaadin/server/AbstractCommunicationManager.java b/server/src/com/vaadin/server/AbstractCommunicationManager.java
deleted file mode 100644
index 17bbbda737..0000000000
--- a/server/src/com/vaadin/server/AbstractCommunicationManager.java
+++ /dev/null
@@ -1,2881 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.server;
-
-import java.io.BufferedWriter;
-import java.io.ByteArrayOutputStream;
-import java.io.CharArrayWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Serializable;
-import java.io.StringWriter;
-import java.lang.reflect.Type;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.security.GeneralSecurityException;
-import java.text.CharacterIterator;
-import java.text.DateFormat;
-import java.text.DateFormatSymbols;
-import java.text.SimpleDateFormat;
-import java.text.StringCharacterIterator;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.GregorianCalendar;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.http.HttpServletResponse;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.vaadin.annotations.JavaScript;
-import com.vaadin.annotations.PreserveOnRefresh;
-import com.vaadin.annotations.StyleSheet;
-import com.vaadin.server.ClientConnector.ConnectorErrorEvent;
-import com.vaadin.server.ComponentSizeValidator.InvalidLayout;
-import com.vaadin.server.ServerRpcManager.RpcInvocationException;
-import com.vaadin.server.StreamVariable.StreamingEndEvent;
-import com.vaadin.server.StreamVariable.StreamingErrorEvent;
-import com.vaadin.shared.ApplicationConstants;
-import com.vaadin.shared.Connector;
-import com.vaadin.shared.JavaScriptConnectorState;
-import com.vaadin.shared.Version;
-import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
-import com.vaadin.shared.communication.MethodInvocation;
-import com.vaadin.shared.communication.ServerRpc;
-import com.vaadin.shared.communication.SharedState;
-import com.vaadin.shared.communication.UidlValue;
-import com.vaadin.shared.ui.ui.UIConstants;
-import com.vaadin.ui.Component;
-import com.vaadin.ui.ConnectorTracker;
-import com.vaadin.ui.HasComponents;
-import com.vaadin.ui.LegacyComponent;
-import com.vaadin.ui.SelectiveRenderer;
-import com.vaadin.ui.UI;
-import com.vaadin.ui.Window;
-
-/**
- * This is a common base class for the server-side implementations of the
- * communication system between the client code (compiled with GWT into
- * JavaScript) and the server side components. Its client side counterpart is
- * {@link com.vaadin.client.ApplicationConnection}.
- * <p>
- * TODO Document better!
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future version
- */
-@Deprecated
-@SuppressWarnings("serial")
-public abstract class AbstractCommunicationManager implements Serializable {
-
- private static final String DASHDASH = "--";
-
- private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler();
-
- private static final RequestHandler CONNECTOR_RESOURCE_HANDLER = new ConnectorResourceHandler();
-
- /**
- * TODO Document me!
- *
- * @author peholmst
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
- */
- @Deprecated
- public interface Callback extends Serializable {
-
- public void criticalNotification(VaadinRequest request,
- VaadinResponse response, String cap, String msg,
- String details, String outOfSyncURL) throws IOException;
- }
-
- static class UploadInterruptedException extends Exception {
- public UploadInterruptedException() {
- super("Upload interrupted by other thread");
- }
- }
-
- // flag used in the request to indicate that the security token should be
- // written to the response
- private static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken";
-
- /* Variable records indexes */
- public static final char VAR_BURST_SEPARATOR = '\u001d';
-
- public static final char VAR_ESCAPE_CHARACTER = '\u001b';
-
- private final HashMap<Integer, ClientCache> uiToClientCache = new HashMap<Integer, ClientCache>();
-
- private static final int MAX_BUFFER_SIZE = 64 * 1024;
-
- /* Same as in apache commons file upload library that was previously used. */
- private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024;
-
- /**
- * The session this communication manager is used for
- */
- private final VaadinSession session;
-
- private List<String> locales;
-
- private int pendingLocalesIndex;
-
- private int timeoutInterval = -1;
-
- private DragAndDropService dragAndDropService;
-
- private String requestThemeName;
-
- private int maxInactiveInterval;
-
- private ClientConnector highlightedConnector;
-
- private Map<String, Class<?>> publishedFileContexts = new HashMap<String, Class<?>>();
-
- /**
- * TODO New constructor - document me!
- *
- * @param session
- */
- public AbstractCommunicationManager(VaadinSession session) {
- this.session = session;
- session.addRequestHandler(getBootstrapHandler());
- session.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER);
- session.addRequestHandler(CONNECTOR_RESOURCE_HANDLER);
- requireLocale(session.getLocale().toString());
- }
-
- protected VaadinSession getSession() {
- return session;
- }
-
- private static final int LF = "\n".getBytes()[0];
-
- private static final String CRLF = "\r\n";
-
- private static final String UTF8 = "UTF-8";
-
- private static String readLine(InputStream stream) throws IOException {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- int readByte = stream.read();
- while (readByte != LF) {
- bout.write(readByte);
- readByte = stream.read();
- }
- byte[] bytes = bout.toByteArray();
- return new String(bytes, 0, bytes.length - 1, UTF8);
- }
-
- /**
- * Method used to stream content from a multipart request (either from
- * servlet or portlet request) to given StreamVariable
- *
- *
- * @param request
- * @param response
- * @param streamVariable
- * @param owner
- * @param boundary
- * @throws IOException
- */
- protected void doHandleSimpleMultipartFileUpload(VaadinRequest request,
- VaadinResponse response, StreamVariable streamVariable,
- String variableName, ClientConnector owner, String boundary)
- throws IOException {
- // multipart parsing, supports only one file for request, but that is
- // fine for our current terminal
-
- final InputStream inputStream = request.getInputStream();
-
- int contentLength = request.getContentLength();
-
- boolean atStart = false;
- boolean firstFileFieldFound = false;
-
- String rawfilename = "unknown";
- String rawMimeType = "application/octet-stream";
-
- /*
- * Read the stream until the actual file starts (empty line). Read
- * filename and content type from multipart headers.
- */
- while (!atStart) {
- String readLine = readLine(inputStream);
- contentLength -= (readLine.getBytes(UTF8).length + CRLF.length());
- if (readLine.startsWith("Content-Disposition:")
- && readLine.indexOf("filename=") > 0) {
- rawfilename = readLine.replaceAll(".*filename=", "");
- char quote = rawfilename.charAt(0);
- rawfilename = rawfilename.substring(1);
- rawfilename = rawfilename.substring(0,
- rawfilename.indexOf(quote));
- firstFileFieldFound = true;
- } else if (firstFileFieldFound && readLine.equals("")) {
- atStart = true;
- } else if (readLine.startsWith("Content-Type")) {
- rawMimeType = readLine.split(": ")[1];
- }
- }
-
- contentLength -= (boundary.length() + CRLF.length() + 2
- * DASHDASH.length() + CRLF.length());
-
- /*
- * Reads bytes from the underlying stream. Compares the read bytes to
- * the boundary string and returns -1 if met.
- *
- * The matching happens so that if the read byte equals to the first
- * char of boundary string, the stream goes to "buffering mode". In
- * buffering mode bytes are read until the character does not match the
- * corresponding from boundary string or the full boundary string is
- * found.
- *
- * Note, if this is someday needed elsewhere, don't shoot yourself to
- * foot and split to a top level helper class.
- */
- InputStream simpleMultiPartReader = new SimpleMultiPartInputStream(
- inputStream, boundary);
-
- /*
- * Should report only the filename even if the browser sends the path
- */
- final String filename = removePath(rawfilename);
- final String mimeType = rawMimeType;
-
- try {
- // TODO Shouldn't this check connectorEnabled?
- if (owner == null) {
- throw new UploadException(
- "File upload ignored because the connector for the stream variable was not found");
- }
- if (owner instanceof Component) {
- if (((Component) owner).isReadOnly()) {
- throw new UploadException(
- "Warning: file upload ignored because the componente was read-only");
- }
- }
- boolean forgetVariable = streamToReceiver(simpleMultiPartReader,
- streamVariable, filename, mimeType, contentLength);
- if (forgetVariable) {
- cleanStreamVariable(owner, variableName);
- }
- } catch (Exception e) {
- session.lock();
- try {
- handleConnectorRelatedException(owner, e);
- } finally {
- session.unlock();
- }
- }
- sendUploadResponse(request, response);
-
- }
-
- /**
- * Used to stream plain file post (aka XHR2.post(File))
- *
- * @param request
- * @param response
- * @param streamVariable
- * @param owner
- * @param contentLength
- * @throws IOException
- */
- protected void doHandleXhrFilePost(VaadinRequest request,
- VaadinResponse response, StreamVariable streamVariable,
- String variableName, ClientConnector owner, int contentLength)
- throws IOException {
-
- // These are unknown in filexhr ATM, maybe add to Accept header that
- // is accessible in portlets
- final String filename = "unknown";
- final String mimeType = filename;
- final InputStream stream = request.getInputStream();
- try {
- /*
- * safe cast as in GWT terminal all variable owners are expected to
- * be components.
- */
- Component component = (Component) owner;
- if (component.isReadOnly()) {
- throw new UploadException(
- "Warning: file upload ignored because the component was read-only");
- }
- boolean forgetVariable = streamToReceiver(stream, streamVariable,
- filename, mimeType, contentLength);
- if (forgetVariable) {
- cleanStreamVariable(owner, variableName);
- }
- } catch (Exception e) {
- session.lock();
- try {
- handleConnectorRelatedException(owner, e);
- } finally {
- session.unlock();
- }
- }
- sendUploadResponse(request, response);
- }
-
- /**
- * @param in
- * @param streamVariable
- * @param filename
- * @param type
- * @param contentLength
- * @return true if the streamvariable has informed that the terminal can
- * forget this variable
- * @throws UploadException
- */
- protected final boolean streamToReceiver(final InputStream in,
- StreamVariable streamVariable, String filename, String type,
- int contentLength) throws UploadException {
- if (streamVariable == null) {
- throw new IllegalStateException(
- "StreamVariable for the post not found");
- }
-
- final VaadinSession session = getSession();
-
- OutputStream out = null;
- int totalBytes = 0;
- StreamingStartEventImpl startedEvent = new StreamingStartEventImpl(
- filename, type, contentLength);
- try {
- boolean listenProgress;
- session.lock();
- try {
- streamVariable.streamingStarted(startedEvent);
- out = streamVariable.getOutputStream();
- listenProgress = streamVariable.listenProgress();
- } finally {
- session.unlock();
- }
-
- // Gets the output target stream
- if (out == null) {
- throw new NoOutputStreamException();
- }
-
- if (null == in) {
- // No file, for instance non-existent filename in html upload
- throw new NoInputStreamException();
- }
-
- final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE];
- int bytesReadToBuffer = 0;
- while ((bytesReadToBuffer = in.read(buffer)) > 0) {
- out.write(buffer, 0, bytesReadToBuffer);
- totalBytes += bytesReadToBuffer;
- if (listenProgress) {
- // update progress if listener set and contentLength
- // received
- session.lock();
- try {
- StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl(
- filename, type, contentLength, totalBytes);
- streamVariable.onProgress(progressEvent);
- } finally {
- session.unlock();
- }
- }
- if (streamVariable.isInterrupted()) {
- throw new UploadInterruptedException();
- }
- }
-
- // upload successful
- out.close();
- StreamingEndEvent event = new StreamingEndEventImpl(filename, type,
- totalBytes);
- session.lock();
- try {
- streamVariable.streamingFinished(event);
- } finally {
- session.unlock();
- }
-
- } catch (UploadInterruptedException e) {
- // Download interrupted by application code
- tryToCloseStream(out);
- StreamingErrorEvent event = new StreamingErrorEventImpl(filename,
- type, contentLength, totalBytes, e);
- session.lock();
- try {
- streamVariable.streamingFailed(event);
- } finally {
- session.unlock();
- }
- // Note, we are not throwing interrupted exception forward as it is
- // not a terminal level error like all other exception.
- } catch (final Exception e) {
- tryToCloseStream(out);
- session.lock();
- try {
- StreamingErrorEvent event = new StreamingErrorEventImpl(
- filename, type, contentLength, totalBytes, e);
- streamVariable.streamingFailed(event);
- // throw exception for terminal to be handled (to be passed to
- // terminalErrorHandler)
- throw new UploadException(e);
- } finally {
- session.unlock();
- }
- }
- return startedEvent.isDisposed();
- }
-
- static void tryToCloseStream(OutputStream out) {
- try {
- // try to close output stream (e.g. file handle)
- if (out != null) {
- out.close();
- }
- } catch (IOException e1) {
- // NOP
- }
- }
-
- /**
- * Removes any possible path information from the filename and returns the
- * filename. Separators / and \\ are used.
- *
- * @param name
- * @return
- */
- private static String removePath(String filename) {
- if (filename != null) {
- filename = filename.replaceAll("^.*[/\\\\]", "");
- }
-
- return filename;
- }
-
- /**
- * TODO document
- *
- * @param request
- * @param response
- * @throws IOException
- */
- protected void sendUploadResponse(VaadinRequest request,
- VaadinResponse response) throws IOException {
- response.setContentType("text/html");
- final OutputStream out = response.getOutputStream();
- final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
- new OutputStreamWriter(out, "UTF-8")));
- outWriter.print("<html><body>download handled</body></html>");
- outWriter.flush();
- out.close();
- }
-
- /**
- * Internally process a UIDL request from the client.
- *
- * This method calls
- * {@link #handleVariables(VaadinRequest, VaadinResponse, Callback, VaadinSession, UI)}
- * to process any changes to variables by the client and then repaints
- * affected components using {@link #paintAfterVariableChanges()}.
- *
- * Also, some cleanup is done when a request arrives for an session that has
- * already been closed.
- *
- * The method handleUidlRequest(...) in subclasses should call this method.
- *
- * TODO better documentation
- *
- * @param request
- * @param response
- * @param callback
- * @param uI
- * target window for the UIDL request, can be null if target not
- * found
- * @throws IOException
- * @throws InvalidUIDLSecurityKeyException
- * @throws JSONException
- */
- public void handleUidlRequest(VaadinRequest request,
- VaadinResponse response, Callback callback, UI uI)
- throws IOException, InvalidUIDLSecurityKeyException, JSONException {
-
- checkWidgetsetVersion(request);
- requestThemeName = request.getParameter("theme");
- maxInactiveInterval = request.getWrappedSession()
- .getMaxInactiveInterval();
- // repaint requested or session has timed out and new one is created
- boolean repaintAll;
- final OutputStream out;
-
- repaintAll = (request
- .getParameter(ApplicationConstants.URL_PARAMETER_REPAINT_ALL) != null);
- // || (request.getSession().isNew()); FIXME What the h*ll is this??
- out = response.getOutputStream();
-
- boolean analyzeLayouts = false;
- if (repaintAll) {
- // analyzing can be done only with repaintAll
- analyzeLayouts = (request
- .getParameter(ApplicationConstants.PARAM_ANALYZE_LAYOUTS) != null);
-
- String pid = request
- .getParameter(ApplicationConstants.PARAM_HIGHLIGHT_CONNECTOR);
- if (pid != null) {
- highlightedConnector = uI.getConnectorTracker().getConnector(
- pid);
- highlightConnector(highlightedConnector);
- }
- }
-
- final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
- new OutputStreamWriter(out, "UTF-8")));
-
- // The rest of the process is synchronized with the session
- // in order to guarantee that no parallel variable handling is
- // made
- session.lock();
- try {
-
- // Verify that there's an UI
- if (uI == null) {
- // This should not happen, no windows exists but
- // session is still open.
- getLogger().warning("Could not get UI for session");
- return;
- }
-
- session.setLastRequestTimestamp(System.currentTimeMillis());
-
- // Change all variables based on request parameters
- if (!handleVariables(request, response, callback, session, uI)) {
-
- // var inconsistency; the client is probably out-of-sync
- SystemMessages ci = response.getService().getSystemMessages(
- uI.getLocale(), request);
- String msg = ci.getOutOfSyncMessage();
- String cap = ci.getOutOfSyncCaption();
- if (msg != null || cap != null) {
- callback.criticalNotification(request, response, cap, msg,
- null, ci.getOutOfSyncURL());
- // will reload page after this
- return;
- }
- // No message to show, let's just repaint all.
- repaintAll = true;
- }
-
- paintAfterVariableChanges(request, response, callback, repaintAll,
- outWriter, uI, analyzeLayouts);
- postPaint(uI);
- } finally {
- session.unlock();
- }
-
- outWriter.close();
- requestThemeName = null;
- }
-
- /**
- * Checks that the version reported by the client (widgetset) matches that
- * of the server.
- *
- * @param request
- */
- private void checkWidgetsetVersion(VaadinRequest request) {
- String widgetsetVersion = request.getParameter("v-wsver");
- if (widgetsetVersion == null) {
- // Only check when the widgetset version is reported. It is reported
- // in the first UIDL request (not the initial request as it is a
- // plain GET /)
- return;
- }
-
- if (!Version.getFullVersion().equals(widgetsetVersion)) {
- getLogger().warning(
- String.format(Constants.WIDGETSET_MISMATCH_INFO,
- Version.getFullVersion(), widgetsetVersion));
- }
- }
-
- /**
- * Method called after the paint phase while still being synchronized on the
- * session
- *
- * @param uI
- *
- */
- protected void postPaint(UI uI) {
- // Remove connectors that have been detached from the session during
- // handling of the request
- uI.getConnectorTracker().cleanConnectorMap();
- }
-
- protected void highlightConnector(ClientConnector highlightedConnector) {
- StringBuilder sb = new StringBuilder();
- sb.append("*** Debug details of a connector: *** \n");
- sb.append("Type: ");
- sb.append(highlightedConnector.getClass().getName());
- sb.append("\nId:");
- sb.append(highlightedConnector.getConnectorId());
- if (highlightedConnector instanceof Component) {
- Component component = (Component) highlightedConnector;
- if (component.getCaption() != null) {
- sb.append("\nCaption:");
- sb.append(component.getCaption());
- }
- }
- printHighlightedConnectorHierarchy(sb, highlightedConnector);
- getLogger().info(sb.toString());
- }
-
- protected void printHighlightedConnectorHierarchy(StringBuilder sb,
- ClientConnector connector) {
- LinkedList<ClientConnector> h = new LinkedList<ClientConnector>();
- h.add(connector);
- ClientConnector parent = connector.getParent();
- while (parent != null) {
- h.addFirst(parent);
- parent = parent.getParent();
- }
-
- sb.append("\nConnector hierarchy:\n");
- VaadinSession session2 = connector.getUI().getSession();
- sb.append(session2.getClass().getName());
- sb.append("(");
- sb.append(session2.getClass().getSimpleName());
- sb.append(".java");
- sb.append(":1)");
- int l = 1;
- for (ClientConnector connector2 : h) {
- sb.append("\n");
- for (int i = 0; i < l; i++) {
- sb.append(" ");
- }
- l++;
- Class<? extends ClientConnector> connectorClass = connector2
- .getClass();
- Class<?> topClass = connectorClass;
- while (topClass.getEnclosingClass() != null) {
- topClass = topClass.getEnclosingClass();
- }
- sb.append(connectorClass.getName());
- sb.append("(");
- sb.append(topClass.getSimpleName());
- sb.append(".java:1)");
- }
- }
-
- /**
- * TODO document
- *
- * @param request
- * @param response
- * @param callback
- * @param repaintAll
- * @param outWriter
- * @param window
- * @param analyzeLayouts
- * @throws PaintException
- * @throws IOException
- * @throws JSONException
- */
- private void paintAfterVariableChanges(VaadinRequest request,
- VaadinResponse response, Callback callback, boolean repaintAll,
- final PrintWriter outWriter, UI uI, boolean analyzeLayouts)
- throws PaintException, IOException, JSONException {
- openJsonMessage(outWriter, response);
-
- // security key
- Object writeSecurityTokenFlag = request
- .getAttribute(WRITE_SECURITY_TOKEN_FLAG);
-
- if (writeSecurityTokenFlag != null) {
- outWriter.print(getSecurityKeyUIDL(request));
- }
-
- writeUidlResponse(request, repaintAll, outWriter, uI, analyzeLayouts);
-
- closeJsonMessage(outWriter);
-
- outWriter.close();
-
- }
-
- /**
- * 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(VaadinRequest request) {
- final String seckey = getSecurityKey(request);
- if (seckey != null) {
- return "\"" + ApplicationConstants.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(VaadinRequest request) {
- String seckey = null;
- WrappedSession session = request.getWrappedSession();
- seckey = (String) session
- .getAttribute(ApplicationConstants.UIDL_SECURITY_TOKEN_ID);
- if (seckey == null) {
- seckey = UUID.randomUUID().toString();
- session.setAttribute(ApplicationConstants.UIDL_SECURITY_TOKEN_ID,
- seckey);
- }
-
- return seckey;
- }
-
- @SuppressWarnings("unchecked")
- public void writeUidlResponse(VaadinRequest request, boolean repaintAll,
- final PrintWriter outWriter, UI ui, boolean analyzeLayouts)
- throws PaintException, JSONException {
- ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>();
- VaadinSession session = ui.getSession();
- // Paints components
- ConnectorTracker uiConnectorTracker = ui.getConnectorTracker();
- getLogger().log(Level.FINE, "* Creating response to client");
- if (repaintAll) {
- getClientCache(ui).clear();
- uiConnectorTracker.markAllConnectorsDirty();
- uiConnectorTracker.markAllClientSidesUninitialized();
-
- // Reset sent locales
- locales = null;
- requireLocale(session.getLocale().toString());
- }
-
- dirtyVisibleConnectors
- .addAll(getDirtyVisibleConnectors(uiConnectorTracker));
-
- getLogger().log(Level.FINE, "Found {0} dirty connectors to paint",
- dirtyVisibleConnectors.size());
- for (ClientConnector connector : dirtyVisibleConnectors) {
- boolean initialized = uiConnectorTracker
- .isClientSideInitialized(connector);
- connector.beforeClientResponse(!initialized);
- }
-
- uiConnectorTracker.setWritingResponse(true);
- try {
- outWriter.print("\"changes\":[");
-
- List<InvalidLayout> invalidComponentRelativeSizes = null;
-
- JsonPaintTarget paintTarget = new JsonPaintTarget(this, outWriter,
- !repaintAll);
- legacyPaint(paintTarget, dirtyVisibleConnectors);
-
- if (analyzeLayouts) {
- invalidComponentRelativeSizes = ComponentSizeValidator
- .validateComponentRelativeSizes(ui.getContent(), null,
- null);
-
- // Also check any existing subwindows
- if (ui.getWindows() != null) {
- for (Window subWindow : ui.getWindows()) {
- invalidComponentRelativeSizes = ComponentSizeValidator
- .validateComponentRelativeSizes(
- subWindow.getContent(),
- invalidComponentRelativeSizes, null);
- }
- }
- }
-
- paintTarget.close();
- outWriter.print("], "); // close changes
-
- // send shared state to client
-
- // for now, send the complete state of all modified and new
- // components
-
- // Ideally, all this would be sent before "changes", but that causes
- // complications with legacy components that create sub-components
- // in their paint phase. Nevertheless, this will be processed on the
- // client after component creation but before legacy UIDL
- // processing.
- JSONObject sharedStates = new JSONObject();
- for (ClientConnector connector : dirtyVisibleConnectors) {
- // encode and send shared state
- try {
- JSONObject stateJson = connector.encodeState();
-
- if (stateJson != null && stateJson.length() != 0) {
- sharedStates.put(connector.getConnectorId(), stateJson);
- }
- } catch (JSONException e) {
- throw new PaintException(
- "Failed to serialize shared state for connector "
- + connector.getClass().getName() + " ("
- + connector.getConnectorId() + "): "
- + e.getMessage(), e);
- }
- }
- outWriter.print("\"state\":");
- outWriter.append(sharedStates.toString());
- outWriter.print(", "); // close states
-
- // TODO This should be optimized. The type only needs to be
- // sent once for each connector id + on refresh. Use the same cache
- // as
- // widget mapping
-
- JSONObject connectorTypes = new JSONObject();
- for (ClientConnector connector : dirtyVisibleConnectors) {
- String connectorType = paintTarget.getTag(connector);
- try {
- connectorTypes.put(connector.getConnectorId(),
- connectorType);
- } catch (JSONException e) {
- throw new PaintException(
- "Failed to send connector type for connector "
- + connector.getConnectorId() + ": "
- + e.getMessage(), e);
- }
- }
- outWriter.print("\"types\":");
- outWriter.append(connectorTypes.toString());
- outWriter.print(", "); // close states
-
- // Send update hierarchy information to the client.
-
- // This could be optimized aswell to send only info if hierarchy has
- // actually changed. Much like with the shared state. Note though
- // that an empty hierarchy is information aswell (e.g. change from 1
- // child to 0 children)
-
- outWriter.print("\"hierarchy\":");
-
- JSONObject hierarchyInfo = new JSONObject();
- for (ClientConnector connector : dirtyVisibleConnectors) {
- String connectorId = connector.getConnectorId();
- JSONArray children = new JSONArray();
-
- for (ClientConnector child : AbstractClientConnector
- .getAllChildrenIterable(connector)) {
- if (isConnectorVisibleToClient(child)) {
- children.put(child.getConnectorId());
- }
- }
- try {
- hierarchyInfo.put(connectorId, children);
- } catch (JSONException e) {
- throw new PaintException(
- "Failed to send hierarchy information about "
- + connectorId + " to the client: "
- + e.getMessage(), e);
- }
- }
- outWriter.append(hierarchyInfo.toString());
- outWriter.print(", "); // close hierarchy
-
- uiConnectorTracker.markAllConnectorsClean();
-
- // send server to client RPC calls for components in the UI, in call
- // order
-
- // collect RPC calls from components in the UI in the order in
- // which they were performed, remove the calls from components
-
- LinkedList<ClientConnector> rpcPendingQueue = new LinkedList<ClientConnector>(
- dirtyVisibleConnectors);
- List<ClientMethodInvocation> pendingInvocations = collectPendingRpcCalls(dirtyVisibleConnectors);
-
- JSONArray rpcCalls = new JSONArray();
- for (ClientMethodInvocation invocation : pendingInvocations) {
- // add invocation to rpcCalls
- try {
- JSONArray invocationJson = new JSONArray();
- invocationJson.put(invocation.getConnector()
- .getConnectorId());
- invocationJson.put(invocation.getInterfaceName());
- invocationJson.put(invocation.getMethodName());
- JSONArray paramJson = new JSONArray();
- for (int i = 0; i < invocation.getParameterTypes().length; ++i) {
- Type parameterType = invocation.getParameterTypes()[i];
- Object referenceParameter = null;
- // TODO Use default values for RPC parameter types
- // if (!JsonCodec.isInternalType(parameterType)) {
- // try {
- // referenceParameter = parameterType.newInstance();
- // } catch (Exception e) {
- // logger.log(Level.WARNING,
- // "Error creating reference object for parameter of type "
- // + parameterType.getName());
- // }
- // }
- EncodeResult encodeResult = JsonCodec.encode(
- invocation.getParameters()[i],
- referenceParameter, parameterType,
- ui.getConnectorTracker());
- paramJson.put(encodeResult.getEncodedValue());
- }
- invocationJson.put(paramJson);
- rpcCalls.put(invocationJson);
- } catch (JSONException e) {
- throw new PaintException(
- "Failed to serialize RPC method call parameters for connector "
- + invocation.getConnector()
- .getConnectorId() + " method "
- + invocation.getInterfaceName() + "."
- + invocation.getMethodName() + ": "
- + e.getMessage(), e);
- }
-
- }
-
- if (rpcCalls.length() > 0) {
- outWriter.print("\"rpc\" : ");
- outWriter.append(rpcCalls.toString());
- outWriter.print(", "); // close rpc
- }
-
- outWriter.print("\"meta\" : {");
- boolean metaOpen = false;
-
- if (repaintAll) {
- metaOpen = true;
- outWriter.write("\"repaintAll\":true");
- if (analyzeLayouts) {
- outWriter.write(", \"invalidLayouts\":");
- outWriter.write("[");
- if (invalidComponentRelativeSizes != null) {
- boolean first = true;
- for (InvalidLayout invalidLayout : invalidComponentRelativeSizes) {
- if (!first) {
- outWriter.write(",");
- } else {
- first = false;
- }
- invalidLayout.reportErrors(outWriter, this,
- System.err);
- }
- }
- outWriter.write("]");
- }
- if (highlightedConnector != null) {
- outWriter.write(", \"hl\":\"");
- outWriter.write(highlightedConnector.getConnectorId());
- outWriter.write("\"");
- highlightedConnector = null;
- }
- }
-
- SystemMessages ci = request.getService().getSystemMessages(
- ui.getLocale(), request);
-
- // meta instruction for client to enable auto-forward to
- // sessionExpiredURL after timer expires.
- if (ci != null && ci.getSessionExpiredMessage() == null
- && ci.getSessionExpiredCaption() == null
- && ci.isSessionExpiredNotificationEnabled()) {
- int newTimeoutInterval = getTimeoutInterval();
- if (repaintAll || (timeoutInterval != newTimeoutInterval)) {
- String escapedURL = ci.getSessionExpiredURL() == null ? ""
- : ci.getSessionExpiredURL().replace("/", "\\/");
- if (metaOpen) {
- outWriter.write(",");
- }
- outWriter.write("\"timedRedirect\":{\"interval\":"
- + (newTimeoutInterval + 15) + ",\"url\":\""
- + escapedURL + "\"}");
- metaOpen = true;
- }
- timeoutInterval = newTimeoutInterval;
- }
-
- outWriter.print("}, \"resources\" : {");
-
- // Precache custom layouts
-
- // TODO We should only precache the layouts that are not
- // cached already (plagiate from usedPaintableTypes)
- int resourceIndex = 0;
- for (final Iterator<Object> i = paintTarget.getUsedResources()
- .iterator(); i.hasNext();) {
- final String resource = (String) i.next();
- InputStream is = null;
- try {
- is = getThemeResourceAsStream(ui, getTheme(ui), resource);
- } catch (final Exception e) {
- // FIXME: Handle exception
- getLogger().log(Level.FINER,
- "Failed to get theme resource stream.", e);
- }
- if (is != null) {
-
- outWriter.print((resourceIndex++ > 0 ? ", " : "") + "\""
- + resource + "\" : ");
- final StringBuffer layout = new StringBuffer();
-
- try {
- final InputStreamReader r = new InputStreamReader(is,
- "UTF-8");
- final char[] buffer = new char[20000];
- int charsRead = 0;
- while ((charsRead = r.read(buffer)) > 0) {
- layout.append(buffer, 0, charsRead);
- }
- r.close();
- } catch (final java.io.IOException e) {
- // FIXME: Handle exception
- getLogger().log(Level.INFO, "Resource transfer failed",
- e);
- }
- outWriter.print("\""
- + JsonPaintTarget.escapeJSON(layout.toString())
- + "\"");
- } else {
- // FIXME: Handle exception
- getLogger().severe("CustomLayout not found: " + resource);
- }
- }
- outWriter.print("}");
-
- Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget
- .getUsedClientConnectors();
- boolean typeMappingsOpen = false;
- ClientCache clientCache = getClientCache(ui);
-
- List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>();
-
- for (Class<? extends ClientConnector> class1 : usedClientConnectors) {
- if (clientCache.cache(class1)) {
- // client does not know the mapping key for this type, send
- // mapping to client
- newConnectorTypes.add(class1);
-
- if (!typeMappingsOpen) {
- typeMappingsOpen = true;
- outWriter.print(", \"typeMappings\" : { ");
- } else {
- outWriter.print(" , ");
- }
- String canonicalName = class1.getCanonicalName();
- outWriter.print("\"");
- outWriter.print(canonicalName);
- outWriter.print("\" : ");
- outWriter.print(getTagForType(class1));
- }
- }
- if (typeMappingsOpen) {
- outWriter.print(" }");
- }
-
- boolean typeInheritanceMapOpen = false;
- if (typeMappingsOpen) {
- // send the whole type inheritance map if any new mappings
- for (Class<? extends ClientConnector> class1 : usedClientConnectors) {
- if (!ClientConnector.class.isAssignableFrom(class1
- .getSuperclass())) {
- continue;
- }
- if (!typeInheritanceMapOpen) {
- typeInheritanceMapOpen = true;
- outWriter.print(", \"typeInheritanceMap\" : { ");
- } else {
- outWriter.print(" , ");
- }
- outWriter.print("\"");
- outWriter.print(getTagForType(class1));
- outWriter.print("\" : ");
- outWriter
- .print(getTagForType((Class<? extends ClientConnector>) class1
- .getSuperclass()));
- }
- if (typeInheritanceMapOpen) {
- outWriter.print(" }");
- }
- }
-
- /*
- * Ensure super classes come before sub classes to get script
- * dependency order right. Sub class @JavaScript might assume that
- *
- * @JavaScript defined by super class is already loaded.
- */
- Collections.sort(newConnectorTypes, new Comparator<Class<?>>() {
- @Override
- public int compare(Class<?> o1, Class<?> o2) {
- // TODO optimize using Class.isAssignableFrom?
- return hierarchyDepth(o1) - hierarchyDepth(o2);
- }
-
- private int hierarchyDepth(Class<?> type) {
- if (type == Object.class) {
- return 0;
- } else {
- return hierarchyDepth(type.getSuperclass()) + 1;
- }
- }
- });
-
- List<String> scriptDependencies = new ArrayList<String>();
- List<String> styleDependencies = new ArrayList<String>();
-
- for (Class<? extends ClientConnector> class1 : newConnectorTypes) {
- JavaScript jsAnnotation = class1
- .getAnnotation(JavaScript.class);
- if (jsAnnotation != null) {
- for (String uri : jsAnnotation.value()) {
- scriptDependencies.add(registerDependency(uri, class1));
- }
- }
-
- StyleSheet styleAnnotation = class1
- .getAnnotation(StyleSheet.class);
- if (styleAnnotation != null) {
- for (String uri : styleAnnotation.value()) {
- styleDependencies.add(registerDependency(uri, class1));
- }
- }
- }
-
- // Include script dependencies in output if there are any
- if (!scriptDependencies.isEmpty()) {
- outWriter.print(", \"scriptDependencies\": "
- + new JSONArray(scriptDependencies).toString());
- }
-
- // Include style dependencies in output if there are any
- if (!styleDependencies.isEmpty()) {
- outWriter.print(", \"styleDependencies\": "
- + new JSONArray(styleDependencies).toString());
- }
-
- // add any pending locale definitions requested by the client
- printLocaleDeclarations(outWriter);
-
- if (dragAndDropService != null) {
- dragAndDropService.printJSONResponse(outWriter);
- }
-
- for (ClientConnector connector : dirtyVisibleConnectors) {
- uiConnectorTracker.markClientSideInitialized(connector);
- }
-
- assert (uiConnectorTracker.getDirtyConnectors().isEmpty()) : "Connectors have been marked as dirty during the end of the paint phase. This is most certainly not intended.";
-
- writePerformanceData(outWriter);
- } finally {
- uiConnectorTracker.setWritingResponse(false);
- }
- }
-
- public static JSONObject encodeState(ClientConnector connector,
- SharedState state) throws JSONException {
- UI uI = connector.getUI();
- ConnectorTracker connectorTracker = uI.getConnectorTracker();
- Class<? extends SharedState> stateType = connector.getStateType();
- Object diffState = connectorTracker.getDiffState(connector);
- boolean supportsDiffState = !JavaScriptConnectorState.class
- .isAssignableFrom(stateType);
- if (diffState == null && supportsDiffState) {
- // Use an empty state object as reference for full
- // repaints
-
- try {
- SharedState referenceState = stateType.newInstance();
- EncodeResult encodeResult = JsonCodec.encode(referenceState,
- null, stateType, uI.getConnectorTracker());
- diffState = encodeResult.getEncodedValue();
- } catch (Exception e) {
- getLogger()
- .log(Level.WARNING,
- "Error creating reference object for state of type {0}",
- stateType.getName());
- }
- }
- EncodeResult encodeResult = JsonCodec.encode(state, diffState,
- stateType, uI.getConnectorTracker());
- if (supportsDiffState) {
- connectorTracker.setDiffState(connector,
- (JSONObject) encodeResult.getEncodedValue());
- }
- return (JSONObject) encodeResult.getDiff();
- }
-
- /**
- * Resolves a dependency URI, registering the URI with this
- * {@code AbstractCommunicationManager} if needed and returns a fully
- * qualified URI.
- */
- private String registerDependency(String resourceUri, Class<?> context) {
- try {
- URI uri = new URI(resourceUri);
- String protocol = uri.getScheme();
-
- if (ApplicationConstants.PUBLISHED_PROTOCOL_NAME.equals(protocol)) {
- // Strip initial slash
- String resourceName = uri.getPath().substring(1);
- return registerPublishedFile(resourceName, context);
- }
-
- if (protocol != null || uri.getHost() != null) {
- return resourceUri;
- }
-
- // Bare path interpreted as published file
- return registerPublishedFile(resourceUri, context);
- } catch (URISyntaxException e) {
- getLogger().log(Level.WARNING,
- "Could not parse resource url " + resourceUri, e);
- return resourceUri;
- }
- }
-
- private String registerPublishedFile(String name, Class<?> context) {
- synchronized (publishedFileContexts) {
- // Add to map of names accepted by servePublishedFile
- if (publishedFileContexts.containsKey(name)) {
- Class<?> oldContext = publishedFileContexts.get(name);
- if (oldContext != context) {
- getLogger()
- .log(Level.WARNING,
- "{0} published by both {1} and {2}. File from {2} will be used.",
- new Object[] { name, context, oldContext });
- }
- } else {
- publishedFileContexts.put(name, context);
- }
- }
-
- return ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX + "/" + name;
- }
-
- /**
- * Adds the performance timing data (used by TestBench 3) to the UIDL
- * response.
- */
- private void writePerformanceData(final PrintWriter outWriter) {
- outWriter.write(String.format(", \"timings\":[%d, %d]",
- session.getCumulativeRequestDuration(),
- session.getLastRequestDuration()));
- }
-
- private void legacyPaint(PaintTarget paintTarget,
- ArrayList<ClientConnector> dirtyVisibleConnectors)
- throws PaintException {
- List<LegacyComponent> legacyComponents = new ArrayList<LegacyComponent>();
- for (Connector connector : dirtyVisibleConnectors) {
- // All Components that want to use paintContent must implement
- // LegacyComponent
- if (connector instanceof LegacyComponent) {
- legacyComponents.add((LegacyComponent) connector);
- }
- }
- sortByHierarchy((List) legacyComponents);
- for (LegacyComponent c : legacyComponents) {
- if (getLogger().isLoggable(Level.FINE)) {
- getLogger().log(
- Level.FINE,
- "Painting LegacyComponent {0}@{1}",
- new Object[] { c.getClass().getName(),
- Integer.toHexString(c.hashCode()) });
- }
- paintTarget.startTag("change");
- final String pid = c.getConnectorId();
- paintTarget.addAttribute("pid", pid);
- LegacyPaint.paint(c, paintTarget);
- paintTarget.endTag("change");
- }
-
- }
-
- private void sortByHierarchy(List<Component> paintables) {
- // Vaadin 6 requires parents to be painted before children as component
- // containers rely on that their updateFromUIDL method has been called
- // before children start calling e.g. updateCaption
- Collections.sort(paintables, new Comparator<Component>() {
-
- @Override
- public int compare(Component c1, Component c2) {
- int depth1 = 0;
- while (c1.getParent() != null) {
- depth1++;
- c1 = c1.getParent();
- }
- int depth2 = 0;
- while (c2.getParent() != null) {
- depth2++;
- c2 = c2.getParent();
- }
- if (depth1 < depth2) {
- return -1;
- }
- if (depth1 > depth2) {
- return 1;
- }
- return 0;
- }
- });
-
- }
-
- private ClientCache getClientCache(UI uI) {
- Integer uiId = Integer.valueOf(uI.getUIId());
- ClientCache cache = uiToClientCache.get(uiId);
- if (cache == null) {
- cache = new ClientCache();
- uiToClientCache.put(uiId, cache);
- }
- return cache;
- }
-
- /**
- * Checks if the connector is visible in context. For Components,
- * {@link #isComponentVisibleToClient(Component)} is used. For other types
- * of connectors, the contextual visibility of its first Component ancestor
- * is used. If no Component ancestor is found, the connector is not visible.
- *
- * @param connector
- * The connector to check
- * @return <code>true</code> if the connector is visible to the client,
- * <code>false</code> otherwise
- */
- public static boolean isConnectorVisibleToClient(ClientConnector connector) {
- if (connector instanceof Component) {
- return isComponentVisibleToClient((Component) connector);
- } else {
- ClientConnector parent = connector.getParent();
- if (parent == null) {
- return false;
- } else {
- return isConnectorVisibleToClient(parent);
- }
- }
- }
-
- /**
- * Checks if the component should be visible to the client. Returns false if
- * the child should not be sent to the client, true otherwise.
- *
- * @param child
- * The child to check
- * @return true if the child is visible to the client, false otherwise
- */
- public static boolean isComponentVisibleToClient(Component child) {
- if (!child.isVisible()) {
- return false;
- }
- HasComponents parent = child.getParent();
-
- if (parent instanceof SelectiveRenderer) {
- if (!((SelectiveRenderer) parent).isRendered(child)) {
- return false;
- }
- }
-
- if (parent != null) {
- return isComponentVisibleToClient(parent);
- } else {
- if (child instanceof UI) {
- // UI has no parent and visibility was checked above
- return true;
- } else {
- // Component which is not attached to any UI
- return false;
- }
- }
- }
-
- private static class NullIterator<E> implements Iterator<E> {
-
- @Override
- public boolean hasNext() {
- return false;
- }
-
- @Override
- public E next() {
- return null;
- }
-
- @Override
- public void remove() {
- }
-
- }
-
- /**
- * Collects all pending RPC calls from listed {@link ClientConnector}s and
- * clears their RPC queues.
- *
- * @param rpcPendingQueue
- * list of {@link ClientConnector} of interest
- * @return ordered list of pending RPC calls
- */
- private List<ClientMethodInvocation> collectPendingRpcCalls(
- List<ClientConnector> rpcPendingQueue) {
- List<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>();
- for (ClientConnector connector : rpcPendingQueue) {
- List<ClientMethodInvocation> paintablePendingRpc = connector
- .retrievePendingRpcCalls();
- if (null != paintablePendingRpc && !paintablePendingRpc.isEmpty()) {
- List<ClientMethodInvocation> oldPendingRpc = pendingInvocations;
- int totalCalls = pendingInvocations.size()
- + paintablePendingRpc.size();
- pendingInvocations = new ArrayList<ClientMethodInvocation>(
- totalCalls);
-
- // merge two ordered comparable lists
- for (int destIndex = 0, oldIndex = 0, paintableIndex = 0; destIndex < totalCalls; destIndex++) {
- if (paintableIndex >= paintablePendingRpc.size()
- || (oldIndex < oldPendingRpc.size() && ((Comparable<ClientMethodInvocation>) oldPendingRpc
- .get(oldIndex))
- .compareTo(paintablePendingRpc
- .get(paintableIndex)) <= 0)) {
- pendingInvocations.add(oldPendingRpc.get(oldIndex++));
- } else {
- pendingInvocations.add(paintablePendingRpc
- .get(paintableIndex++));
- }
- }
- }
- }
- return pendingInvocations;
- }
-
- protected abstract InputStream getThemeResourceAsStream(UI uI,
- String themeName, String resource);
-
- private int getTimeoutInterval() {
- return maxInactiveInterval;
- }
-
- private String getTheme(UI uI) {
- String themeName = uI.getTheme();
- String requestThemeName = getRequestTheme();
-
- if (requestThemeName != null) {
- themeName = requestThemeName;
- }
- if (themeName == null) {
- themeName = VaadinServlet.getDefaultTheme();
- }
- return themeName;
- }
-
- private String getRequestTheme() {
- return requestThemeName;
- }
-
- /**
- * Returns false if the cross site request forgery protection is turned off.
- *
- * @param session
- * @return false if the XSRF is turned off, true otherwise
- */
- public boolean isXSRFEnabled(VaadinSession session) {
- return session.getConfiguration().isXsrfProtectionEnabled();
- }
-
- /**
- * TODO document
- *
- * If this method returns false, something was submitted that we did not
- * expect; this is probably due to the client being out-of-sync and sending
- * variable changes for non-existing pids
- *
- * @return true if successful, false if there was an inconsistency
- */
- private boolean handleVariables(VaadinRequest request,
- VaadinResponse response, Callback callback, VaadinSession session,
- UI uI) throws IOException, InvalidUIDLSecurityKeyException,
- JSONException {
- boolean success = true;
-
- String changes = getRequestPayload(request);
- if (changes != null) {
-
- // Manage bursts one by one
- final String[] bursts = changes.split(String
- .valueOf(VAR_BURST_SEPARATOR));
-
- // Security: double cookie submission pattern unless disabled by
- // property
- if (isXSRFEnabled(session)) {
- if (bursts.length == 1 && "init".equals(bursts[0])) {
- // init request; don't handle any variables, key sent in
- // response.
- request.setAttribute(WRITE_SECURITY_TOKEN_FLAG, true);
- return true;
- } else {
- // ApplicationServlet has stored the security token in the
- // session; check that it matched the one sent in the UIDL
- String sessId = (String) request
- .getWrappedSession()
- .getAttribute(
- ApplicationConstants.UIDL_SECURITY_TOKEN_ID);
-
- if (sessId == null || !sessId.equals(bursts[0])) {
- throw new InvalidUIDLSecurityKeyException(
- "Security key mismatch");
- }
- }
-
- }
-
- for (int bi = 1; bi < bursts.length; bi++) {
- // unescape any encoded separator characters in the burst
- final String burst = unescapeBurst(bursts[bi]);
- success &= handleBurst(request, uI, burst);
-
- // In case that there were multiple bursts, we know that this is
- // a special synchronous case for closing window. Thus we are
- // not interested in sending any UIDL changes back to client.
- // Still we must clear component tree between bursts to ensure
- // that no removed components are updated. The painting after
- // the last burst is handled normally by the calling method.
- if (bi < bursts.length - 1) {
-
- // We will be discarding all changes
- final PrintWriter outWriter = new PrintWriter(
- new CharArrayWriter());
-
- paintAfterVariableChanges(request, response, callback,
- true, outWriter, uI, false);
-
- }
-
- }
- }
- /*
- * Note that we ignore inconsistencies while handling unload request.
- * The client can't remove invalid variable changes from the burst, and
- * we don't have the required logic implemented on the server side. E.g.
- * a component is removed in a previous burst.
- */
- return success;
- }
-
- /**
- * Processes a message burst received from the client.
- *
- * A burst can contain any number of RPC calls, including legacy variable
- * change calls that are processed separately.
- *
- * Consecutive changes to the value of the same variable are combined and
- * changeVariables() is only called once for them. This preserves the Vaadin
- * 6 semantics for components and add-ons that do not use Vaadin 7 RPC
- * directly.
- *
- * @param source
- * @param uI
- * the UI receiving the burst
- * @param burst
- * the content of the burst as a String to be parsed
- * @return true if the processing of the burst was successful and there were
- * no messages to non-existent components
- */
- public boolean handleBurst(VaadinRequest source, UI uI, final String burst) {
- boolean success = true;
- try {
- Set<Connector> enabledConnectors = new HashSet<Connector>();
-
- List<MethodInvocation> invocations = parseInvocations(
- uI.getConnectorTracker(), burst);
- for (MethodInvocation invocation : invocations) {
- final ClientConnector connector = getConnector(uI,
- invocation.getConnectorId());
-
- if (connector != null && connector.isConnectorEnabled()) {
- enabledConnectors.add(connector);
- }
- }
-
- for (int i = 0; i < invocations.size(); i++) {
- MethodInvocation invocation = invocations.get(i);
-
- final ClientConnector connector = getConnector(uI,
- invocation.getConnectorId());
- if (connector == null) {
- getLogger()
- .log(Level.WARNING,
- "Received RPC call for unknown connector with id {0} (tried to invoke {1}.{2})",
- new Object[] { invocation.getConnectorId(),
- invocation.getInterfaceName(),
- invocation.getMethodName() });
- continue;
- }
-
- if (!enabledConnectors.contains(connector)) {
-
- if (invocation instanceof LegacyChangeVariablesInvocation) {
- LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
- // TODO convert window close to a separate RPC call and
- // handle above - not a variable change
-
- // Handle special case where window-close is called
- // after the window has been removed from the
- // application or the application has closed
- Map<String, Object> changes = legacyInvocation
- .getVariableChanges();
- if (changes.size() == 1 && changes.containsKey("close")
- && Boolean.TRUE.equals(changes.get("close"))) {
- // Silently ignore this
- continue;
- }
- }
-
- // Connector is disabled, log a warning and move to the next
- String msg = "Ignoring RPC call for disabled connector "
- + connector.getClass().getName();
- if (connector instanceof Component) {
- String caption = ((Component) connector).getCaption();
- if (caption != null) {
- msg += ", caption=" + caption;
- }
- }
- getLogger().warning(msg);
- continue;
- }
-
- if (invocation instanceof ServerRpcMethodInvocation) {
- try {
- ServerRpcManager.applyInvocation(connector,
- (ServerRpcMethodInvocation) invocation);
- } catch (RpcInvocationException e) {
- handleConnectorRelatedException(connector, e);
- }
- } else {
-
- // All code below is for legacy variable changes
- LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
- Map<String, Object> changes = legacyInvocation
- .getVariableChanges();
- try {
- if (connector instanceof VariableOwner) {
- changeVariables(source, (VariableOwner) connector,
- changes);
- } else {
- throw new IllegalStateException(
- "Received legacy variable change for "
- + connector.getClass().getName()
- + " ("
- + connector.getConnectorId()
- + ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: "
- + changes.keySet());
- }
- } catch (Exception e) {
- handleConnectorRelatedException(connector, e);
- }
- }
- }
- } catch (JSONException e) {
- getLogger().log(Level.WARNING,
- "Unable to parse RPC call from the client: {0}",
- e.getMessage());
- // TODO or return success = false?
- throw new RuntimeException(e);
- }
-
- return success;
- }
-
- /**
- * Handles an exception that occurred when processing Rpc calls or a file
- * upload.
- *
- * @param ui
- * The UI where the exception occured
- * @param throwable
- * The exception
- * @param connector
- * The Rpc target
- */
- private void handleConnectorRelatedException(ClientConnector connector,
- Throwable throwable) {
- ErrorEvent errorEvent = new ConnectorErrorEvent(connector, throwable);
- ErrorHandler handler = ErrorEvent.findErrorHandler(connector);
- handler.error(errorEvent);
- }
-
- /**
- * Parse a message burst from the client into a list of MethodInvocation
- * instances.
- *
- * @param connectorTracker
- * The ConnectorTracker used to lookup connectors
- * @param burst
- * message string (JSON)
- * @return list of MethodInvocation to perform
- * @throws JSONException
- */
- private List<MethodInvocation> parseInvocations(
- ConnectorTracker connectorTracker, final String burst)
- throws JSONException {
- JSONArray invocationsJson = new JSONArray(burst);
-
- ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>();
-
- MethodInvocation previousInvocation = null;
- // parse JSON to MethodInvocations
- for (int i = 0; i < invocationsJson.length(); ++i) {
-
- JSONArray invocationJson = invocationsJson.getJSONArray(i);
-
- MethodInvocation invocation = parseInvocation(invocationJson,
- previousInvocation, connectorTracker);
- if (invocation != null) {
- // Can be null if the invocation was a legacy invocation and it
- // was merged with the previous one or if the invocation was
- // rejected because of an error.
- invocations.add(invocation);
- previousInvocation = invocation;
- }
- }
- return invocations;
- }
-
- private MethodInvocation parseInvocation(JSONArray invocationJson,
- MethodInvocation previousInvocation,
- ConnectorTracker connectorTracker) throws JSONException {
- String connectorId = invocationJson.getString(0);
- String interfaceName = invocationJson.getString(1);
- String methodName = invocationJson.getString(2);
-
- if (connectorTracker.getConnector(connectorId) == null
- && !connectorId
- .equals(ApplicationConstants.DRAG_AND_DROP_CONNECTOR_ID)) {
- getLogger()
- .log(Level.WARNING,
- "RPC call to "
- + interfaceName
- + "."
- + methodName
- + " received for connector "
- + connectorId
- + " but no such connector could be found. Resynchronizing client.");
- // This is likely an out of sync issue (client tries to update a
- // connector which is not present). Force resync.
- connectorTracker.markAllConnectorsDirty();
- return null;
- }
-
- JSONArray parametersJson = invocationJson.getJSONArray(3);
-
- if (LegacyChangeVariablesInvocation.isLegacyVariableChange(
- interfaceName, methodName)) {
- if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) {
- previousInvocation = null;
- }
-
- return parseLegacyChangeVariablesInvocation(connectorId,
- interfaceName, methodName,
- (LegacyChangeVariablesInvocation) previousInvocation,
- parametersJson, connectorTracker);
- } else {
- return parseServerRpcInvocation(connectorId, interfaceName,
- methodName, parametersJson, connectorTracker);
- }
-
- }
-
- private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation(
- String connectorId, String interfaceName, String methodName,
- LegacyChangeVariablesInvocation previousInvocation,
- JSONArray parametersJson, ConnectorTracker connectorTracker)
- throws JSONException {
- if (parametersJson.length() != 2) {
- throw new JSONException(
- "Invalid parameters in legacy change variables call. Expected 2, was "
- + parametersJson.length());
- }
- String variableName = parametersJson.getString(0);
- UidlValue uidlValue = (UidlValue) JsonCodec.decodeInternalType(
- UidlValue.class, true, parametersJson.get(1), connectorTracker);
-
- Object value = uidlValue.getValue();
-
- if (previousInvocation != null
- && previousInvocation.getConnectorId().equals(connectorId)) {
- previousInvocation.setVariableChange(variableName, value);
- return null;
- } else {
- return new LegacyChangeVariablesInvocation(connectorId,
- variableName, value);
- }
- }
-
- private ServerRpcMethodInvocation parseServerRpcInvocation(
- String connectorId, String interfaceName, String methodName,
- JSONArray parametersJson, ConnectorTracker connectorTracker)
- throws JSONException {
- ClientConnector connector = connectorTracker.getConnector(connectorId);
-
- ServerRpcManager<?> rpcManager = connector.getRpcManager(interfaceName);
- if (rpcManager == null) {
- /*
- * Security: Don't even decode the json parameters if no RpcManager
- * corresponding to the received method invocation has been
- * registered.
- */
- getLogger()
- .log(Level.WARNING,
- "Ignoring RPC call to {0}.{1} in connector {2} ({3}) as no RPC implementation is regsitered",
- new Object[] { interfaceName, methodName,
- connector.getClass().getName(), connectorId });
- return null;
- }
-
- // Use interface from RpcManager instead of loading the class based on
- // the string name to avoid problems with OSGi
- Class<? extends ServerRpc> rpcInterface = rpcManager.getRpcInterface();
-
- ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation(
- connectorId, rpcInterface, methodName, parametersJson.length());
-
- Object[] parameters = new Object[parametersJson.length()];
- Type[] declaredRpcMethodParameterTypes = invocation.getMethod()
- .getGenericParameterTypes();
-
- for (int j = 0; j < parametersJson.length(); ++j) {
- Object parameterValue = parametersJson.get(j);
- Type parameterType = declaredRpcMethodParameterTypes[j];
- parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType,
- parameterValue, connectorTracker);
- }
- invocation.setParameters(parameters);
- return invocation;
- }
-
- protected void changeVariables(Object source, final VariableOwner owner,
- Map<String, Object> m) {
- owner.changeVariables(source, m);
- }
-
- protected ClientConnector getConnector(UI uI, String connectorId) {
- ClientConnector c = uI.getConnectorTracker().getConnector(connectorId);
- if (c == null
- && connectorId.equals(getDragAndDropService().getConnectorId())) {
- return getDragAndDropService();
- }
-
- return c;
- }
-
- private DragAndDropService getDragAndDropService() {
- if (dragAndDropService == null) {
- dragAndDropService = new DragAndDropService(this);
- }
- return dragAndDropService;
- }
-
- /**
- * Reads the request data from the Request and returns it converted to an
- * UTF-8 string.
- *
- * @param request
- * @return
- * @throws IOException
- */
- protected String getRequestPayload(VaadinRequest request)
- throws IOException {
-
- int requestLength = request.getContentLength();
- if (requestLength == 0) {
- return null;
- }
-
- ByteArrayOutputStream bout = requestLength <= 0 ? new ByteArrayOutputStream()
- : new ByteArrayOutputStream(requestLength);
-
- InputStream inputStream = request.getInputStream();
- byte[] buffer = new byte[MAX_BUFFER_SIZE];
-
- while (true) {
- int read = inputStream.read(buffer);
- if (read == -1) {
- break;
- }
- bout.write(buffer, 0, read);
- }
- String result = new String(bout.toByteArray(), "utf-8");
-
- return result;
- }
-
- /**
- * Unescape encoded burst separator characters in a burst received from the
- * client. This protects from separator injection attacks.
- *
- * @param encodedValue
- * to decode
- * @return decoded value
- */
- protected String unescapeBurst(String encodedValue) {
- final StringBuilder result = new StringBuilder();
- final StringCharacterIterator iterator = new StringCharacterIterator(
- encodedValue);
- char character = iterator.current();
- while (character != CharacterIterator.DONE) {
- if (VAR_ESCAPE_CHARACTER == character) {
- character = iterator.next();
- switch (character) {
- case VAR_ESCAPE_CHARACTER + 0x30:
- // escaped escape character
- result.append(VAR_ESCAPE_CHARACTER);
- break;
- case VAR_BURST_SEPARATOR + 0x30:
- // +0x30 makes these letters for easier reading
- result.append((char) (character - 0x30));
- break;
- case CharacterIterator.DONE:
- // error
- throw new RuntimeException(
- "Communication error: Unexpected end of message");
- default:
- // other escaped character - probably a client-server
- // version mismatch
- throw new RuntimeException(
- "Invalid escaped character from the client - check that the widgetset and server versions match");
- }
- } else {
- // not a special character - add it to the result as is
- result.append(character);
- }
- character = iterator.next();
- }
- return result.toString();
- }
-
- /**
- * Prints the queued (pending) locale definitions to a {@link PrintWriter}
- * in a (UIDL) format that can be sent to the client and used there in
- * formatting dates, times etc.
- *
- * @param outWriter
- */
- private void printLocaleDeclarations(PrintWriter outWriter) {
- /*
- * ----------------------------- Sending Locale sensitive date
- * -----------------------------
- */
-
- // Send locale informations to client
- outWriter.print(", \"locales\":[");
- for (; pendingLocalesIndex < locales.size(); pendingLocalesIndex++) {
-
- final Locale l = generateLocale(locales.get(pendingLocalesIndex));
- // Locale name
- outWriter.print("{\"name\":\"" + l.toString() + "\",");
-
- /*
- * Month names (both short and full)
- */
- final DateFormatSymbols dfs = new DateFormatSymbols(l);
- final String[] short_months = dfs.getShortMonths();
- final String[] months = dfs.getMonths();
- outWriter.print("\"smn\":[\""
- + // ShortMonthNames
- short_months[0] + "\",\"" + short_months[1] + "\",\""
- + short_months[2] + "\",\"" + short_months[3] + "\",\""
- + short_months[4] + "\",\"" + short_months[5] + "\",\""
- + short_months[6] + "\",\"" + short_months[7] + "\",\""
- + short_months[8] + "\",\"" + short_months[9] + "\",\""
- + short_months[10] + "\",\"" + short_months[11] + "\""
- + "],");
- outWriter.print("\"mn\":[\""
- + // MonthNames
- months[0] + "\",\"" + months[1] + "\",\"" + months[2]
- + "\",\"" + months[3] + "\",\"" + months[4] + "\",\""
- + months[5] + "\",\"" + months[6] + "\",\"" + months[7]
- + "\",\"" + months[8] + "\",\"" + months[9] + "\",\""
- + months[10] + "\",\"" + months[11] + "\"" + "],");
-
- /*
- * Weekday names (both short and full)
- */
- final String[] short_days = dfs.getShortWeekdays();
- final String[] days = dfs.getWeekdays();
- outWriter.print("\"sdn\":[\""
- + // ShortDayNames
- short_days[1] + "\",\"" + short_days[2] + "\",\""
- + short_days[3] + "\",\"" + short_days[4] + "\",\""
- + short_days[5] + "\",\"" + short_days[6] + "\",\""
- + short_days[7] + "\"" + "],");
- outWriter.print("\"dn\":[\""
- + // DayNames
- days[1] + "\",\"" + days[2] + "\",\"" + days[3] + "\",\""
- + days[4] + "\",\"" + days[5] + "\",\"" + days[6] + "\",\""
- + days[7] + "\"" + "],");
-
- /*
- * First day of week (0 = sunday, 1 = monday)
- */
- final Calendar cal = new GregorianCalendar(l);
- outWriter.print("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ",");
-
- /*
- * Date formatting (MM/DD/YYYY etc.)
- */
-
- DateFormat dateFormat = DateFormat.getDateTimeInstance(
- DateFormat.SHORT, DateFormat.SHORT, l);
- if (!(dateFormat instanceof SimpleDateFormat)) {
- getLogger().log(Level.WARNING,
- "Unable to get default date pattern for locale {0}", l);
- dateFormat = new SimpleDateFormat();
- }
- final String df = ((SimpleDateFormat) dateFormat).toPattern();
-
- int timeStart = df.indexOf("H");
- if (timeStart < 0) {
- timeStart = df.indexOf("h");
- }
- final int ampm_first = df.indexOf("a");
- // E.g. in Korean locale AM/PM is before h:mm
- // TODO should take that into consideration on client-side as well,
- // now always h:mm a
- if (ampm_first > 0 && ampm_first < timeStart) {
- timeStart = ampm_first;
- }
- // Hebrew locale has time before the date
- final boolean timeFirst = timeStart == 0;
- String dateformat;
- if (timeFirst) {
- int dateStart = df.indexOf(' ');
- if (ampm_first > dateStart) {
- dateStart = df.indexOf(' ', ampm_first);
- }
- dateformat = df.substring(dateStart + 1);
- } else {
- dateformat = df.substring(0, timeStart - 1);
- }
-
- outWriter.print("\"df\":\"" + dateformat.trim() + "\",");
-
- /*
- * Time formatting (24 or 12 hour clock and AM/PM suffixes)
- */
- final String timeformat = df.substring(timeStart, df.length());
- /*
- * Doesn't return second or milliseconds.
- *
- * We use timeformat to determine 12/24-hour clock
- */
- final boolean twelve_hour_clock = timeformat.indexOf("a") > -1;
- // TODO there are other possibilities as well, like 'h' in french
- // (ignore them, too complicated)
- final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "."
- : ":";
- // outWriter.print("\"tf\":\"" + timeformat + "\",");
- outWriter.print("\"thc\":" + twelve_hour_clock + ",");
- outWriter.print("\"hmd\":\"" + hour_min_delimiter + "\"");
- if (twelve_hour_clock) {
- final String[] ampm = dfs.getAmPmStrings();
- outWriter.print(",\"ampm\":[\"" + ampm[0] + "\",\"" + ampm[1]
- + "\"]");
- }
- outWriter.print("}");
- if (pendingLocalesIndex < locales.size() - 1) {
- outWriter.print(",");
- }
- }
- outWriter.print("]"); // Close locales
- }
-
- protected void closeJsonMessage(PrintWriter outWriter) {
- outWriter.print("}]");
- }
-
- /**
- * Writes the opening of JSON message to be sent to client.
- *
- * @param outWriter
- * @param response
- */
- protected void openJsonMessage(PrintWriter outWriter,
- VaadinResponse response) {
- // Sets the response type
- response.setContentType("application/json; charset=UTF-8");
- // some dirt to prevent cross site scripting
- outWriter.print("for(;;);[{");
- }
-
- /**
- * Returns dirty components which are in given window. Components in an
- * invisible subtrees are omitted.
- *
- * @param w
- * UI window for which dirty components is to be fetched
- * @return
- */
- private ArrayList<ClientConnector> getDirtyVisibleConnectors(
- ConnectorTracker connectorTracker) {
- ArrayList<ClientConnector> dirtyConnectors = new ArrayList<ClientConnector>();
- for (ClientConnector c : connectorTracker.getDirtyConnectors()) {
- if (isConnectorVisibleToClient(c)) {
- dirtyConnectors.add(c);
- }
- }
-
- return dirtyConnectors;
- }
-
- /**
- * 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
- * the need to use the {@link Locale} class and all the framework behind it
- * on the client.
- *
- * @see Locale#toString()
- *
- * @param value
- */
- public void requireLocale(String value) {
- if (locales == null) {
- locales = new ArrayList<String>();
- locales.add(session.getLocale().toString());
- pendingLocalesIndex = 0;
- }
- if (!locales.contains(value)) {
- locales.add(value);
- }
- }
-
- /**
- * Constructs a {@link Locale} instance to be sent to the client based on a
- * short locale description string.
- *
- * @see #requireLocale(String)
- *
- * @param value
- * @return
- */
- private Locale generateLocale(String value) {
- final String[] temp = value.split("_");
- if (temp.length == 1) {
- return new Locale(temp[0]);
- } else if (temp.length == 2) {
- return new Locale(temp[0], temp[1]);
- } else {
- return new Locale(temp[0], temp[1], temp[2]);
- }
- }
-
- protected class InvalidUIDLSecurityKeyException extends
- GeneralSecurityException {
-
- InvalidUIDLSecurityKeyException(String message) {
- super(message);
- }
-
- }
-
- private final HashMap<Class<? extends ClientConnector>, Integer> typeToKey = new HashMap<Class<? extends ClientConnector>, Integer>();
- private int nextTypeKey = 0;
-
- private BootstrapHandler bootstrapHandler;
-
- String getTagForType(Class<? extends ClientConnector> class1) {
- Integer id = typeToKey.get(class1);
- if (id == null) {
- id = nextTypeKey++;
- typeToKey.put(class1, id);
- if (getLogger().isLoggable(Level.FINE)) {
- getLogger().log(Level.FINE, "Mapping {0} to {1}",
- new Object[] { class1.getName(), id });
- }
- }
- return id.toString();
- }
-
- /**
- * Helper class for terminal to keep track of data that client is expected
- * to know.
- *
- * TODO make customlayout templates (from theme) to be cached here.
- */
- class ClientCache implements Serializable {
-
- private final Set<Object> res = new HashSet<Object>();
-
- /**
- *
- * @param paintable
- * @return true if the given class was added to cache
- */
- boolean cache(Object object) {
- return res.add(object);
- }
-
- public void clear() {
- res.clear();
- }
-
- }
-
- public String getStreamVariableTargetUrl(ClientConnector owner,
- String name, StreamVariable value) {
- /*
- * We will use the same APP/* URI space as ApplicationResources but
- * prefix url with UPLOAD
- *
- * eg. APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY]
- *
- * SECKEY is created on each paint to make URL's unpredictable (to
- * prevent CSRF attacks).
- *
- * NAME and PID from URI forms a key to fetch StreamVariable when
- * handling post
- */
- String paintableId = owner.getConnectorId();
- UI ui = owner.getUI();
- int uiId = ui.getUIId();
- String key = uiId + "/" + paintableId + "/" + name;
-
- ConnectorTracker connectorTracker = ui.getConnectorTracker();
- connectorTracker.addStreamVariable(paintableId, name, value);
- String seckey = connectorTracker.getSeckey(value);
-
- return ApplicationConstants.APP_PROTOCOL_PREFIX
- + ServletPortletHelper.UPLOAD_URL_PREFIX + key + "/" + seckey;
-
- }
-
- public void cleanStreamVariable(ClientConnector owner, String name) {
- owner.getUI().getConnectorTracker()
- .cleanStreamVariable(owner.getConnectorId(), 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;
- }
-
- /**
- * @return
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
- */
- @Deprecated
- protected abstract BootstrapHandler createBootstrapHandler();
-
- /**
- * 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 VaadinServlet}).
- * <p>
- * The request handlers are invoked in the revere order in which they were
- * added to the session 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 session is invoked towards the end unless
- * any previous handler has already produced a response.
- * </p>
- *
- * @param request
- * the Vaadin 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
- * if a handler throws an exception
- *
- * @see VaadinSession#addRequestHandler(RequestHandler)
- * @see RequestHandler
- *
- * @since 7.0
- */
- protected boolean handleOtherRequest(VaadinRequest request,
- VaadinResponse response) throws IOException {
- // Use a copy to avoid ConcurrentModificationException
- for (RequestHandler handler : new ArrayList<RequestHandler>(
- session.getRequestHandlers())) {
- if (handler.handleRequest(session, request, response)) {
- return true;
- }
- }
- // If not handled
- return false;
- }
-
- public void handleBrowserDetailsRequest(VaadinRequest request,
- VaadinResponse response, VaadinSession session) throws IOException {
-
- session.lock();
-
- try {
- assert UI.getCurrent() == null;
-
- response.setContentType("application/json; charset=UTF-8");
-
- UI uI = getBrowserDetailsUI(request, session);
-
- JSONObject params = new JSONObject();
- params.put(UIConstants.UI_ID_PARAMETER, uI.getUIId());
- String initialUIDL = getInitialUIDL(request, uI);
- params.put("uidl", initialUIDL);
-
- // NOTE! GateIn requires, for some weird reason, getOutputStream
- // to be used instead of getWriter() (it seems to interpret
- // application/json as a binary content type)
- final OutputStream out = response.getOutputStream();
- final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
- new OutputStreamWriter(out, "UTF-8")));
-
- outWriter.write(params.toString());
- // NOTE GateIn requires the buffers to be flushed to work
- outWriter.flush();
- out.flush();
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- session.unlock();
- }
- }
-
- private UI getBrowserDetailsUI(VaadinRequest request, VaadinSession session) {
- VaadinService vaadinService = request.getService();
-
- List<UIProvider> uiProviders = session.getUIProviders();
-
- UIClassSelectionEvent classSelectionEvent = new UIClassSelectionEvent(
- request);
-
- UIProvider provider = null;
- Class<? extends UI> uiClass = null;
- for (UIProvider p : uiProviders) {
- // Check for existing LegacyWindow
- if (p instanceof LegacyApplicationUIProvider) {
- LegacyApplicationUIProvider legacyProvider = (LegacyApplicationUIProvider) p;
-
- UI existingUi = legacyProvider
- .getExistingUI(classSelectionEvent);
- if (existingUi != null) {
- reinitUI(existingUi, request);
- return existingUi;
- }
- }
-
- uiClass = p.getUIClass(classSelectionEvent);
- if (uiClass != null) {
- provider = p;
- break;
- }
- }
-
- if (provider == null || uiClass == null) {
- return null;
- }
-
- // Check for an existing UI based on window.name
-
- // Special parameter sent by vaadinBootstrap.js
- String windowName = request.getParameter("v-wn");
-
- Map<String, Integer> retainOnRefreshUIs = session
- .getPreserveOnRefreshUIs();
- if (windowName != null && !retainOnRefreshUIs.isEmpty()) {
- // Check for a known UI
-
- Integer retainedUIId = retainOnRefreshUIs.get(windowName);
-
- if (retainedUIId != null) {
- UI retainedUI = session.getUIById(retainedUIId.intValue());
- if (uiClass.isInstance(retainedUI)) {
- reinitUI(retainedUI, request);
- return retainedUI;
- } else {
- getLogger().log(
- Level.INFO,
- "Not using retained UI in {0} because retained UI was of type {1}"
- + " but {2} is expected for the request.",
- new Object[] { windowName, retainedUI.getClass(),
- uiClass });
- }
- }
- }
-
- // No existing UI found - go on by creating and initializing one
-
- Integer uiId = Integer.valueOf(session.getNextUIid());
-
- // Explicit Class.cast to detect if the UIProvider does something
- // unexpected
- UICreateEvent event = new UICreateEvent(request, uiClass, uiId);
- UI ui = uiClass.cast(provider.createInstance(event));
-
- // Initialize some fields for a newly created UI
- if (ui.getSession() != session) {
- // Session already set for LegacyWindow
- ui.setSession(session);
- }
-
- // Set thread local here so it is available in init
- UI.setCurrent(ui);
-
- ui.doInit(request, uiId.intValue());
-
- session.addUI(ui);
-
- // Remember if it should be remembered
- if (vaadinService.preserveUIOnRefresh(provider, event)) {
- // Remember this UI
- if (windowName == null) {
- getLogger()
- .log(Level.WARNING,
- "There is no window.name available for UI {0} that should be preserved.",
- uiClass);
- } else {
- session.getPreserveOnRefreshUIs().put(windowName, uiId);
- }
- }
-
- return ui;
- }
-
- /**
- * Updates a UI that has already been initialized but is now loaded again,
- * e.g. because of {@link PreserveOnRefresh}.
- *
- * @param ui
- * @param request
- */
- private void reinitUI(UI ui, VaadinRequest request) {
- UI.setCurrent(ui);
-
- // Fire fragment change if the fragment has changed
- String location = request.getParameter("v-loc");
- if (location != null) {
- ui.getPage().updateLocation(location);
- }
- }
-
- /**
- * 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 uI
- * the UI for which the UIDL should be generated
- * @return a string with the initial UIDL message
- * @throws PaintException
- * if an exception occurs while painting
- * @throws JSONException
- * if an exception occurs while encoding output
- */
- protected String getInitialUIDL(VaadinRequest request, UI uI)
- throws PaintException, JSONException {
- // TODO maybe unify writeUidlResponse()?
- StringWriter sWriter = new StringWriter();
- PrintWriter pWriter = new PrintWriter(sWriter);
- pWriter.print("{");
- if (isXSRFEnabled(uI.getSession())) {
- pWriter.print(getSecurityKeyUIDL(request));
- }
- writeUidlResponse(request, true, pWriter, uI, false);
- pWriter.print("}");
- String initialUIDL = sWriter.toString();
- getLogger().log(Level.FINE, "Initial UIDL:{0}", initialUIDL);
- return initialUIDL;
- }
-
- /**
- * Serve a connector resource from the classpath if the resource has
- * previously been registered by calling
- * {@link #registerPublishedFile(String, Class)}. Sending arbitrary files
- * from the classpath is prevented by only accepting resource names that
- * have explicitly been registered. Resources can currently only be
- * registered by including a {@link JavaScript} or {@link StyleSheet}
- * annotation on a Connector class.
- *
- * @param request
- * @param response
- *
- * @throws IOException
- */
- public void servePublishedFile(VaadinRequest request,
- VaadinResponse response) throws IOException {
-
- String pathInfo = request.getPathInfo();
- // + 2 to also remove beginning and ending slashes
- String fileName = pathInfo
- .substring(ApplicationConstants.PUBLISHED_FILE_PATH.length() + 2);
-
- final String mimetype = response.getService().getMimeType(fileName);
-
- // Security check: avoid accidentally serving from the UI of the
- // classpath instead of relative to the context class
- if (fileName.startsWith("/")) {
- getLogger().log(Level.WARNING,
- "Published file request starting with / rejected: {0}",
- fileName);
- response.sendError(HttpServletResponse.SC_NOT_FOUND, fileName);
- return;
- }
-
- // Check that the resource name has been registered
- Class<?> context;
- synchronized (publishedFileContexts) {
- context = publishedFileContexts.get(fileName);
- }
-
- // Security check: don't serve resource if the name hasn't been
- // registered in the map
- if (context == null) {
- getLogger()
- .log(Level.WARNING,
- "Rejecting published file request for file that has not been published: {0}",
- fileName);
- response.sendError(HttpServletResponse.SC_NOT_FOUND, fileName);
- return;
- }
-
- // Resolve file relative to the location of the context class
- InputStream in = context.getResourceAsStream(fileName);
- if (in == null) {
- getLogger()
- .log(Level.WARNING,
- "{0} published by {1} not found. Verify that the file {2}/{3} is available on the classpath.",
- new Object[] {
- fileName,
- context.getName(),
- context.getPackage().getName()
- .replace('.', '/'), fileName });
- response.sendError(HttpServletResponse.SC_NOT_FOUND, fileName);
- return;
- }
-
- // TODO Check and set cache headers
-
- OutputStream out = null;
- try {
- if (mimetype != null) {
- response.setContentType(mimetype);
- }
-
- out = response.getOutputStream();
-
- final byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE];
-
- int bytesRead = 0;
- while ((bytesRead = in.read(buffer)) > 0) {
- out.write(buffer, 0, bytesRead);
- }
- out.flush();
- } finally {
- try {
- in.close();
- } catch (Exception e) {
- // Do nothing
- }
- if (out != null) {
- try {
- out.close();
- } catch (Exception e) {
- // Do nothing
- }
- }
- }
- }
-
- /**
- * Handles file upload request submitted via Upload component.
- *
- * @param UI
- * The UI for this request
- *
- * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable)
- *
- * @param request
- * @param response
- * @throws IOException
- * @throws InvalidUIDLSecurityKeyException
- */
- public void handleFileUpload(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException,
- InvalidUIDLSecurityKeyException {
-
- /*
- * URI pattern: APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY] See
- * #createReceiverUrl
- */
-
- String pathInfo = request.getPathInfo();
- // strip away part until the data we are interested starts
- int startOfData = pathInfo
- .indexOf(ServletPortletHelper.UPLOAD_URL_PREFIX)
- + ServletPortletHelper.UPLOAD_URL_PREFIX.length();
- String uppUri = pathInfo.substring(startOfData);
- String[] parts = uppUri.split("/", 4); // 0= UIid, 1 = cid, 2= name, 3
- // = sec key
- String uiId = parts[0];
- String connectorId = parts[1];
- String variableName = parts[2];
- UI uI = session.getUIById(Integer.parseInt(uiId));
- UI.setCurrent(uI);
-
- StreamVariable streamVariable = uI.getConnectorTracker()
- .getStreamVariable(connectorId, variableName);
- String secKey = uI.getConnectorTracker().getSeckey(streamVariable);
- if (secKey.equals(parts[3])) {
-
- ClientConnector source = getConnector(uI, connectorId);
- String contentType = request.getContentType();
- if (contentType.contains("boundary")) {
- // Multipart requests contain boundary string
- 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(request, response, streamVariable,
- variableName, source, request.getContentLength());
- }
- } else {
- throw new InvalidUIDLSecurityKeyException(
- "Security key in upload post did not match!");
- }
-
- }
-
- /**
- * Handles a heartbeat request. Heartbeat requests are periodically sent by
- * the client-side to inform the server that the UI sending the heartbeat is
- * still alive (the browser window is open, the connection is up) even when
- * there are no UIDL requests for a prolonged period of time. UIs that do
- * not receive either heartbeat or UIDL requests are eventually removed from
- * the session and garbage collected.
- *
- * @param request
- * @param response
- * @param session
- * @throws IOException
- */
- public void handleHeartbeatRequest(VaadinRequest request,
- VaadinResponse response, VaadinSession session) throws IOException {
- UI ui = null;
- try {
- int uiId = Integer.parseInt(request
- .getParameter(UIConstants.UI_ID_PARAMETER));
- ui = session.getUIById(uiId);
- } catch (NumberFormatException nfe) {
- // null-check below handles this as well
- }
- if (ui != null) {
- ui.setLastHeartbeatTimestamp(System.currentTimeMillis());
- // Ensure that the browser does not cache heartbeat responses.
- // iOS 6 Safari requires this (#10370)
- response.setHeader("Cache-Control", "no-cache");
- } else {
- response.sendError(HttpServletResponse.SC_NOT_FOUND, "UI not found");
- }
- }
-
- /**
- * Stream that extracts content from another stream until the boundary
- * string is encountered.
- *
- * Public only for unit tests, should be considered private for all other
- * purposes.
- */
- public static class SimpleMultiPartInputStream extends InputStream {
-
- /**
- * Counter of how many characters have been matched to boundary string
- * from the stream
- */
- int matchedCount = -1;
-
- /**
- * Used as pointer when returning bytes after partly matched boundary
- * string.
- */
- int curBoundaryIndex = 0;
- /**
- * The byte found after a "promising start for boundary"
- */
- private int bufferedByte = -1;
- private boolean atTheEnd = false;
-
- private final char[] boundary;
-
- private final InputStream realInputStream;
-
- public SimpleMultiPartInputStream(InputStream realInputStream,
- String boundaryString) {
- boundary = (CRLF + DASHDASH + boundaryString).toCharArray();
- this.realInputStream = realInputStream;
- }
-
- @Override
- public int read() throws IOException {
- if (atTheEnd) {
- // End boundary reached, nothing more to read
- return -1;
- } else if (bufferedByte >= 0) {
- /* Purge partially matched boundary if there was such */
- return getBuffered();
- } else if (matchedCount != -1) {
- /*
- * Special case where last "failed" matching ended with first
- * character from boundary string
- */
- return matchForBoundary();
- } else {
- int fromActualStream = realInputStream.read();
- if (fromActualStream == -1) {
- // unexpected end of stream
- throw new IOException(
- "The multipart stream ended unexpectedly");
- }
- if (boundary[0] == fromActualStream) {
- /*
- * If matches the first character in boundary string, start
- * checking if the boundary is fetched.
- */
- return matchForBoundary();
- }
- return fromActualStream;
- }
- }
-
- /**
- * Reads the input to expect a boundary string. Expects that the first
- * character has already been matched.
- *
- * @return -1 if the boundary was matched, else returns the first byte
- * from boundary
- * @throws IOException
- */
- private int matchForBoundary() throws IOException {
- matchedCount = 0;
- /*
- * Going to "buffered mode". Read until full boundary match or a
- * different character.
- */
- while (true) {
- matchedCount++;
- if (matchedCount == boundary.length) {
- /*
- * The whole boundary matched so we have reached the end of
- * file
- */
- atTheEnd = true;
- return -1;
- }
- int fromActualStream = realInputStream.read();
- if (fromActualStream != boundary[matchedCount]) {
- /*
- * Did not find full boundary, cache the mismatching byte
- * and start returning the partially matched boundary.
- */
- bufferedByte = fromActualStream;
- return getBuffered();
- }
- }
- }
-
- /**
- * Returns the partly matched boundary string and the byte following
- * that.
- *
- * @return
- * @throws IOException
- */
- private int getBuffered() throws IOException {
- int b;
- if (matchedCount == 0) {
- // The boundary has been returned, return the buffered byte.
- b = bufferedByte;
- bufferedByte = -1;
- matchedCount = -1;
- } else {
- b = boundary[curBoundaryIndex++];
- if (curBoundaryIndex == matchedCount) {
- // The full boundary has been returned, remaining is the
- // char that did not match the boundary.
-
- curBoundaryIndex = 0;
- if (bufferedByte != boundary[0]) {
- /*
- * next call for getBuffered will return the
- * bufferedByte that came after the partial boundary
- * match
- */
- matchedCount = 0;
- } else {
- /*
- * Special case where buffered byte again matches the
- * boundaryString. This could be the start of the real
- * end boundary.
- */
- matchedCount = 0;
- bufferedByte = -1;
- }
- }
- }
- if (b == -1) {
- throw new IOException("The multipart stream ended unexpectedly");
- }
- return b;
- }
- }
-
- private static final Logger getLogger() {
- return Logger.getLogger(AbstractCommunicationManager.class.getName());
- }
-}
diff --git a/server/src/com/vaadin/server/BootstrapHandler.java b/server/src/com/vaadin/server/BootstrapHandler.java
index 403fefc0e1..dddfb385a6 100644
--- a/server/src/com/vaadin/server/BootstrapHandler.java
+++ b/server/src/com/vaadin/server/BootstrapHandler.java
@@ -41,6 +41,7 @@ import org.jsoup.parser.Tag;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.shared.Version;
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.ui.UI;
/**
@@ -51,7 +52,14 @@ import com.vaadin.ui.UI;
* @deprecated As of 7.0. Will likely change or be removed in a future version
*/
@Deprecated
-public abstract class BootstrapHandler implements RequestHandler {
+public abstract class BootstrapHandler extends SynchronizedRequestHandler {
+
+ /**
+ * Parameter that is added to the UI init request if the session has already
+ * been restarted when generating the bootstrap HTML and ?restartApplication
+ * should thus be ignored when handling the UI init request.
+ */
+ public static final String IGNORE_RESTART_PARAM = "ignoreRestart";
protected class BootstrapContext implements Serializable {
@@ -61,6 +69,7 @@ public abstract class BootstrapHandler implements RequestHandler {
private String widgetsetName;
private String themeName;
private String appId;
+ private PushMode pushMode;
public BootstrapContext(VaadinResponse response,
BootstrapFragmentResponse bootstrapResponse) {
@@ -98,6 +107,30 @@ public abstract class BootstrapHandler implements RequestHandler {
return themeName;
}
+ public PushMode getPushMode() {
+ if (pushMode == null) {
+ UICreateEvent event = new UICreateEvent(getRequest(),
+ getUIClass());
+
+ pushMode = getBootstrapResponse().getUIProvider().getPushMode(
+ event);
+ if (pushMode == null) {
+ pushMode = getRequest().getService()
+ .getDeploymentConfiguration().getPushMode();
+ }
+
+ if (pushMode.isEnabled()
+ && !getRequest().getService().ensurePushAvailable()) {
+ /*
+ * Fall back if not supported (ensurePushAvailable will log
+ * information to the developer the first time this happens)
+ */
+ pushMode = PushMode.DISABLED;
+ }
+ }
+ return pushMode;
+ }
+
public String getAppId() {
if (appId == null) {
appId = getRequest().getService().getMainDivId(getSession(),
@@ -113,10 +146,19 @@ public abstract class BootstrapHandler implements RequestHandler {
}
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
+ if (ServletPortletHelper.isAppRequest(request)) {
+ // We do not want to handle /APP requests here, instead let it fall
+ // through and produce a 404
+ return false;
+ }
try {
+ // Update WebBrowser here only to make WebBrowser information
+ // available in init for LegacyApplications
+ session.getBrowser().updateRequestDetails(request);
+
List<UIProvider> uiProviders = session.getUIProviders();
UIClassSelectionEvent classSelectionEvent = new UIClassSelectionEvent(
@@ -241,11 +283,9 @@ public abstract class BootstrapHandler implements RequestHandler {
/*
* Enable Chrome Frame in all versions of IE if installed.
- *
- * Claim IE10 support to avoid using compatibility mode.
*/
head.appendElement("meta").attr("http-equiv", "X-UA-Compatible")
- .attr("content", "IE=9;chrome=1");
+ .attr("content", "IE=10;chrome=1");
String title = response.getUIProvider().getPageTitle(
new UICreateEvent(context.getRequest(), context.getUIClass()));
@@ -334,8 +374,8 @@ public abstract class BootstrapHandler implements RequestHandler {
VaadinRequest request = context.getRequest();
VaadinService vaadinService = request.getService();
- String staticFileLocation = vaadinService
- .getStaticFileLocation(request);
+ String vaadinLocation = vaadinService.getStaticFileLocation(request)
+ + "/VAADIN/";
fragmentNodes
.add(new Element(Tag.valueOf("iframe"), "")
@@ -345,8 +385,14 @@ public abstract class BootstrapHandler implements RequestHandler {
"position:absolute;width:0;height:0;border:0;overflow:hidden")
.attr("src", "javascript:false"));
- String bootstrapLocation = staticFileLocation
- + "/VAADIN/vaadinBootstrap.js";
+ if (context.getPushMode().isEnabled()) {
+ // Load client-side dependencies for push support
+ fragmentNodes.add(new Element(Tag.valueOf("script"), "").attr(
+ "type", "text/javascript").attr("src",
+ vaadinLocation + ApplicationConstants.VAADIN_PUSH_JS));
+ }
+
+ String bootstrapLocation = vaadinLocation + "vaadinBootstrap.js";
fragmentNodes.add(new Element(Tag.valueOf("script"), "").attr("type",
"text/javascript").attr("src", bootstrapLocation));
Element mainScriptTag = new Element(Tag.valueOf("script"), "").attr(
@@ -415,6 +461,12 @@ public abstract class BootstrapHandler implements RequestHandler {
appConfig.put("theme", themeName);
}
+ // Ignore restartApplication that might be passed to UI init
+ if (request
+ .getParameter(VaadinService.URL_PARAMETER_RESTART_APPLICATION) != null) {
+ appConfig.put("extraParams", "&" + IGNORE_RESTART_PARAM + "=1");
+ }
+
JSONObject versionInfo = new JSONObject();
versionInfo.put("vaadinVersion", Version.getFullVersion());
appConfig.put("versionInfo", versionInfo);
diff --git a/server/src/com/vaadin/server/BrowserWindowOpener.java b/server/src/com/vaadin/server/BrowserWindowOpener.java
index 8e049ca454..a6e420f89c 100644
--- a/server/src/com/vaadin/server/BrowserWindowOpener.java
+++ b/server/src/com/vaadin/server/BrowserWindowOpener.java
@@ -38,7 +38,8 @@ public class BrowserWindowOpener extends AbstractExtension {
private final String path;
private final Class<? extends UI> uiClass;
- public BrowserWindowOpenerUIProvider(Class<? extends UI> uiClass, String path) {
+ public BrowserWindowOpenerUIProvider(Class<? extends UI> uiClass,
+ String path) {
this.path = ensureInitialSlash(path);
this.uiClass = uiClass;
}
diff --git a/server/src/com/vaadin/server/ClientConnector.java b/server/src/com/vaadin/server/ClientConnector.java
index 5e95b18281..3b52fbc730 100644
--- a/server/src/com/vaadin/server/ClientConnector.java
+++ b/server/src/com/vaadin/server/ClientConnector.java
@@ -300,7 +300,7 @@ public interface ClientConnector extends Connector {
/**
* Called by the framework to encode the state to a JSONObject. This is
* typically done by calling the static method
- * {@link AbstractCommunicationManager#encodeState(ClientConnector, SharedState)}
+ * {@link LegacyCommunicationManager#encodeState(ClientConnector, SharedState)}
* .
*
* @return a JSON object with the encoded connector state
@@ -318,8 +318,12 @@ public interface ClientConnector extends Connector {
* routed to this method with the remaining part of the requested path
* available in the path parameter.
* <p>
- * {@link DynamicConnectorResource} can be used to easily make an
- * appropriate URL available to the client-side code.
+ * NOTE that the session is not locked when this method is called. It is the
+ * responsibility of the connector to ensure that the session is locked
+ * while handling state or other session related data. For best performance
+ * the session should be unlocked before writing a large response to the
+ * client.
+ * </p>
*
* @param request
* the request that should be handled
diff --git a/server/src/com/vaadin/server/CommunicationManager.java b/server/src/com/vaadin/server/CommunicationManager.java
deleted file mode 100644
index 8b3550481d..0000000000
--- a/server/src/com/vaadin/server/CommunicationManager.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.server;
-
-import java.io.InputStream;
-
-import javax.servlet.ServletContext;
-
-import com.vaadin.ui.UI;
-
-/**
- * Application manager processes changes and paints for single application
- * instance.
- *
- * This class handles applications running as servlets.
- *
- * @see AbstractCommunicationManager
- *
- * @author Vaadin Ltd.
- * @since 5.0
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future version
- */
-@Deprecated
-@SuppressWarnings("serial")
-public class CommunicationManager extends AbstractCommunicationManager {
-
- /**
- * TODO New constructor - document me!
- *
- * @param session
- */
- public CommunicationManager(VaadinSession session) {
- super(session);
- }
-
- @Override
- protected BootstrapHandler createBootstrapHandler() {
- return new BootstrapHandler() {
- @Override
- protected String getServiceUrl(BootstrapContext context) {
- String pathInfo = context.getRequest().getPathInfo();
- if (pathInfo == null) {
- return null;
- } else {
- /*
- * Make a relative URL to the servlet by adding one ../ for
- * each path segment in pathInfo (i.e. the part of the
- * requested path that comes after the servlet mapping)
- */
- return VaadinServletService
- .getCancelingRelativePath(pathInfo);
- }
- }
-
- @Override
- public String getThemeName(BootstrapContext context) {
- String themeName = context.getRequest().getParameter(
- VaadinServlet.URL_PARAMETER_THEME);
- if (themeName == null) {
- themeName = super.getThemeName(context);
- }
- return themeName;
- }
- };
- }
-
- @Override
- protected InputStream getThemeResourceAsStream(UI uI, String themeName,
- String resource) {
- VaadinServletService service = (VaadinServletService) uI.getSession()
- .getService();
- ServletContext servletContext = service.getServlet()
- .getServletContext();
- return servletContext.getResourceAsStream("/"
- + VaadinServlet.THEME_DIR_PATH + '/' + themeName + "/"
- + resource);
- }
-}
diff --git a/server/src/com/vaadin/server/ComponentSizeValidator.java b/server/src/com/vaadin/server/ComponentSizeValidator.java
index f5e2e2fe12..27d087a2b2 100644
--- a/server/src/com/vaadin/server/ComponentSizeValidator.java
+++ b/server/src/com/vaadin/server/ComponentSizeValidator.java
@@ -191,7 +191,6 @@ public class ComponentSizeValidator implements Serializable {
}
public void reportErrors(PrintWriter clientJSON,
- AbstractCommunicationManager communicationManager,
PrintStream serverErrorStream) {
clientJSON.write("{");
@@ -269,8 +268,7 @@ public class ComponentSizeValidator implements Serializable {
} else {
first = false;
}
- subError.reportErrors(clientJSON, communicationManager,
- serverErrorStream);
+ subError.reportErrors(clientJSON, serverErrorStream);
}
clientJSON.write("]");
serverErrorStream.println("<< Sub erros");
diff --git a/server/src/com/vaadin/server/ConnectorResource.java b/server/src/com/vaadin/server/ConnectorResource.java
index 8f8591e6b1..8682f8ce6f 100644
--- a/server/src/com/vaadin/server/ConnectorResource.java
+++ b/server/src/com/vaadin/server/ConnectorResource.java
@@ -30,6 +30,15 @@ public interface ConnectorResource extends Resource {
/**
* Gets resource as stream.
+ * <p>
+ * Note that this method is called while the session is locked to prevent
+ * race conditions but the methods in the returned {@link DownloadStream}
+ * are assumed to be unrelated to the VaadinSession and are called without
+ * holding session locks (to prevent locking the session during long file
+ * downloads).
+ * </p>
+ *
+ * @return A download stream which produces the resource content
*/
public DownloadStream getStream();
diff --git a/server/src/com/vaadin/server/ConnectorResourceHandler.java b/server/src/com/vaadin/server/ConnectorResourceHandler.java
index 03a2fcc115..00d82988d3 100644
--- a/server/src/com/vaadin/server/ConnectorResourceHandler.java
+++ b/server/src/com/vaadin/server/ConnectorResourceHandler.java
@@ -16,6 +16,7 @@
package com.vaadin.server;
import java.io.IOException;
+import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
@@ -25,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
public class ConnectorResourceHandler implements RequestHandler {
// APP/connector/[uiid]/[cid]/[filename.xyz]
@@ -46,28 +48,38 @@ public class ConnectorResourceHandler implements RequestHandler {
return false;
}
Matcher matcher = CONNECTOR_RESOURCE_PATTERN.matcher(requestPath);
- if (matcher.matches()) {
- String uiId = matcher.group(1);
- String cid = matcher.group(2);
- String key = matcher.group(3);
- UI ui = session.getUIById(Integer.parseInt(uiId));
+ if (!matcher.matches()) {
+ return false;
+ }
+ String uiId = matcher.group(1);
+ String cid = matcher.group(2);
+ String key = matcher.group(3);
+
+ session.lock();
+ UI ui;
+ ClientConnector connector;
+ try {
+ ui = session.getUIById(Integer.parseInt(uiId));
if (ui == null) {
return error(request, response,
"Ignoring connector request for no-existent root "
+ uiId);
}
- UI.setCurrent(ui);
- VaadinSession.setCurrent(ui.getSession());
-
- ClientConnector connector = ui.getConnectorTracker().getConnector(
- cid);
+ connector = ui.getConnectorTracker().getConnector(cid);
if (connector == null) {
return error(request, response,
"Ignoring connector request for no-existent connector "
+ cid + " in root " + uiId);
}
+ } finally {
+ session.unlock();
+ }
+
+ Map<Class<?>, CurrentInstance> oldThreadLocals = CurrentInstance
+ .setThreadLocals(ui);
+ try {
if (!connector.handleConnectorRequest(request, response, key)) {
return error(request, response, connector.getClass()
.getSimpleName()
@@ -75,20 +87,11 @@ public class ConnectorResourceHandler implements RequestHandler {
+ connector.getConnectorId()
+ ") did not handle connector request for " + key);
}
-
- return true;
- } else if (requestPath.matches('/' + ApplicationConstants.APP_PATH
- + "(/.*)?")) {
- /*
- * This should be the last request handler before we get to
- * bootstrap logic. Prevent /APP requests from reaching bootstrap
- * handlers to help protect the /APP name space for framework usage.
- */
- return error(request, response,
- "Returning 404 for /APP request not yet handled.");
- } else {
- return false;
+ } finally {
+ CurrentInstance.restoreThreadLocals(oldThreadLocals);
}
+
+ return true;
}
private static boolean error(VaadinRequest request,
diff --git a/server/src/com/vaadin/server/Constants.java b/server/src/com/vaadin/server/Constants.java
index a9bc3e5b9e..f8d8105286 100644
--- a/server/src/com/vaadin/server/Constants.java
+++ b/server/src/com/vaadin/server/Constants.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.server;
+import com.vaadin.shared.communication.PushMode;
+
/**
* TODO Document me!
*
@@ -47,6 +49,13 @@ public interface Constants {
+ "in web.xml. The default of 5min will be used.\n"
+ "===========================================================";
+ static final String WARNING_PUSH_MODE_NOT_RECOGNIZED = "\n"
+ + "===========================================================\n"
+ + "WARNING: pushMode has been set to an unrecognized value\n"
+ + "in web.xml. The permitted values are \"disabled\", \"manual\",\n"
+ + "and \"automatic\". The default of \"disabled\" will be used.\n"
+ + "===========================================================";
+
static final String WIDGETSET_MISMATCH_INFO = "\n"
+ "=================================================================\n"
+ "The widgetset in use does not seem to be built for the Vaadin\n"
@@ -56,6 +65,53 @@ public interface Constants {
+ " Widgetset version: %s\n"
+ "=================================================================";
+ static final String REQUIRED_ATMOSPHERE_VERSION = "1.0.12";
+
+ static final String INVALID_ATMOSPHERE_VERSION_WARNING = "\n"
+ + "=================================================================\n"
+ + "Vaadin depends on Atomsphere {0} but version {1} was found.\n"
+ + "This might cause compatibility problems if push is used.\n"
+ + "=================================================================";
+
+ static final String ATMOSPHERE_MISSING_ERROR = "\n"
+ + "=================================================================\n"
+ + "Atmosphere could not be loaded. When using push with Vaadin, the\n"
+ + "Atmosphere framework must be present on the classpath.\n"
+ + "If using a dependency management system, please add a dependency\n"
+ + "to vaadin-push.\n"
+ + "If managing dependencies manually, please make sure Atmosphere\n"
+ + REQUIRED_ATMOSPHERE_VERSION
+ + " is included on the classpath.\n"
+ + "Will fall back to using "
+ + PushMode.class.getSimpleName()
+ + "."
+ + PushMode.DISABLED.name()
+ + ".\n"
+ + "=================================================================";
+
+ static final String PUSH_NOT_SUPPORTED_ERROR = "\n"
+ + "=================================================================\n"
+ + "Push is not supported for {0}\n"
+ + "Will fall back to using "
+ + PushMode.class.getSimpleName()
+ + "."
+ + PushMode.DISABLED.name()
+ + ".\n"
+ + "=================================================================";
+
+ public static final String WARNING_LEGACY_PROPERTY_TOSTRING = "You are using toString() instead of getValue() to get the value for a Property of type {0}"
+ + ". This is strongly discouraged and only provided for backwards compatibility with Vaadin 6. "
+ + "To disable this warning message and retain the behavior, set the init parameter \""
+ + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING
+ + "\" to \"true\". To disable the legacy functionality, set \""
+ + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING
+ + "\" to false."
+ + " (Note that your debugger might call toString() and trigger this message).";
+
+ static final String WARNING_UNKNOWN_LEGACY_PROPERTY_TOSTRING_VALUE = "Unknown value '{0}' for parameter "
+ + Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING
+ + ". Supported values are 'false','warning','true'";
+
static final String URL_PARAMETER_THEME = "theme";
static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode";
@@ -63,7 +119,9 @@ public interface Constants {
static final String SERVLET_PARAMETER_RESOURCE_CACHE_TIME = "resourceCacheTime";
static final String SERVLET_PARAMETER_HEARTBEAT_INTERVAL = "heartbeatInterval";
static final String SERVLET_PARAMETER_CLOSE_IDLE_SESSIONS = "closeIdleSessions";
+ static final String SERVLET_PARAMETER_PUSH_MODE = "pushMode";
static final String SERVLET_PARAMETER_UI_PROVIDER = "UIProvider";
+ static final String SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING = "legacyPropertyToString";
// Configurable parameter names
static final String PARAMETER_VAADIN_RESOURCES = "Resources";
diff --git a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java
index 5b0c3fe8d1..80c3644d77 100644
--- a/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java
+++ b/server/src/com/vaadin/server/DefaultDeploymentConfiguration.java
@@ -17,8 +17,11 @@
package com.vaadin.server;
import java.util.Properties;
+import java.util.logging.Level;
import java.util.logging.Logger;
+import com.vaadin.shared.communication.PushMode;
+
/**
* The default implementation of {@link DeploymentConfiguration} based on a base
* class for resolving system properties and a set of init parameters.
@@ -33,7 +36,9 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration {
private int resourceCacheTime;
private int heartbeatInterval;
private boolean closeIdleSessions;
+ private PushMode pushMode;
private final Class<?> systemPropertyBaseClass;
+ private LegacyProperyToStringMode legacyPropertyToStringMode;
/**
* Create a new deployment configuration instance.
@@ -55,6 +60,27 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration {
checkResourceCacheTime();
checkHeartbeatInterval();
checkCloseIdleSessions();
+ checkPushMode();
+ checkLegacyPropertyToString();
+ }
+
+ private void checkLegacyPropertyToString() {
+ String param = getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_LEGACY_PROPERTY_TOSTRING, "warning");
+ if ("true".equals(param)) {
+ legacyPropertyToStringMode = LegacyProperyToStringMode.ENABLED;
+ } else if ("false".equals(param)) {
+ legacyPropertyToStringMode = LegacyProperyToStringMode.DISABLED;
+ } else {
+ if (!"warning".equals(param)) {
+ getLogger()
+ .log(Level.WARNING,
+ Constants.WARNING_UNKNOWN_LEGACY_PROPERTY_TOSTRING_VALUE,
+ param);
+ }
+ legacyPropertyToStringMode = LegacyProperyToStringMode.WARNING;
+
+ }
}
@Override
@@ -167,12 +193,32 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration {
return heartbeatInterval;
}
+ /**
+ * {@inheritDoc}
+ * <p>
+ * The default value is false.
+ */
@Override
public boolean isCloseIdleSessions() {
return closeIdleSessions;
}
/**
+ * {@inheritDoc}
+ * <p>
+ * The default mode is {@link PushMode#DISABLED}.
+ */
+ @Override
+ public PushMode getPushMode() {
+ return pushMode;
+ }
+
+ @Override
+ public Properties getInitParameters() {
+ return initParameters;
+ }
+
+ /**
* Log a warning if Vaadin is not running in production mode.
*/
private void checkProductionMode() {
@@ -231,13 +277,26 @@ public class DefaultDeploymentConfiguration implements DeploymentConfiguration {
.equals("true");
}
+ private void checkPushMode() {
+ String mode = getApplicationOrSystemProperty(
+ Constants.SERVLET_PARAMETER_PUSH_MODE,
+ PushMode.DISABLED.toString());
+ try {
+ pushMode = Enum.valueOf(PushMode.class, mode.toUpperCase());
+ } catch (IllegalArgumentException e) {
+ getLogger().warning(Constants.WARNING_PUSH_MODE_NOT_RECOGNIZED);
+ pushMode = PushMode.DISABLED;
+ }
+ }
+
private Logger getLogger() {
return Logger.getLogger(getClass().getName());
}
@Override
- public Properties getInitParameters() {
- return initParameters;
+ @Deprecated
+ public LegacyProperyToStringMode getLegacyPropertyToStringMode() {
+ return legacyPropertyToStringMode;
}
}
diff --git a/server/src/com/vaadin/server/DeploymentConfiguration.java b/server/src/com/vaadin/server/DeploymentConfiguration.java
index bd4bc928f4..bf9c019b6d 100644
--- a/server/src/com/vaadin/server/DeploymentConfiguration.java
+++ b/server/src/com/vaadin/server/DeploymentConfiguration.java
@@ -19,6 +19,9 @@ package com.vaadin.server;
import java.io.Serializable;
import java.util.Properties;
+import com.vaadin.data.util.AbstractProperty;
+import com.vaadin.shared.communication.PushMode;
+
/**
* A collection of properties configured at deploy time as well as a way of
* accessing third party properties not explicitly supported by this class.
@@ -28,6 +31,23 @@ import java.util.Properties;
* @since 7.0.0
*/
public interface DeploymentConfiguration extends Serializable {
+
+ /**
+ * Determines the mode of the "legacyPropertyToString" parameter.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+ @Deprecated
+ public enum LegacyProperyToStringMode {
+ DISABLED, WARNING, ENABLED;
+
+ public boolean useLegacyMode() {
+ return this == WARNING || this == ENABLED;
+ }
+
+ }
+
/**
* Returns whether Vaadin is in production mode.
*
@@ -78,6 +98,14 @@ public interface DeploymentConfiguration extends Serializable {
public boolean isCloseIdleSessions();
/**
+ * Returns the mode of bidirectional ("push") client-server communication
+ * that should be used.
+ *
+ * @return The push mode in use.
+ */
+ public PushMode getPushMode();
+
+ /**
* Gets the properties configured for the deployment, e.g. as init
* parameters to the servlet or portlet.
*
@@ -101,4 +129,13 @@ public interface DeploymentConfiguration extends Serializable {
public String getApplicationOrSystemProperty(String propertyName,
String defaultValue);
+ /**
+ * Returns to legacy Property.toString() mode used. See
+ * {@link AbstractProperty#isLegacyToStringEnabled()} for more information.
+ *
+ * @return The Property.toString() mode in use.
+ */
+ @Deprecated
+ public LegacyProperyToStringMode getLegacyPropertyToStringMode();
+
}
diff --git a/server/src/com/vaadin/server/DownloadStream.java b/server/src/com/vaadin/server/DownloadStream.java
index e2f9fc5296..4e66831f1d 100644
--- a/server/src/com/vaadin/server/DownloadStream.java
+++ b/server/src/com/vaadin/server/DownloadStream.java
@@ -28,6 +28,11 @@ import javax.servlet.http.HttpServletResponse;
/**
* Downloadable stream.
+ * <p>
+ * Note that the methods in a DownloadStream are called without locking the
+ * session to prevent locking the session during long file downloads. If your
+ * DownloadStream uses anything from the session, you must handle the locking.
+ * </p>
*
* @author Vaadin Ltd.
* @since 3.0
diff --git a/server/src/com/vaadin/server/DragAndDropService.java b/server/src/com/vaadin/server/DragAndDropService.java
index 5a54b5ae3a..a83e83ef7f 100644
--- a/server/src/com/vaadin/server/DragAndDropService.java
+++ b/server/src/com/vaadin/server/DragAndDropService.java
@@ -16,7 +16,7 @@
package com.vaadin.server;
import java.io.IOException;
-import java.io.PrintWriter;
+import java.io.Writer;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -50,13 +50,13 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
private DragAndDropEvent dragEvent;
- private final AbstractCommunicationManager manager;
+ private final LegacyCommunicationManager manager;
private AcceptCriterion acceptCriterion;
private ErrorHandler errorHandler;
- public DragAndDropService(AbstractCommunicationManager manager) {
+ public DragAndDropService(LegacyCommunicationManager manager) {
this.manager = manager;
}
@@ -209,10 +209,10 @@ public class DragAndDropService implements VariableOwner, ClientConnector {
return true;
}
- void printJSONResponse(PrintWriter outWriter) throws PaintException {
+ public void printJSONResponse(Writer outWriter) throws IOException {
if (isDirty()) {
- outWriter.print(", \"dd\":");
+ outWriter.write(", \"dd\":");
JsonPaintTarget jsonPaintTarget = new JsonPaintTarget(manager,
outWriter, false);
diff --git a/server/src/com/vaadin/server/FileDownloader.java b/server/src/com/vaadin/server/FileDownloader.java
index 7cc1fd7cc8..9b49ad8edd 100644
--- a/server/src/com/vaadin/server/FileDownloader.java
+++ b/server/src/com/vaadin/server/FileDownloader.java
@@ -129,10 +129,15 @@ public class FileDownloader extends AbstractExtension {
// Ignore if it isn't for us
return false;
}
+ getSession().lock();
+ DownloadStream stream;
- Resource resource = getFileDownloadResource();
- if (resource instanceof ConnectorResource) {
- DownloadStream stream = ((ConnectorResource) resource).getStream();
+ try {
+ Resource resource = getFileDownloadResource();
+ if (!(resource instanceof ConnectorResource)) {
+ return false;
+ }
+ stream = ((ConnectorResource) resource).getStream();
if (stream.getParameter("Content-Disposition") == null) {
// Content-Disposition: attachment generally forces download
@@ -140,15 +145,15 @@ public class FileDownloader extends AbstractExtension {
"attachment; filename=\"" + stream.getFileName() + "\"");
}
- // Content-Type to block eager browser plug-ins from hijacking the
- // file
+ // Content-Type to block eager browser plug-ins from hijacking
+ // the file
if (isOverrideContentType()) {
stream.setContentType("application/octet-stream;charset=UTF-8");
}
- stream.writeResponse(request, response);
- return true;
- } else {
- return false;
+ } finally {
+ getSession().unlock();
}
+ stream.writeResponse(request, response);
+ return true;
}
}
diff --git a/server/src/com/vaadin/server/GAEVaadinServlet.java b/server/src/com/vaadin/server/GAEVaadinServlet.java
index 0d2063d446..b4a83603b0 100644
--- a/server/src/com/vaadin/server/GAEVaadinServlet.java
+++ b/server/src/com/vaadin/server/GAEVaadinServlet.java
@@ -184,16 +184,14 @@ public class GAEVaadinServlet extends VaadinServlet {
return;
}
- RequestType requestType = getRequestType(request);
-
- if (requestType == RequestType.STATIC_FILE) {
+ if (isStaticResourceRequest(request)) {
// no locking needed, let superclass handle
super.service(request, response);
cleanSession(request);
return;
}
- if (requestType == RequestType.APP) {
+ if (ServletPortletHelper.isAppRequest(request)) {
// no locking needed, let superclass handle
getApplicationContext(request,
MemcacheServiceFactory.getMemcacheService());
@@ -205,7 +203,11 @@ public class GAEVaadinServlet extends VaadinServlet {
final HttpSession session = request.getSession(getService()
.requestCanCreateSession(request));
if (session == null) {
- handleServiceSessionExpired(request, response);
+ try {
+ getService().handleSessionExpired(request, response);
+ } catch (ServiceException e) {
+ throw new ServletException(e);
+ }
cleanSession(request);
return;
}
@@ -218,19 +220,21 @@ public class GAEVaadinServlet extends VaadinServlet {
// try to get lock
long started = new Date().getTime();
// non-UIDL requests will try indefinitely
- while (requestType != RequestType.UIDL
- || new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) {
- locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40),
- MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
- if (locked) {
- break;
- }
- try {
- Thread.sleep(RETRY_AFTER_MILLISECONDS);
- } catch (InterruptedException e) {
- getLogger().finer(
- "Thread.sleep() interrupted while waiting for lock. Trying again. "
- + e);
+ if (!ServletPortletHelper.isUIDLRequest(request)) {
+ while (new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) {
+ locked = memcache.put(mutex, 1,
+ Expiration.byDeltaSeconds(40),
+ MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT);
+ if (locked) {
+ break;
+ }
+ try {
+ Thread.sleep(RETRY_AFTER_MILLISECONDS);
+ } catch (InterruptedException e) {
+ getLogger().finer(
+ "Thread.sleep() interrupted while waiting for lock. Trying again. "
+ + e);
+ }
}
}
diff --git a/server/src/com/vaadin/server/GlobalResourceHandler.java b/server/src/com/vaadin/server/GlobalResourceHandler.java
index 0fac14e20c..d411b286d0 100644
--- a/server/src/com/vaadin/server/GlobalResourceHandler.java
+++ b/server/src/com/vaadin/server/GlobalResourceHandler.java
@@ -31,6 +31,7 @@ import javax.servlet.http.HttpServletResponse;
import com.vaadin.shared.ApplicationConstants;
import com.vaadin.ui.LegacyComponent;
import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
/**
* A {@link RequestHandler} that takes care of {@link ConnectorResource}s that
@@ -85,30 +86,38 @@ public class GlobalResourceHandler implements RequestHandler {
return error(request, response, pathInfo
+ " is not a valid global resource path");
}
+ session.lock();
+ Map<Class<?>, CurrentInstance> oldThreadLocals = null;
+ DownloadStream stream = null;
+ try {
+ UI ui = session.getUIById(Integer.parseInt(uiid));
+ if (ui == null) {
+ return error(request, response, "No UI found for id " + uiid);
+ }
+ oldThreadLocals = CurrentInstance.setThreadLocals(ui);
+ ConnectorResource resource;
+ if (LEGACY_TYPE.equals(type)) {
+ resource = legacyResources.get(key);
+ } else {
+ return error(request, response, "Unknown global resource type "
+ + type + " in requested path " + pathInfo);
+ }
- UI ui = session.getUIById(Integer.parseInt(uiid));
- if (ui == null) {
- return error(request, response, "No UI found for id " + uiid);
- }
- UI.setCurrent(ui);
-
- ConnectorResource resource;
- if (LEGACY_TYPE.equals(type)) {
- resource = legacyResources.get(key);
- } else {
- return error(request, response, "Unknown global resource type "
- + type + " in requested path " + pathInfo);
- }
-
- if (resource == null) {
- return error(request, response, "Global resource " + key
- + " not found");
- }
+ if (resource == null) {
+ return error(request, response, "Global resource " + key
+ + " not found");
+ }
- DownloadStream stream = resource.getStream();
- if (stream == null) {
- return error(request, response, "Resource " + resource
- + " didn't produce any stream.");
+ stream = resource.getStream();
+ if (stream == null) {
+ return error(request, response, "Resource " + resource
+ + " didn't produce any stream.");
+ }
+ } finally {
+ session.unlock();
+ if (oldThreadLocals != null) {
+ CurrentInstance.restoreThreadLocals(oldThreadLocals);
+ }
}
stream.writeResponse(request, response);
diff --git a/server/src/com/vaadin/server/JsonCodec.java b/server/src/com/vaadin/server/JsonCodec.java
index 9a70efab28..d533ed99f3 100644
--- a/server/src/com/vaadin/server/JsonCodec.java
+++ b/server/src/com/vaadin/server/JsonCodec.java
@@ -667,7 +667,7 @@ public class JsonCodec implements Serializable {
} else if (value instanceof Connector) {
Connector connector = (Connector) value;
if (value instanceof Component
- && !(AbstractCommunicationManager
+ && !(LegacyCommunicationManager
.isComponentVisibleToClient((Component) value))) {
return encodeNull();
}
@@ -871,7 +871,7 @@ public class JsonCodec implements Serializable {
for (Entry<?, ?> entry : map.entrySet()) {
ClientConnector key = (ClientConnector) entry.getKey();
- if (AbstractCommunicationManager.isConnectorVisibleToClient(key)) {
+ if (LegacyCommunicationManager.isConnectorVisibleToClient(key)) {
EncodeResult encodedValue = encode(entry.getValue(), null,
valueType, connectorTracker);
jsonMap.put(key.getConnectorId(),
diff --git a/server/src/com/vaadin/server/JsonPaintTarget.java b/server/src/com/vaadin/server/JsonPaintTarget.java
index 11bfb33fe1..ca70391f64 100644
--- a/server/src/com/vaadin/server/JsonPaintTarget.java
+++ b/server/src/com/vaadin/server/JsonPaintTarget.java
@@ -18,6 +18,7 @@ package com.vaadin.server;
import java.io.PrintWriter;
import java.io.Serializable;
+import java.io.Writer;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
@@ -60,7 +61,7 @@ public class JsonPaintTarget implements PaintTarget {
private boolean closed = false;
- private final AbstractCommunicationManager manager;
+ private final LegacyCommunicationManager manager;
private int changes = 0;
@@ -86,14 +87,13 @@ public class JsonPaintTarget implements PaintTarget {
* @throws PaintException
* if the paint operation failed.
*/
- public JsonPaintTarget(AbstractCommunicationManager manager,
- PrintWriter outWriter, boolean cachingRequired)
- throws PaintException {
+ public JsonPaintTarget(LegacyCommunicationManager manager,
+ Writer outWriter, boolean cachingRequired) throws PaintException {
this.manager = manager;
// Sets the target for UIDL writing
- uidlBuffer = outWriter;
+ uidlBuffer = new PrintWriter(outWriter);
// Initialize tag-writing
mOpenTags = new Stack<String>();
@@ -1007,7 +1007,7 @@ public class JsonPaintTarget implements PaintTarget {
return manager.getTagForType(clientConnectorClass);
}
- Collection<Class<? extends ClientConnector>> getUsedClientConnectors() {
+ public Collection<Class<? extends ClientConnector>> getUsedClientConnectors() {
return usedClientConnectors;
}
diff --git a/server/src/com/vaadin/server/LegacyCommunicationManager.java b/server/src/com/vaadin/server/LegacyCommunicationManager.java
new file mode 100644
index 0000000000..c0194db243
--- /dev/null
+++ b/server/src/com/vaadin/server/LegacyCommunicationManager.java
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.Writer;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.vaadin.server.ClientConnector.ConnectorErrorEvent;
+import com.vaadin.server.communication.LocaleWriter;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.JavaScriptConnectorState;
+import com.vaadin.shared.communication.SharedState;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.ConnectorTracker;
+import com.vaadin.ui.HasComponents;
+import com.vaadin.ui.SelectiveRenderer;
+import com.vaadin.ui.UI;
+
+/**
+ * This is a common base class for the server-side implementations of the
+ * communication system between the client code (compiled with GWT into
+ * JavaScript) and the server side components. Its client side counterpart is
+ * {@link com.vaadin.client.ApplicationConnection}.
+ * <p>
+ * TODO Document better!
+ *
+ * @deprecated As of 7.0. Will likely change or be removed in a future version
+ */
+@Deprecated
+@SuppressWarnings("serial")
+public class LegacyCommunicationManager implements Serializable {
+
+ // TODO Refactor (#11410)
+ private final HashMap<Integer, ClientCache> uiToClientCache = new HashMap<Integer, ClientCache>();
+
+ /**
+ * The session this communication manager is used for
+ */
+ private final VaadinSession session;
+
+ // TODO Refactor to UI shared state (#11378)
+ private List<String> locales;
+
+ // TODO Move to VaadinSession (#11409)
+ private DragAndDropService dragAndDropService;
+
+ // TODO Refactor (#11412)
+ private String requestThemeName;
+
+ // TODO Refactor (#11413)
+ private Map<String, Class<?>> publishedFileContexts = new HashMap<String, Class<?>>();
+
+ /**
+ * TODO New constructor - document me!
+ *
+ * @param session
+ */
+ public LegacyCommunicationManager(VaadinSession session) {
+ this.session = session;
+ requireLocale(session.getLocale().toString());
+ }
+
+ protected VaadinSession getSession() {
+ return session;
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11411.
+ */
+ @Deprecated
+ public static JSONObject encodeState(ClientConnector connector,
+ SharedState state) throws JSONException {
+ UI uI = connector.getUI();
+ ConnectorTracker connectorTracker = uI.getConnectorTracker();
+ Class<? extends SharedState> stateType = connector.getStateType();
+ Object diffState = connectorTracker.getDiffState(connector);
+ boolean supportsDiffState = !JavaScriptConnectorState.class
+ .isAssignableFrom(stateType);
+ if (diffState == null && supportsDiffState) {
+ // Use an empty state object as reference for full
+ // repaints
+
+ try {
+ SharedState referenceState = stateType.newInstance();
+ EncodeResult encodeResult = JsonCodec.encode(referenceState,
+ null, stateType, uI.getConnectorTracker());
+ diffState = encodeResult.getEncodedValue();
+ } catch (Exception e) {
+ getLogger()
+ .log(Level.WARNING,
+ "Error creating reference object for state of type {0}",
+ stateType.getName());
+ }
+ }
+ EncodeResult encodeResult = JsonCodec.encode(state, diffState,
+ stateType, uI.getConnectorTracker());
+ if (supportsDiffState) {
+ connectorTracker.setDiffState(connector,
+ (JSONObject) encodeResult.getEncodedValue());
+ }
+ return (JSONObject) encodeResult.getDiff();
+ }
+
+ /**
+ * Resolves a dependency URI, registering the URI with this
+ * {@code LegacyCommunicationManager} if needed and returns a fully
+ * qualified URI.
+ *
+ * @deprecated As of 7.1. See #11413.
+ */
+ @Deprecated
+ public String registerDependency(String resourceUri, Class<?> context) {
+ try {
+ URI uri = new URI(resourceUri);
+ String protocol = uri.getScheme();
+
+ if (ApplicationConstants.PUBLISHED_PROTOCOL_NAME.equals(protocol)) {
+ // Strip initial slash
+ String resourceName = uri.getPath().substring(1);
+ return registerPublishedFile(resourceName, context);
+ }
+
+ if (protocol != null || uri.getHost() != null) {
+ return resourceUri;
+ }
+
+ // Bare path interpreted as published file
+ return registerPublishedFile(resourceUri, context);
+ } catch (URISyntaxException e) {
+ getLogger().log(Level.WARNING,
+ "Could not parse resource url " + resourceUri, e);
+ return resourceUri;
+ }
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11413.
+ */
+ @Deprecated
+ public Map<String, Class<?>> getDependencies() {
+ return publishedFileContexts;
+ }
+
+ private String registerPublishedFile(String name, Class<?> context) {
+ // Add to map of names accepted by servePublishedFile
+ if (publishedFileContexts.containsKey(name)) {
+ Class<?> oldContext = publishedFileContexts.get(name);
+ if (oldContext != context) {
+ getLogger()
+ .log(Level.WARNING,
+ "{0} published by both {1} and {2}. File from {2} will be used.",
+ new Object[] { name, context, oldContext });
+ }
+ } else {
+ publishedFileContexts.put(name, context);
+ }
+
+ return ApplicationConstants.PUBLISHED_PROTOCOL_PREFIX + "/" + name;
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11410.
+ */
+ @Deprecated
+ public ClientCache getClientCache(UI uI) {
+ Integer uiId = Integer.valueOf(uI.getUIId());
+ ClientCache cache = uiToClientCache.get(uiId);
+ if (cache == null) {
+ cache = new ClientCache();
+ uiToClientCache.put(uiId, cache);
+ }
+ return cache;
+ }
+
+ /**
+ * Checks if the connector is visible in context. For Components,
+ * {@link #isComponentVisibleToClient(Component)} is used. For other types
+ * of connectors, the contextual visibility of its first Component ancestor
+ * is used. If no Component ancestor is found, the connector is not visible.
+ *
+ * @deprecated As of 7.1. See #11411.
+ *
+ * @param connector
+ * The connector to check
+ * @return <code>true</code> if the connector is visible to the client,
+ * <code>false</code> otherwise
+ */
+ @Deprecated
+ public static boolean isConnectorVisibleToClient(ClientConnector connector) {
+ if (connector instanceof Component) {
+ return isComponentVisibleToClient((Component) connector);
+ } else {
+ ClientConnector parent = connector.getParent();
+ if (parent == null) {
+ return false;
+ } else {
+ return isConnectorVisibleToClient(parent);
+ }
+ }
+ }
+
+ /**
+ * Checks if the component should be visible to the client. Returns false if
+ * the child should not be sent to the client, true otherwise.
+ *
+ * @deprecated As of 7.1. See #11411.
+ *
+ * @param child
+ * The child to check
+ * @return true if the child is visible to the client, false otherwise
+ */
+ @Deprecated
+ public static boolean isComponentVisibleToClient(Component child) {
+ if (!child.isVisible()) {
+ return false;
+ }
+ HasComponents parent = child.getParent();
+
+ if (parent instanceof SelectiveRenderer) {
+ if (!((SelectiveRenderer) parent).isRendered(child)) {
+ return false;
+ }
+ }
+
+ if (parent != null) {
+ return isComponentVisibleToClient(parent);
+ } else {
+ if (child instanceof UI) {
+ // UI has no parent and visibility was checked above
+ return true;
+ } else {
+ // Component which is not attached to any UI
+ return false;
+ }
+ }
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11412.
+ */
+ @Deprecated
+ public String getTheme(UI uI) {
+ String themeName = uI.getTheme();
+ String requestThemeName = getRequestTheme();
+
+ if (requestThemeName != null) {
+ themeName = requestThemeName;
+ }
+ if (themeName == null) {
+ themeName = VaadinServlet.getDefaultTheme();
+ }
+ return themeName;
+ }
+
+ private String getRequestTheme() {
+ return requestThemeName;
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11411.
+ */
+ @Deprecated
+ public ClientConnector getConnector(UI uI, String connectorId) {
+ ClientConnector c = uI.getConnectorTracker().getConnector(connectorId);
+ if (c == null
+ && connectorId.equals(getDragAndDropService().getConnectorId())) {
+ return getDragAndDropService();
+ }
+
+ return c;
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11409.
+ */
+ @Deprecated
+ public DragAndDropService getDragAndDropService() {
+ if (dragAndDropService == null) {
+ dragAndDropService = new DragAndDropService(this);
+ }
+ return dragAndDropService;
+ }
+
+ /**
+ * Prints the queued (pending) locale definitions to a {@link PrintWriter}
+ * in a (UIDL) format that can be sent to the client and used there in
+ * formatting dates, times etc.
+ *
+ * @deprecated As of 7.1. See #11378.
+ *
+ * @param outWriter
+ */
+ @Deprecated
+ public void printLocaleDeclarations(Writer writer) throws IOException {
+ new LocaleWriter().write(locales, writer);
+ }
+
+ /**
+ * 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
+ * the need to use the {@link Locale} class and all the framework behind it
+ * on the client.
+ *
+ * @deprecated As of 7.1. See #11378.
+ *
+ * @see Locale#toString()
+ *
+ * @param value
+ */
+ @Deprecated
+ public void requireLocale(String value) {
+ if (locales == null) {
+ locales = new ArrayList<String>();
+ locales.add(session.getLocale().toString());
+ }
+ if (!locales.contains(value)) {
+ locales.add(value);
+ }
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11378.
+ */
+ @Deprecated
+ public void resetLocales() {
+ locales = null;
+ }
+
+ /**
+ * @deprecated As of 7.1. Will be removed in the future.
+ */
+ @Deprecated
+ public static class InvalidUIDLSecurityKeyException extends
+ GeneralSecurityException {
+
+ public InvalidUIDLSecurityKeyException(String message) {
+ super(message);
+ }
+ }
+
+ private final HashMap<Class<? extends ClientConnector>, Integer> typeToKey = new HashMap<Class<? extends ClientConnector>, Integer>();
+ private int nextTypeKey = 0;
+
+ private BootstrapHandler bootstrapHandler;
+
+ /**
+ * @deprecated As of 7.1. Will be removed in the future.
+ */
+ @Deprecated
+ public String getTagForType(Class<? extends ClientConnector> class1) {
+ Integer id = typeToKey.get(class1);
+ if (id == null) {
+ id = nextTypeKey++;
+ typeToKey.put(class1, id);
+ if (getLogger().isLoggable(Level.FINE)) {
+ getLogger().log(Level.FINE, "Mapping {0} to {1}",
+ new Object[] { class1.getName(), id });
+ }
+ }
+ return id.toString();
+ }
+
+ /**
+ * Helper class for terminal to keep track of data that client is expected
+ * to know.
+ *
+ * TODO make customlayout templates (from theme) to be cached here.
+ *
+ * @deprecated As of 7.1. See #11410.
+ */
+ @Deprecated
+ public class ClientCache implements Serializable {
+
+ private final Set<Object> res = new HashSet<Object>();
+
+ /**
+ *
+ * @param paintable
+ * @return true if the given class was added to cache
+ */
+ public boolean cache(Object object) {
+ return res.add(object);
+ }
+
+ public void clear() {
+ res.clear();
+ }
+
+ }
+
+ /**
+ * @deprecated As of 7.1. See #11411.
+ */
+ @Deprecated
+ public String getStreamVariableTargetUrl(ClientConnector owner,
+ String name, StreamVariable value) {
+ /*
+ * We will use the same APP/* URI space as ApplicationResources but
+ * prefix url with UPLOAD
+ *
+ * eg. APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY]
+ *
+ * SECKEY is created on each paint to make URL's unpredictable (to
+ * prevent CSRF attacks).
+ *
+ * NAME and PID from URI forms a key to fetch StreamVariable when
+ * handling post
+ */
+ String paintableId = owner.getConnectorId();
+ UI ui = owner.getUI();
+ int uiId = ui.getUIId();
+ String key = uiId + "/" + paintableId + "/" + name;
+
+ ConnectorTracker connectorTracker = ui.getConnectorTracker();
+ connectorTracker.addStreamVariable(paintableId, name, value);
+ String seckey = connectorTracker.getSeckey(value);
+
+ return ApplicationConstants.APP_PROTOCOL_PREFIX
+ + ServletPortletHelper.UPLOAD_URL_PREFIX + key + "/" + seckey;
+
+ }
+
+ /**
+ * Handles an exception that occurred when processing RPC calls or a file
+ * upload.
+ *
+ * @deprecated As of 7.1. See #11411.
+ *
+ * @param ui
+ * The UI where the exception occured
+ * @param throwable
+ * The exception
+ * @param connector
+ * The Rpc target
+ */
+ @Deprecated
+ public void handleConnectorRelatedException(ClientConnector connector,
+ Throwable throwable) {
+ ErrorEvent errorEvent = new ConnectorErrorEvent(connector, throwable);
+ ErrorHandler handler = ErrorEvent.findErrorHandler(connector);
+ handler.error(errorEvent);
+ }
+
+ /**
+ * Requests that the given UI should be fully re-rendered on the client
+ * side.
+ *
+ * @since 7.1
+ * @deprecated. As of 7.1. Should be refactored once locales are fixed
+ * (#11378)
+ */
+ @Deprecated
+ public void repaintAll(UI ui) {
+ getClientCache(ui).clear();
+ ui.getConnectorTracker().markAllConnectorsDirty();
+ ui.getConnectorTracker().markAllClientSidesUninitialized();
+
+ // Reset sent locales
+ resetLocales();
+ requireLocale(session.getLocale().toString());
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(LegacyCommunicationManager.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/LegacyPaint.java b/server/src/com/vaadin/server/LegacyPaint.java
index 09477aaf3e..8d59dfd5ea 100644
--- a/server/src/com/vaadin/server/LegacyPaint.java
+++ b/server/src/com/vaadin/server/LegacyPaint.java
@@ -50,7 +50,7 @@ public class LegacyPaint implements Serializable {
public static void paint(Component component, PaintTarget target)
throws PaintException {
// Only paint content of visible components.
- if (!AbstractCommunicationManager.isComponentVisibleToClient(component)) {
+ if (!LegacyCommunicationManager.isComponentVisibleToClient(component)) {
return;
}
diff --git a/server/src/com/vaadin/server/Page.java b/server/src/com/vaadin/server/Page.java
index 8737b478c3..d4c16fe7f7 100644
--- a/server/src/com/vaadin/server/Page.java
+++ b/server/src/com/vaadin/server/Page.java
@@ -21,14 +21,18 @@ import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.EventObject;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import com.vaadin.event.EventRouter;
import com.vaadin.shared.ui.BorderStyle;
import com.vaadin.shared.ui.ui.PageClientRpc;
+import com.vaadin.shared.ui.ui.PageState;
import com.vaadin.shared.ui.ui.UIConstants;
+import com.vaadin.shared.ui.ui.UIState;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.LegacyWindow;
import com.vaadin.ui.Link;
@@ -218,7 +222,7 @@ public class Page implements Serializable {
}
}
- private static final Method BROWSWER_RESIZE_METHOD = ReflectTools
+ private static final Method BROWSER_RESIZE_METHOD = ReflectTools
.findMethod(BrowserWindowResizeListener.class,
"browserWindowResized", BrowserWindowResizeEvent.class);
@@ -303,6 +307,102 @@ public class Page implements Serializable {
}
}
+ /**
+ * Contains dynamically injected styles injected in the HTML document at
+ * runtime.
+ *
+ * @since 7.1
+ */
+ public static class Styles implements Serializable {
+
+ private final Map<Integer, String> stringInjections = new HashMap<Integer, String>();
+
+ private final Map<Integer, Resource> resourceInjections = new HashMap<Integer, Resource>();
+
+ // The combined injection counter between both string and resource
+ // injections. Used as the key for the injection maps
+ private int injectionCounter = 0;
+
+ // Points to the next injection that has not yet been made into the Page
+ private int nextInjectionPosition = 0;
+
+ private final UI ui;
+
+ private Styles(UI ui) {
+ this.ui = ui;
+ }
+
+ /**
+ * Injects a raw CSS string into the page.
+ *
+ * @param css
+ * The CSS to inject
+ */
+ public void add(String css) {
+ if (css == null) {
+ throw new IllegalArgumentException(
+ "Cannot inject null CSS string");
+ }
+
+ stringInjections.put(injectionCounter++, css);
+ ui.markAsDirty();
+ }
+
+ /**
+ * Injects a CSS resource into the page
+ *
+ * @param resource
+ * The resource to inject.
+ */
+ public void add(Resource resource) {
+ if (resource == null) {
+ throw new IllegalArgumentException(
+ "Cannot inject null resource");
+ }
+
+ resourceInjections.put(injectionCounter++, resource);
+ ui.markAsDirty();
+ }
+
+ private void paint(PaintTarget target) throws PaintException {
+
+ // If full repaint repaint all injections
+ if (target.isFullRepaint()) {
+ nextInjectionPosition = 0;
+ }
+
+ if (injectionCounter > nextInjectionPosition) {
+
+ target.startTag("css-injections");
+
+ while (injectionCounter > nextInjectionPosition) {
+
+ String stringInjection = stringInjections
+ .get(nextInjectionPosition);
+ if (stringInjection != null) {
+ target.startTag("css-string");
+ target.addAttribute("id", nextInjectionPosition);
+ target.addText(stringInjection);
+ target.endTag("css-string");
+ }
+
+ Resource resourceInjection = resourceInjections
+ .get(nextInjectionPosition);
+ if (resourceInjection != null) {
+ target.startTag("css-resource");
+ target.addAttribute("id", nextInjectionPosition);
+ target.addAttribute("url", resourceInjection);
+ target.endTag("css-resource");
+ }
+
+ nextInjectionPosition++;
+ }
+
+ target.endTag("css-injections");
+ }
+ }
+ }
+
private EventRouter eventRouter;
private final UI uI;
@@ -312,13 +412,18 @@ public class Page implements Serializable {
private JavaScript javaScript;
+ private Styles styles;
+
/**
* The current browser location.
*/
private URI location;
- public Page(UI uI) {
+ private final PageState state;
+
+ public Page(UI uI, PageState state) {
this.uI = uI;
+ this.state = state;
}
private void addListener(Class<?> eventType, Object target, Method method) {
@@ -504,20 +609,27 @@ public class Page implements Serializable {
}
/**
- * Adds a new {@link BrowserWindowResizeListener} to this uI. The listener
- * will be notified whenever the browser window within which this uI resides
+ * Adds a new {@link BrowserWindowResizeListener} to this UI. The listener
+ * will be notified whenever the browser window within which this UI resides
* is resized.
+ * <p>
+ * In most cases, the UI should be in lazy resize mode when using browser
+ * window resize listeners. Otherwise, a large number of events can be
+ * received while a resize is being performed. Use
+ * {@link UI#setResizeLazy(boolean)}.
+ * </p>
*
* @param resizeListener
* the listener to add
*
* @see BrowserWindowResizeListener#browserWindowResized(BrowserWindowResizeEvent)
- * @see #setResizeLazy(boolean)
+ * @see UI#setResizeLazy(boolean)
*/
public void addBrowserWindowResizeListener(
BrowserWindowResizeListener resizeListener) {
addListener(BrowserWindowResizeEvent.class, resizeListener,
- BROWSWER_RESIZE_METHOD);
+ BROWSER_RESIZE_METHOD);
+ getState(true).hasResizeListeners = true;
}
/**
@@ -539,7 +651,9 @@ public class Page implements Serializable {
public void removeBrowserWindowResizeListener(
BrowserWindowResizeListener resizeListener) {
removeListener(BrowserWindowResizeEvent.class, resizeListener,
- BROWSWER_RESIZE_METHOD);
+ BROWSER_RESIZE_METHOD);
+ getState(true).hasResizeListeners = eventRouter
+ .hasListeners(BrowserWindowResizeEvent.class);
}
/**
@@ -576,10 +690,23 @@ public class Page implements Serializable {
javaScript = new JavaScript();
javaScript.extend(uI);
}
-
return javaScript;
}
+ /**
+ * Returns that stylesheet associated with this Page. The stylesheet
+ * contains additional styles injected at runtime into the HTML document.
+ *
+ * @since 7.1
+ */
+ public Styles getStyles() {
+
+ if (styles == null) {
+ styles = new Styles(uI);
+ }
+ return styles;
+ }
+
public void paintContent(PaintTarget target) throws PaintException {
if (!openList.isEmpty()) {
for (final Iterator<OpenResource> i = openList.iterator(); i
@@ -637,6 +764,9 @@ public class Page implements Serializable {
location.toString());
}
+ if (styles != null) {
+ styles.paint(target);
+ }
}
/**
@@ -915,4 +1045,36 @@ public class Page implements Serializable {
uI.getRpcProxy(PageClientRpc.class).setTitle(title);
}
+ /**
+ * Reloads the page in the browser.
+ */
+ public void reload() {
+ uI.getRpcProxy(PageClientRpc.class).reload();
+ }
+
+ /**
+ * Returns the page state.
+ * <p>
+ * The page state is transmitted to UIConnector together with
+ * {@link UIState} rather than as an individual entity.
+ * </p>
+ * <p>
+ * The state should be considered an internal detail of Page. Classes
+ * outside of Page should not access it directly but only through public
+ * APIs provided by Page.
+ * </p>
+ *
+ * @since 7.1
+ * @param markAsDirty
+ * true to mark the state as dirty
+ * @return PageState object that can be read in any case and modified if
+ * markAsDirty is true
+ */
+ protected PageState getState(boolean markAsDirty) {
+ if (markAsDirty) {
+ uI.markAsDirty();
+ }
+ return state;
+ }
+
}
diff --git a/server/src/com/vaadin/server/PortletCommunicationManager.java b/server/src/com/vaadin/server/PortletCommunicationManager.java
deleted file mode 100644
index cece75847c..0000000000
--- a/server/src/com/vaadin/server/PortletCommunicationManager.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.server;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.portlet.MimeResponse;
-import javax.portlet.PortletContext;
-import javax.portlet.PortletRequest;
-import javax.portlet.PortletResponse;
-import javax.portlet.RenderRequest;
-import javax.portlet.RenderResponse;
-import javax.portlet.ResourceURL;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.vaadin.shared.ApplicationConstants;
-import com.vaadin.ui.UI;
-
-/**
- * TODO document me!
- *
- * @author peholmst
- *
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future version
- */
-@Deprecated
-@SuppressWarnings("serial")
-public class PortletCommunicationManager extends AbstractCommunicationManager {
-
- public PortletCommunicationManager(VaadinSession session) {
- super(session);
- }
-
- @Override
- protected BootstrapHandler createBootstrapHandler() {
- return new BootstrapHandler() {
- @Override
- public boolean handleRequest(VaadinSession session,
- VaadinRequest request, VaadinResponse response)
- throws IOException {
- PortletRequest portletRequest = ((VaadinPortletRequest) request)
- .getPortletRequest();
- if (portletRequest instanceof RenderRequest) {
- return super.handleRequest(session, request, response);
- } else {
- return false;
- }
- }
-
- @Override
- protected String getServiceUrl(BootstrapContext context) {
- ResourceURL portletResourceUrl = getRenderResponse(context)
- .createResourceURL();
- portletResourceUrl.setResourceID(VaadinPortlet.RESOURCE_URL_ID);
- return portletResourceUrl.toString();
- }
-
- private RenderResponse getRenderResponse(BootstrapContext context) {
- PortletResponse response = ((VaadinPortletResponse) context
- .getResponse()).getPortletResponse();
-
- RenderResponse renderResponse = (RenderResponse) response;
- return renderResponse;
- }
-
- @Override
- protected void appendMainScriptTagContents(
- BootstrapContext context, StringBuilder builder)
- throws JSONException, IOException {
- // fixed base theme to use - all portal pages with Vaadin
- // applications will load this exactly once
- String portalTheme = ((VaadinPortletRequest) context
- .getRequest())
- .getPortalProperty(VaadinPortlet.PORTAL_PARAMETER_VAADIN_THEME);
- if (portalTheme != null
- && !portalTheme.equals(context.getThemeName())) {
- String portalThemeUri = getThemeUri(context, portalTheme);
- // XSS safe - originates from portal properties
- builder.append("vaadin.loadTheme('" + portalThemeUri
- + "');");
- }
-
- super.appendMainScriptTagContents(context, builder);
- }
-
- @Override
- protected String getMainDivStyle(BootstrapContext context) {
- VaadinService vaadinService = context.getRequest().getService();
- return vaadinService.getDeploymentConfiguration()
- .getApplicationOrSystemProperty(
- VaadinPortlet.PORTLET_PARAMETER_STYLE, null);
- }
-
- @Override
- protected JSONObject getApplicationParameters(
- BootstrapContext context) throws JSONException,
- PaintException {
- JSONObject parameters = super.getApplicationParameters(context);
- VaadinPortletResponse response = (VaadinPortletResponse) context
- .getResponse();
- MimeResponse portletResponse = (MimeResponse) response
- .getPortletResponse();
- ResourceURL resourceURL = portletResponse.createResourceURL();
- resourceURL.setResourceID("v-browserDetails");
- parameters.put("browserDetailsUrl", resourceURL.toString());
-
- // Always send path info as a query parameter
- parameters.put(
- ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER,
- true);
-
- return parameters;
- }
-
- };
-
- }
-
- @Override
- protected InputStream getThemeResourceAsStream(UI uI, String themeName,
- String resource) {
- VaadinPortletSession session = (VaadinPortletSession) uI.getSession();
- PortletContext portletContext = session.getPortletSession()
- .getPortletContext();
- return portletContext.getResourceAsStream("/"
- + VaadinPortlet.THEME_DIR_PATH + '/' + themeName + "/"
- + resource);
- }
-
-}
diff --git a/server/src/com/vaadin/server/RequestHandler.java b/server/src/com/vaadin/server/RequestHandler.java
index 24107b744b..873752c5f2 100644
--- a/server/src/com/vaadin/server/RequestHandler.java
+++ b/server/src/com/vaadin/server/RequestHandler.java
@@ -19,17 +19,26 @@ package com.vaadin.server;
import java.io.IOException;
import java.io.Serializable;
+import com.vaadin.ui.UI;
+
/**
- * Handler for producing a response to non-UIDL requests. Handlers can be added
- * to service sessions using
- * {@link VaadinSession#addRequestHandler(RequestHandler)}
+ * Handler for producing a response to HTTP requests. Handlers can be either
+ * added on a {@link VaadinService service} level, common for all users, or on a
+ * {@link VaadinSession session} level for only a single user.
*/
public interface RequestHandler extends Serializable {
/**
- * Handles a non-UIDL request. If a response is written, this method should
- * return <code>true</code> to indicate that no more request handlers should
- * be invoked for the request.
+ * Called when a request needs to be handled. If a response is written, this
+ * method should return <code>true</code> to indicate that no more request
+ * handlers should be invoked for the request.
+ * <p>
+ * Note that request handlers by default do not lock the session. If you are
+ * using VaadinSession or anything inside the VaadinSession you must ensure
+ * the session is locked. This can be done by extending
+ * {@link SynchronizedRequestHandler} or by using
+ * {@link VaadinSession#access(Runnable)} or {@link UI#access(Runnable)}.
+ * </p>
*
* @param session
* The session for the request
@@ -40,6 +49,7 @@ public interface RequestHandler extends Serializable {
* @return true if a response has been written and no further request
* handlers should be called, otherwise false
* @throws IOException
+ * If an IO error occurred
*/
boolean handleRequest(VaadinSession session, VaadinRequest request,
VaadinResponse response) throws IOException;
diff --git a/server/src/com/vaadin/server/RequestTimer.java b/server/src/com/vaadin/server/RequestTimer.java
deleted file mode 100644
index 2f91348ce5..0000000000
--- a/server/src/com/vaadin/server/RequestTimer.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.vaadin.server;
-
-import java.io.Serializable;
-
-/**
- * Times the handling of requests and stores the information as an attribute in
- * the request. The timing info is later passed on to the client in the UIDL and
- * the client provides JavaScript API for accessing this data from e.g.
- * TestBench.
- *
- * @author Jonatan Kronqvist / Vaadin Ltd
- */
-public class RequestTimer implements Serializable {
- private long requestStartTime = 0;
-
- /**
- * Starts the timing of a request. This should be called before any
- * processing of the request.
- */
- public void start() {
- requestStartTime = System.nanoTime();
- }
-
- /**
- * Stops the timing of a request. This should be called when all processing
- * of a request has finished.
- *
- * @param context
- */
- public void stop(VaadinSession context) {
- // Measure and store the total handling time. This data can be
- // used in TestBench 3 tests.
- long time = (System.nanoTime() - requestStartTime) / 1000000;
-
- // The timings must be stored in the context, since a new
- // RequestTimer is created for every request.
- context.setLastRequestDuration(time);
- }
-}
diff --git a/server/src/com/vaadin/server/ServerRpcManager.java b/server/src/com/vaadin/server/ServerRpcManager.java
index ec25ce83ca..a1682cb453 100644
--- a/server/src/com/vaadin/server/ServerRpcManager.java
+++ b/server/src/com/vaadin/server/ServerRpcManager.java
@@ -139,7 +139,7 @@ public class ServerRpcManager<T extends ServerRpc> implements Serializable {
*
* @return RPC interface type
*/
- protected Class<T> getRpcInterface() {
+ public Class<T> getRpcInterface() {
return rpcInterface;
}
diff --git a/server/src/com/vaadin/server/ServletPortletHelper.java b/server/src/com/vaadin/server/ServletPortletHelper.java
index ce9872f40e..c14467a10e 100644
--- a/server/src/com/vaadin/server/ServletPortletHelper.java
+++ b/server/src/com/vaadin/server/ServletPortletHelper.java
@@ -23,23 +23,14 @@ import com.vaadin.shared.ApplicationConstants;
import com.vaadin.ui.Component;
import com.vaadin.ui.UI;
-/*
- * Copyright 2000-2013 Vaadin Ltd.
+/**
+ * Contains helper methods shared by {@link VaadinServlet} and
+ * {@link VaadinPortlet}.
*
- * 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.
+ * @deprecated As of 7.1. Will be removed or refactored in the future.
*/
-
-class ServletPortletHelper implements Serializable {
+@Deprecated
+public class ServletPortletHelper implements Serializable {
public static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/";
/**
* The default SystemMessages (read-only).
@@ -132,6 +123,10 @@ class ServletPortletHelper implements Serializable {
return hasPathPrefix(request, ApplicationConstants.HEARTBEAT_PATH + '/');
}
+ public static boolean isPushRequest(VaadinRequest request) {
+ return hasPathPrefix(request, ApplicationConstants.PUSH_PATH + '/');
+ }
+
public static void initDefaultUIProvider(VaadinSession session,
VaadinService vaadinService) throws ServiceException {
String uiProperty = vaadinService.getDeploymentConfiguration()
@@ -200,7 +195,7 @@ class ServletPortletHelper implements Serializable {
* <li>{@link Locale#getDefault()}</li>
* </ol>
*/
- static Locale findLocale(Component component, VaadinSession session,
+ public static Locale findLocale(Component component, VaadinSession session,
VaadinRequest request) {
if (component == null) {
component = UI.getCurrent();
@@ -234,5 +229,4 @@ class ServletPortletHelper implements Serializable {
return Locale.getDefault();
}
-
}
diff --git a/server/src/com/vaadin/server/SessionExpiredHandler.java b/server/src/com/vaadin/server/SessionExpiredHandler.java
new file mode 100644
index 0000000000..6a7896f3d1
--- /dev/null
+++ b/server/src/com/vaadin/server/SessionExpiredHandler.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server;
+
+import java.io.IOException;
+
+/**
+ * A specialized RequestHandler which is capable of sending session expiration
+ * messages to the user.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public interface SessionExpiredHandler extends RequestHandler {
+
+ /**
+ * Called when the a session expiration has occured and a notification needs
+ * to be sent to the user. If a response is written, this method should
+ * return <code>true</code> to indicate that no more
+ * {@link SessionExpiredHandler} handlers should be invoked for the request.
+ *
+ * @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
+ * If an IO error occurred
+ * @since 7.1
+ */
+ boolean handleSessionExpired(VaadinRequest request, VaadinResponse response)
+ throws IOException;
+
+}
diff --git a/server/src/com/vaadin/server/SynchronizedRequestHandler.java b/server/src/com/vaadin/server/SynchronizedRequestHandler.java
new file mode 100644
index 0000000000..ac730dcecb
--- /dev/null
+++ b/server/src/com/vaadin/server/SynchronizedRequestHandler.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server;
+
+import java.io.IOException;
+
+/**
+ * RequestHandler which takes care of locking and unlocking of the VaadinSession
+ * automatically. The session is locked before
+ * {@link #synchronizedHandleRequest(VaadinSession, VaadinRequest, VaadinResponse)}
+ * is called and unlocked after it has completed.
+ *
+ * @author Vaadin Ltd
+ * @version @VERSION@
+ * @since 7.1
+ */
+public abstract class SynchronizedRequestHandler implements RequestHandler {
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ session.lock();
+ try {
+ return synchronizedHandleRequest(session, request, response);
+ } finally {
+ session.unlock();
+ }
+ }
+
+ /**
+ * Identical to
+ * {@link #handleRequest(VaadinSession, VaadinRequest, VaadinResponse)}
+ * except the {@link VaadinSession} is locked before this is called and
+ * unlocked after this has completed.
+ *
+ * @see #handleRequest(VaadinSession, VaadinRequest, VaadinResponse)
+ * @param session
+ * The session for the request
+ * @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
+ * If an IO error occurred
+ */
+ public abstract boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException;
+
+}
diff --git a/server/src/com/vaadin/server/UIProvider.java b/server/src/com/vaadin/server/UIProvider.java
index a91db6b88d..0305b907e6 100644
--- a/server/src/com/vaadin/server/UIProvider.java
+++ b/server/src/com/vaadin/server/UIProvider.java
@@ -20,9 +20,11 @@ import java.io.Serializable;
import java.lang.annotation.Annotation;
import com.vaadin.annotations.PreserveOnRefresh;
+import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.annotations.Widgetset;
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.ui.UI;
public abstract class UIProvider implements Serializable {
@@ -149,4 +151,27 @@ public abstract class UIProvider implements Serializable {
return titleAnnotation.value();
}
}
+
+ /**
+ * Finds the {@link PushMode} to use for a specific UI. If no specific push
+ * mode is required, <code>null</code> is returned.
+ * <p>
+ * The default implementation uses the @{@link Push} annotation if it's
+ * defined for the UI class.
+ *
+ * @param event
+ * the UI create event with information about the UI and the
+ * current request.
+ * @return the push mode to use, or <code>null</code> if the default push
+ * mode should be used
+ *
+ */
+ public PushMode getPushMode(UICreateEvent event) {
+ Push push = getAnnotationFor(event.getUIClass(), Push.class);
+ if (push == null) {
+ return null;
+ } else {
+ return push.value();
+ }
+ }
}
diff --git a/server/src/com/vaadin/server/UnsupportedBrowserHandler.java b/server/src/com/vaadin/server/UnsupportedBrowserHandler.java
index 55d5a5c78f..5fc00408a9 100644
--- a/server/src/com/vaadin/server/UnsupportedBrowserHandler.java
+++ b/server/src/com/vaadin/server/UnsupportedBrowserHandler.java
@@ -24,18 +24,18 @@ import java.io.Writer;
*
* <p>
* This handler is usually added to the application by
- * {@link AbstractCommunicationManager}.
+ * {@link LegacyCommunicationManager}.
* </p>
*/
@SuppressWarnings("serial")
-public class UnsupportedBrowserHandler implements RequestHandler {
+public class UnsupportedBrowserHandler extends SynchronizedRequestHandler {
/** Cookie used to ignore browser checks */
public static final String FORCE_LOAD_COOKIE = "vaadinforceload=1";
@Override
- public boolean handleRequest(VaadinSession session, VaadinRequest request,
- VaadinResponse response) throws IOException {
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
// Check if the browser is supported
// If Chrome Frame is available we'll assume it's ok
diff --git a/server/src/com/vaadin/server/VaadinPortlet.java b/server/src/com/vaadin/server/VaadinPortlet.java
index ac4e904898..327ce78a6c 100644
--- a/server/src/com/vaadin/server/VaadinPortlet.java
+++ b/server/src/com/vaadin/server/VaadinPortlet.java
@@ -15,16 +15,10 @@
*/
package com.vaadin.server;
-import java.io.BufferedWriter;
import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.security.GeneralSecurityException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
@@ -46,12 +40,11 @@ import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
import com.liferay.portal.kernel.util.PropsUtil;
-import com.vaadin.server.AbstractCommunicationManager.Callback;
-import com.vaadin.ui.UI;
+import com.vaadin.server.communication.PortletDummyRequestHandler;
+import com.vaadin.server.communication.PortletUIInitHandler;
import com.vaadin.util.CurrentInstance;
/**
@@ -257,24 +250,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
}
- public static class AbstractApplicationPortletWrapper implements Callback {
-
- private final VaadinPortlet portlet;
-
- public AbstractApplicationPortletWrapper(VaadinPortlet portlet) {
- this.portlet = portlet;
- }
-
- @Override
- public void criticalNotification(VaadinRequest request,
- VaadinResponse response, String cap, String msg,
- String details, String outOfSyncURL) throws IOException {
- portlet.criticalNotification((VaadinPortletRequest) request,
- (VaadinPortletResponse) response, 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.
@@ -332,11 +307,16 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
}
DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(initParameters);
- vaadinService = createPortletService(deploymentConfiguration);
+ try {
+ vaadinService = createPortletService(deploymentConfiguration);
+ } catch (ServiceException e) {
+ throw new PortletException("Could not initialized VaadinPortlet", e);
+ }
// Sets current service even though there are no request and response
vaadinService.setCurrentInstances(null, null);
portletInitialized();
+
CurrentInstance.clearAll();
}
@@ -350,15 +330,21 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
}
protected VaadinPortletService createPortletService(
- DeploymentConfiguration deploymentConfiguration) {
- return new VaadinPortletService(this, deploymentConfiguration);
+ DeploymentConfiguration deploymentConfiguration)
+ throws ServiceException {
+ VaadinPortletService service = new VaadinPortletService(this,
+ deploymentConfiguration);
+ service.init();
+ return service;
}
/**
* @author Vaadin Ltd
*
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * @deprecated As of 7.0. This is no longer used and only provided for
+ * backwards compatibility. Each {@link RequestHandler} can
+ * individually decide whether it wants to handle a request or
+ * not.
*/
@Deprecated
protected enum RequestType {
@@ -369,8 +355,10 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
* @param vaadinRequest
* @return
*
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * @deprecated As of 7.0. This is no longer used and only provided for
+ * backwards compatibility. Each {@link RequestHandler} can
+ * individually decide whether it wants to handle a request or
+ * not.
*/
@Deprecated
protected RequestType getRequestType(VaadinPortletRequest vaadinRequest) {
@@ -381,7 +369,7 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
ResourceRequest resourceRequest = (ResourceRequest) request;
if (ServletPortletHelper.isUIDLRequest(vaadinRequest)) {
return RequestType.UIDL;
- } else if (isBrowserDetailsRequest(resourceRequest)) {
+ } else if (PortletUIInitHandler.isUIInitRequest(vaadinRequest)) {
return RequestType.BROWSER_DETAILS;
} else if (ServletPortletHelper.isFileUploadRequest(vaadinRequest)) {
return RequestType.FILE_UPLOAD;
@@ -392,12 +380,9 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
return RequestType.APP;
} else if (ServletPortletHelper.isHeartbeatRequest(vaadinRequest)) {
return RequestType.HEARTBEAT;
- } else if (isDummyRequest(resourceRequest)) {
+ } else if (PortletDummyRequestHandler.isDummyRequest(vaadinRequest)) {
return RequestType.DUMMY;
} else {
- // these are not served with ResourceRequests, but by a servlet
- // on the portal at portlet root path (configured by default by
- // Liferay at deployment time, similar on other portals)
return RequestType.STATIC_FILE;
}
} else if (request instanceof ActionRequest) {
@@ -408,16 +393,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
return RequestType.UNKNOWN;
}
- private boolean isBrowserDetailsRequest(ResourceRequest request) {
- return request.getResourceID() != null
- && request.getResourceID().equals("v-browserDetails");
- }
-
- private boolean isDummyRequest(ResourceRequest request) {
- return request.getResourceID() != null
- && request.getResourceID().equals("DUMMY");
- }
-
/**
* @param request
* @param response
@@ -430,145 +405,14 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
@Deprecated
protected void handleRequest(PortletRequest request,
PortletResponse response) throws PortletException, IOException {
- RequestTimer requestTimer = new RequestTimer();
- requestTimer.start();
CurrentInstance.clearAll();
setCurrent(this);
-
try {
- AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper(
- this);
-
- VaadinPortletRequest vaadinRequest = createVaadinRequest(request);
-
- VaadinPortletResponse vaadinResponse = new VaadinPortletResponse(
- response, getService());
-
- getService().setCurrentInstances(vaadinRequest, vaadinResponse);
-
- RequestType requestType = getRequestType(vaadinRequest);
-
- if (requestType == RequestType.UNKNOWN) {
- handleUnknownRequest(request, response);
- } else if (requestType == RequestType.DUMMY) {
- /*
- * This dummy page is used by action responses to redirect to,
- * in order to prevent the boot strap code from being rendered
- * into strange places such as iframes.
- */
- ((ResourceResponse) response).setContentType("text/html");
- final OutputStream out = ((ResourceResponse) response)
- .getPortletOutputStream();
- final PrintWriter outWriter = new PrintWriter(
- new BufferedWriter(new OutputStreamWriter(out, "UTF-8")));
- outWriter.print("<html><body>dummy page</body></html>");
- outWriter.close();
- } else {
- VaadinPortletSession vaadinSession = null;
-
- try {
- // TODO What about PARAM_UNLOADBURST &
- // redirectToApplication??
-
- vaadinSession = (VaadinPortletSession) getService()
- .findVaadinSession(vaadinRequest);
- if (vaadinSession == null) {
- return;
- }
-
- PortletCommunicationManager communicationManager = (PortletCommunicationManager) vaadinSession
- .getCommunicationManager();
-
- if (requestType == RequestType.PUBLISHED_FILE) {
- communicationManager.servePublishedFile(vaadinRequest,
- vaadinResponse);
- return;
- } else if (requestType == RequestType.HEARTBEAT) {
- communicationManager.handleHeartbeatRequest(
- vaadinRequest, vaadinResponse, vaadinSession);
- return;
- }
-
- /* Update browser information from request */
- vaadinSession.getBrowser().updateRequestDetails(
- vaadinRequest);
-
- /* Notify listeners */
-
- // Finds the right UI
- UI uI = null;
- if (requestType == RequestType.UIDL) {
- uI = getService().findUI(vaadinRequest);
- }
-
- // TODO Should this happen before or after the transaction
- // starts?
- if (request instanceof RenderRequest) {
- vaadinSession.firePortletRenderRequest(uI,
- (RenderRequest) request,
- (RenderResponse) response);
- } else if (request instanceof ActionRequest) {
- vaadinSession.firePortletActionRequest(uI,
- (ActionRequest) request,
- (ActionResponse) response);
- } else if (request instanceof EventRequest) {
- vaadinSession.firePortletEventRequest(uI,
- (EventRequest) request,
- (EventResponse) response);
- } else if (request instanceof ResourceRequest) {
- vaadinSession.firePortletResourceRequest(uI,
- (ResourceRequest) request,
- (ResourceResponse) response);
- }
-
- /* Handle the request */
- if (requestType == RequestType.FILE_UPLOAD) {
- // UI is resolved in handleFileUpload by
- // PortletCommunicationManager
- communicationManager.handleFileUpload(vaadinSession,
- vaadinRequest, vaadinResponse);
- return;
- } else if (requestType == RequestType.BROWSER_DETAILS) {
- communicationManager.handleBrowserDetailsRequest(
- vaadinRequest, vaadinResponse, vaadinSession);
- return;
- } else if (requestType == RequestType.UIDL) {
- // Handles AJAX UIDL requests
- communicationManager.handleUidlRequest(vaadinRequest,
- vaadinResponse, portletWrapper, uI);
-
- // Ensure that the browser does not cache UIDL
- // responses.
- // iOS 6 Safari requires this (#9732)
- response.setProperty("Cache-Control", "no-cache");
- return;
- } else {
- handleOtherRequest(vaadinRequest, vaadinResponse,
- requestType, vaadinSession,
- communicationManager);
- }
- } catch (final SessionExpiredException e) {
- // TODO Figure out a better way to deal with
- // SessionExpiredExceptions
- getLogger().finest("A user session has expired");
- } catch (final GeneralSecurityException e) {
- // TODO Figure out a better way to deal with
- // GeneralSecurityExceptions
- getLogger()
- .fine("General security exception, the security key was probably incorrect.");
- } catch (final Throwable e) {
- handleServiceException(vaadinRequest, vaadinResponse,
- vaadinSession, e);
- } finally {
- if (vaadinSession != null) {
- getService().cleanupSession(vaadinSession);
- requestTimer.stop(vaadinSession);
- }
- }
- }
- } finally {
- CurrentInstance.clearAll();
+ getService().handleRequest(createVaadinRequest(request),
+ createVaadinResponse(response));
+ } catch (ServiceException e) {
+ throw new PortletException(e);
}
}
@@ -592,50 +436,12 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
}
- protected VaadinPortletService getService() {
- return vaadinService;
- }
-
- private void handleUnknownRequest(PortletRequest request,
- PortletResponse response) {
- getLogger().warning("Unknown request type");
+ private VaadinPortletResponse createVaadinResponse(PortletResponse response) {
+ return new VaadinPortletResponse(response, getService());
}
- /**
- * Handle a portlet request that is not for static files, UIDL or upload.
- * Also render requests are handled here.
- *
- * This method is called after starting the application and calling portlet
- * and transaction listeners.
- *
- * @param request
- * @param response
- * @param requestType
- * @param vaadinSession
- * @param vaadinSession
- * @param communicationManager
- * @throws PortletException
- * @throws IOException
- * @throws MalformedURLException
- */
- private void handleOtherRequest(VaadinPortletRequest request,
- VaadinResponse response, RequestType requestType,
- VaadinSession vaadinSession,
- PortletCommunicationManager communicationManager)
- throws PortletException, IOException, MalformedURLException {
- if (requestType == RequestType.APP || requestType == RequestType.RENDER) {
- if (!communicationManager.handleOtherRequest(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) {
- // nothing to do, listeners do all the work
- } else {
- throw new IllegalStateException(
- "handleRequest() without anything to do - should never happen!");
- }
+ protected VaadinPortletService getService() {
+ return vaadinService;
}
@Override
@@ -678,98 +484,6 @@ public class VaadinPortlet extends GenericPortlet implements Constants,
handleRequest(request, response);
}
- private void handleServiceException(VaadinPortletRequest request,
- VaadinPortletResponse response, VaadinSession vaadinSession,
- Throwable e) throws IOException, PortletException {
- // TODO Check that this error handler is working when running inside a
- // portlet
-
- // if this was an UIDL request, response UIDL back to client
- ErrorHandler errorHandler = ErrorEvent.findErrorHandler(vaadinSession);
- if (getRequestType(request) == RequestType.UIDL) {
- SystemMessages ci = getService().getSystemMessages(
- ServletPortletHelper.findLocale(null, vaadinSession,
- request), request);
- criticalNotification(request, response,
- ci.getInternalErrorCaption(), ci.getInternalErrorMessage(),
- null, ci.getInternalErrorURL());
- if (errorHandler != null) {
- errorHandler.error(new ErrorEvent(e));
- }
- } else {
- if (errorHandler != null) {
- errorHandler.error(new ErrorEvent(e));
- } else {
- // Re-throw other exceptions
- throw new PortletException(e);
- }
- }
- }
-
- /**
- * Send notification to client's application. Used to notify client of
- * critical errors and session expiration due to long inactivity. Server has
- * no knowledge of what application client refers to.
- *
- * @param request
- * the Portlet request instance.
- * @param response
- * the Portlet response to write to.
- * @param caption
- * for the notification
- * @param message
- * for the notification
- * @param details
- * a detail message to show in addition to the passed message.
- * Currently shown directly but could be hidden behind a details
- * drop down.
- * @param url
- * url to load after message, null for current page
- * @throws IOException
- * if the writing failed due to input/output error.
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
- */
- @Deprecated
- void criticalNotification(VaadinPortletRequest request,
- VaadinPortletResponse response, String caption, String message,
- String details, String url) throws IOException {
-
- // clients JS app is still running, but server application either
- // no longer exists or it might fail to perform reasonably.
- // send a notification to client's application and link how
- // to "restart" application.
-
- if (caption != null) {
- caption = "\"" + caption + "\"";
- }
- if (details != null) {
- if (message == null) {
- message = details;
- } else {
- message += "<br/><br/>" + details;
- }
- }
- if (message != null) {
- message = "\"" + message + "\"";
- }
- if (url != null) {
- url = "\"" + url + "\"";
- }
-
- // Set the response type
- response.setContentType("application/json; charset=UTF-8");
- final OutputStream out = response.getOutputStream();
- final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
- new OutputStreamWriter(out, "UTF-8")));
- outWriter.print("for(;;);[{\"changes\":[], \"meta\" : {"
- + "\"appError\": {" + "\"caption\":" + caption + ","
- + "\"message\" : " + message + "," + "\"url\" : " + url
- + "}}, \"resources\": {}, \"locales\":[]}]");
- outWriter.close();
- }
-
private static final Logger getLogger() {
return Logger.getLogger(VaadinPortlet.class.getName());
}
diff --git a/server/src/com/vaadin/server/VaadinPortletService.java b/server/src/com/vaadin/server/VaadinPortletService.java
index e59ea7fd5e..2eca07dd4a 100644
--- a/server/src/com/vaadin/server/VaadinPortletService.java
+++ b/server/src/com/vaadin/server/VaadinPortletService.java
@@ -17,21 +17,30 @@
package com.vaadin.server;
import java.io.File;
+import java.io.InputStream;
import java.net.URL;
+import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
+import javax.portlet.EventRequest;
import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
+import javax.portlet.RenderRequest;
import com.vaadin.server.VaadinPortlet.RequestType;
+import com.vaadin.server.communication.PortletBootstrapHandler;
+import com.vaadin.server.communication.PortletDummyRequestHandler;
+import com.vaadin.server.communication.PortletListenerNotifier;
+import com.vaadin.server.communication.PortletUIInitHandler;
import com.vaadin.ui.UI;
public class VaadinPortletService extends VaadinService {
private final VaadinPortlet portlet;
public VaadinPortletService(VaadinPortlet portlet,
- DeploymentConfiguration deploymentConfiguration) {
+ DeploymentConfiguration deploymentConfiguration)
+ throws ServiceException {
super(deploymentConfiguration);
this.portlet = portlet;
@@ -46,7 +55,25 @@ public class VaadinPortletService extends VaadinService {
}
}
- protected VaadinPortlet getPortlet() {
+ @Override
+ protected List<RequestHandler> createRequestHandlers()
+ throws ServiceException {
+ List<RequestHandler> handlers = super.createRequestHandlers();
+
+ handlers.add(new PortletUIInitHandler());
+ handlers.add(new PortletListenerNotifier());
+ handlers.add(0, new PortletDummyRequestHandler());
+ handlers.add(0, new PortletBootstrapHandler());
+
+ return handlers;
+ }
+
+ /**
+ * Retrieves a reference to the portlet associated with this service.
+ *
+ * @return A reference to the VaadinPortlet this service is using
+ */
+ public VaadinPortlet getPortlet() {
return portlet;
}
@@ -155,13 +182,19 @@ public class VaadinPortletService extends VaadinService {
@Override
protected boolean requestCanCreateSession(VaadinRequest request) {
- RequestType requestType = getRequestType(request);
- if (requestType == RequestType.RENDER) {
+ if (!(request instanceof VaadinPortletRequest)) {
+ throw new IllegalArgumentException(
+ "Request is not a VaadinPortletRequest");
+ }
+
+ PortletRequest portletRequest = ((VaadinPortletRequest) request)
+ .getPortletRequest();
+ if (portletRequest instanceof RenderRequest) {
// In most cases the first request is a render request that
// renders the HTML fragment. This should create a Vaadin
// session unless there is already one.
return true;
- } else if (requestType == RequestType.EVENT) {
+ } else if (portletRequest instanceof EventRequest) {
// A portlet can also be sent an event even though it has not
// been rendered, e.g. portlet on one page sends an event to a
// portlet on another page and then moves the user to that page.
@@ -191,12 +224,6 @@ public class VaadinPortletService extends VaadinService {
return type;
}
- @Override
- protected AbstractCommunicationManager createCommunicationManager(
- VaadinSession session) {
- return new PortletCommunicationManager(session);
- }
-
public static PortletRequest getCurrentPortletRequest() {
VaadinRequest currentRequest = VaadinService.getCurrentRequest();
if (currentRequest instanceof VaadinPortletRequest) {
@@ -230,6 +257,17 @@ public class VaadinPortletService extends VaadinService {
}
@Override
+ public InputStream getThemeResourceAsStream(UI uI, String themeName,
+ String resource) {
+ VaadinPortletSession session = (VaadinPortletSession) uI.getSession();
+ PortletContext portletContext = session.getPortletSession()
+ .getPortletContext();
+ return portletContext.getResourceAsStream("/"
+ + VaadinPortlet.THEME_DIR_PATH + '/' + themeName + "/"
+ + resource);
+ }
+
+ @Override
public String getMainDivId(VaadinSession session, VaadinRequest request,
Class<? extends UI> uiClass) {
PortletRequest portletRequest = ((VaadinPortletRequest) request)
@@ -240,4 +278,20 @@ public class VaadinPortletService extends VaadinService {
*/
return "v-" + portletRequest.getWindowID();
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.server.VaadinService#handleSessionExpired(com.vaadin.server
+ * .VaadinRequest, com.vaadin.server.VaadinResponse)
+ */
+ @Override
+ protected void handleSessionExpired(VaadinRequest request,
+ VaadinResponse response) {
+ // TODO Figure out a better way to deal with
+ // SessionExpiredExceptions
+ getLogger().finest("A user session has expired");
+ }
+
}
diff --git a/server/src/com/vaadin/server/VaadinService.java b/server/src/com/vaadin/server/VaadinService.java
index ada0fac107..af0c280c19 100644
--- a/server/src/com/vaadin/server/VaadinService.java
+++ b/server/src/com/vaadin/server/VaadinService.java
@@ -16,24 +16,43 @@
package com.vaadin.server;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.portlet.PortletContext;
import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.json.JSONException;
+import org.json.JSONObject;
import com.vaadin.annotations.PreserveOnRefresh;
import com.vaadin.event.EventRouter;
+import com.vaadin.server.communication.FileUploadHandler;
+import com.vaadin.server.communication.HeartbeatHandler;
+import com.vaadin.server.communication.PublishedFileHandler;
+import com.vaadin.server.communication.SessionRequestHandler;
+import com.vaadin.server.communication.UidlRequestHandler;
+import com.vaadin.shared.JsonConstants;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.ui.UI;
import com.vaadin.util.CurrentInstance;
@@ -70,6 +89,8 @@ public abstract class VaadinService implements Serializable {
@Deprecated
public static final String URL_PARAMETER_CLOSE_APPLICATION = "closeApplication";
+ private static final String REQUEST_START_TIME_ATTRIBUTE = "requestStartTime";
+
private final DeploymentConfiguration deploymentConfiguration;
private final EventRouter eventRouter = new EventRouter();
@@ -79,6 +100,15 @@ public abstract class VaadinService implements Serializable {
private ClassLoader classLoader;
+ private Iterable<RequestHandler> requestHandlers;
+
+ /**
+ * Keeps track of whether a warning about missing push support has already
+ * been logged. This is used to avoid spamming the log with the same message
+ * every time a new UI is bootstrapped.
+ */
+ private boolean pushWarningEmitted = false;
+
/**
* Creates a new vaadin service based on a deployment configuration
*
@@ -107,6 +137,45 @@ public abstract class VaadinService implements Serializable {
}
/**
+ * Initializes this service. The service should be initialized before it is
+ * used.
+ *
+ * @since 7.1
+ * @throws ServiceException
+ * if a problem occurs when creating the service
+ */
+ public void init() throws ServiceException {
+ List<RequestHandler> handlers = createRequestHandlers();
+ Collections.reverse(handlers);
+ requestHandlers = Collections.unmodifiableCollection(handlers);
+ }
+
+ /**
+ * Called during initialization to add the request handlers for the service.
+ * Note that the returned list will be reversed so the last handler will be
+ * called first. This enables overriding this method and using add on the
+ * returned list to add a custom request handler which overrides any
+ * predefined handler.
+ *
+ * @return The list of request handlers used by this service.
+ * @throws ServiceException
+ * if a problem occurs when creating the request handlers
+ */
+ protected List<RequestHandler> createRequestHandlers()
+ throws ServiceException {
+ ArrayList<RequestHandler> handlers = new ArrayList<RequestHandler>();
+ handlers.add(new SessionRequestHandler());
+ handlers.add(new PublishedFileHandler());
+ handlers.add(new HeartbeatHandler());
+ handlers.add(new FileUploadHandler());
+ handlers.add(new UidlRequestHandler());
+ handlers.add(new UnsupportedBrowserHandler());
+ handlers.add(new ConnectorResourceHandler());
+
+ return handlers;
+ }
+
+ /**
* 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.
@@ -329,18 +398,40 @@ public abstract class VaadinService implements Serializable {
SESSION_DESTROY_METHOD);
}
+ /**
+ * Handles destruction of the given session. Internally ensures proper
+ * locking is done.
+ *
+ * @param vaadinSession
+ * The session to destroy
+ */
public void fireSessionDestroy(VaadinSession vaadinSession) {
- for (UI ui : new ArrayList<UI>(vaadinSession.getUIs())) {
- // close() called here for consistency so that it is always called
- // before a UI is removed. UI.isClosing() is thus always true in
- // UI.detach() and associated detach listeners.
- if (!ui.isClosing()) {
- ui.close();
+ final VaadinSession session = vaadinSession;
+ session.access(new Runnable() {
+ @Override
+ public void run() {
+ ArrayList<UI> uis = new ArrayList<UI>(session.getUIs());
+ for (final UI ui : uis) {
+ ui.access(new Runnable() {
+ @Override
+ public void run() {
+ /*
+ * close() called here for consistency so that it is
+ * always called before a UI is removed.
+ * UI.isClosing() is thus always true in UI.detach()
+ * and associated detach listeners.
+ */
+ if (!ui.isClosing()) {
+ ui.close();
+ }
+ session.removeUI(ui);
+ }
+ });
+ }
+ eventRouter.fireEvent(new SessionDestroyEvent(
+ VaadinService.this, session));
}
- vaadinSession.removeUI(ui);
- }
-
- eventRouter.fireEvent(new SessionDestroyEvent(this, vaadinSession));
+ });
}
/**
@@ -358,6 +449,10 @@ public abstract class VaadinService implements Serializable {
/**
* Attempts to find a Vaadin service session associated with this request.
+ * <p>
+ * Handles locking of the session internally to avoid creation of duplicate
+ * sessions by two threads simultaneously.
+ * </p>
*
* @param request
* the request to get a vaadin service session for.
@@ -381,9 +476,135 @@ public abstract class VaadinService implements Serializable {
return vaadinSession;
}
+ /**
+ * Associates the given lock with this service and the given wrapped
+ * session. This method should not be called more than once when the lock is
+ * initialized for the session.
+ *
+ * @see #getSessionLock(WrappedSession)
+ * @param wrappedSession
+ * The wrapped session the lock is associated with
+ * @param lock
+ * The lock object
+ */
+ private void setSessionLock(WrappedSession wrappedSession, Lock lock) {
+ assert wrappedSession != null : "Can't set a lock for a null session";
+ assert wrappedSession.getAttribute(getLockAttributeName()) == null : "Changing the lock for a session is not allowed";
+
+ wrappedSession.setAttribute(getLockAttributeName(), lock);
+ }
+
+ /**
+ * Returns the name used to store the lock in the HTTP session.
+ *
+ * @return The attribute name for the lock
+ */
+ private String getLockAttributeName() {
+ return getServiceName() + ".lock";
+ }
+
+ /**
+ * Gets the lock instance used to lock the VaadinSession associated with the
+ * given wrapped session.
+ * <p>
+ * This method uses the wrapped session instead of VaadinSession to be able
+ * to lock even before the VaadinSession has been initialized.
+ * </p>
+ *
+ * @param wrappedSession
+ * The wrapped session
+ * @return A lock instance used for locking access to the wrapped session
+ */
+ protected Lock getSessionLock(WrappedSession wrappedSession) {
+ Object lock = wrappedSession.getAttribute(getLockAttributeName());
+
+ if (lock instanceof ReentrantLock) {
+ return (ReentrantLock) lock;
+ }
+
+ if (lock == null) {
+ return null;
+ }
+
+ throw new RuntimeException(
+ "Something else than a ReentrantLock was stored in the "
+ + getLockAttributeName() + " in the session");
+ }
+
+ /**
+ * Locks the given session for this service instance. Typically you want to
+ * call {@link VaadinSession#lock()} instead of this method.
+ *
+ * @param wrappedSession
+ * The session to lock
+ */
+ protected void lockSession(WrappedSession wrappedSession) {
+ Lock lock = getSessionLock(wrappedSession);
+ if (lock == null) {
+ /*
+ * No lock found in the session attribute. Ensure only one lock is
+ * created and used by everybody by doing double checked locking.
+ * Assumes there is a memory barrier for the attribute (i.e. that
+ * the CPU flushes its caches and reads the value directly from main
+ * memory).
+ */
+ synchronized (VaadinService.class) {
+ lock = getSessionLock(wrappedSession);
+ if (lock == null) {
+ lock = new ReentrantLock();
+ setSessionLock(wrappedSession, lock);
+ }
+ }
+ }
+ lock.lock();
+ }
+
+ /**
+ * Releases the lock for the given session for this service instance.
+ * Typically you want to call {@link VaadinSession#unlock()} instead of this
+ * method.
+ *
+ * @param wrappedSession
+ * The session to unlock
+ */
+ protected void unlockSession(WrappedSession wrappedSession) {
+ assert getSessionLock(wrappedSession) != null;
+ assert ((ReentrantLock) getSessionLock(wrappedSession))
+ .isHeldByCurrentThread() : "Trying to unlock the session but it has not been locked by this thread";
+ getSessionLock(wrappedSession).unlock();
+ }
+
private VaadinSession findOrCreateVaadinSession(VaadinRequest request)
throws SessionExpiredException, ServiceException {
boolean requestCanCreateSession = requestCanCreateSession(request);
+ WrappedSession wrappedSession = getWrappedSession(request,
+ requestCanCreateSession);
+
+ lockSession(wrappedSession);
+ try {
+ return doFindOrCreateVaadinSession(request, requestCanCreateSession);
+ } finally {
+ unlockSession(wrappedSession);
+ }
+
+ }
+
+ /**
+ * Finds or creates a Vaadin session. Assumes necessary synchronization has
+ * been done by the caller to ensure this is not called simultaneously by
+ * several threads.
+ *
+ * @param request
+ * @param requestCanCreateSession
+ * @return
+ * @throws SessionExpiredException
+ * @throws ServiceException
+ */
+ private VaadinSession doFindOrCreateVaadinSession(VaadinRequest request,
+ boolean requestCanCreateSession) throws SessionExpiredException,
+ ServiceException {
+ assert ((ReentrantLock) getSessionLock(request.getWrappedSession()))
+ .isHeldByCurrentThread() : "Session has not been locked by this thread";
/* Find an existing session for this request. */
VaadinSession session = getExistingSession(request,
@@ -395,10 +616,12 @@ public abstract class VaadinService implements Serializable {
* not specifically requested to close or restart it.
*/
- final boolean restartApplication = (request
- .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null);
- final boolean closeApplication = (request
- .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null);
+ final boolean restartApplication = hasParameter(request,
+ URL_PARAMETER_RESTART_APPLICATION)
+ && !hasParameter(request,
+ BootstrapHandler.IGNORE_RESTART_PARAM);
+ final boolean closeApplication = hasParameter(request,
+ URL_PARAMETER_CLOSE_APPLICATION);
if (restartApplication) {
closeSession(session, request.getWrappedSession(false));
@@ -429,8 +652,26 @@ public abstract class VaadinService implements Serializable {
}
+ private static boolean hasParameter(VaadinRequest request,
+ String parameterName) {
+ return request.getParameter(parameterName) != null;
+ }
+
+ /**
+ * Creates and registers a new VaadinSession for this service. Assumes
+ * proper locking has been taken care of by the caller.
+ *
+ *
+ * @param request
+ * The request which triggered session creation.
+ * @return A new VaadinSession instance
+ * @throws ServiceException
+ */
private VaadinSession createAndRegisterSession(VaadinRequest request)
throws ServiceException {
+ assert ((ReentrantLock) getSessionLock(request.getWrappedSession()))
+ .isHeldByCurrentThread() : "Session has not been locked by this thread";
+
VaadinSession session = createVaadinSession(request);
VaadinSession.setCurrent(session);
@@ -441,7 +682,7 @@ public abstract class VaadinService implements Serializable {
Locale locale = request.getLocale();
session.setLocale(locale);
session.setConfiguration(getDeploymentConfiguration());
- session.setCommunicationManager(createCommunicationManager(session));
+ session.setCommunicationManager(new LegacyCommunicationManager(session));
ServletPortletHelper.initDefaultUIProvider(session, this);
onVaadinSessionStarted(request, session);
@@ -468,23 +709,13 @@ public abstract class VaadinService implements Serializable {
}
/**
- * Create a communication manager to use for the given service session.
- *
- * @param session
- * the service session for which a new communication manager is
- * needed
- * @return a new communication manager
- */
- protected abstract AbstractCommunicationManager createCommunicationManager(
- VaadinSession session);
-
- /**
- * Creates a new Vaadin service session.
+ * Creates a new Vaadin session for this service and request
*
* @param request
- * @return
- * @throws ServletException
- * @throws MalformedURLException
+ * The request for which to create a VaadinSession
+ * @return A new VaadinSession
+ * @throws ServiceException
+ *
*/
protected VaadinSession createVaadinSession(VaadinRequest request)
throws ServiceException {
@@ -512,12 +743,8 @@ public abstract class VaadinService implements Serializable {
protected VaadinSession getExistingSession(VaadinRequest request,
boolean allowSessionCreation) throws SessionExpiredException {
- // Ensures that the session is still valid
- final WrappedSession session = request
- .getWrappedSession(allowSessionCreation);
- if (session == null) {
- throw new SessionExpiredException();
- }
+ final WrappedSession session = getWrappedSession(request,
+ allowSessionCreation);
VaadinSession vaadinSession = VaadinSession
.getForSession(this, session);
@@ -530,6 +757,28 @@ public abstract class VaadinService implements Serializable {
}
/**
+ * Retrieves the wrapped session for the request.
+ *
+ * @param request
+ * The request for which to retrieve a session
+ * @param requestCanCreateSession
+ * true to create a new session if one currently does not exist
+ * @return The retrieved (or created) wrapped session
+ * @throws SessionExpiredException
+ * If the request is not associated to a session and new session
+ * creation is not allowed
+ */
+ private WrappedSession getWrappedSession(VaadinRequest request,
+ boolean requestCanCreateSession) throws SessionExpiredException {
+ final WrappedSession session = request
+ .getWrappedSession(requestCanCreateSession);
+ if (session == null) {
+ throw new SessionExpiredException();
+ }
+ return session;
+ }
+
+ /**
* Checks whether it's valid to create a new service session as a result of
* the given request.
*
@@ -582,12 +831,21 @@ public abstract class VaadinService implements Serializable {
*/
public void setCurrentInstances(VaadinRequest request,
VaadinResponse response) {
- CurrentInstance.setInheritable(VaadinService.class, this);
+ setCurrent(this);
CurrentInstance.set(VaadinRequest.class, request);
CurrentInstance.set(VaadinResponse.class, response);
}
/**
+ * Sets the given Vaadin service as the current service.
+ *
+ * @param service
+ */
+ public static void setCurrent(VaadinService service) {
+ CurrentInstance.setInheritable(VaadinService.class, service);
+ }
+
+ /**
* Gets the currently processed Vaadin request. The current request is
* automatically defined when the request is started. The current request
* can not be used in e.g. background threads because of the way server
@@ -640,6 +898,7 @@ public abstract class VaadinService implements Serializable {
*
*/
public UI findUI(VaadinRequest request) {
+ // getForSession asserts that the lock is held
VaadinSession session = VaadinSession.getForSession(this,
request.getWrappedSession());
@@ -647,16 +906,10 @@ public abstract class VaadinService implements Serializable {
String uiIdString = request.getParameter(UIConstants.UI_ID_PARAMETER);
int uiId = Integer.parseInt(uiIdString);
- // Get lock before accessing data in session
- session.lock();
- try {
- UI ui = session.getUIById(uiId);
+ UI ui = session.getUIById(uiId);
- UI.setCurrent(ui);
- return ui;
- } finally {
- session.unlock();
- }
+ UI.setCurrent(ui);
+ return ui;
}
/**
@@ -725,8 +978,12 @@ public abstract class VaadinService implements Serializable {
// Ensure VaadinServiceSession knows where it's stored
if (value instanceof VaadinSession) {
VaadinSession serviceSession = (VaadinSession) value;
- serviceSession.storeInSession(serviceSession.getService(),
- newSession);
+ VaadinService service = serviceSession.getService();
+ // Use the same lock instance in the new session
+ service.setSessionLock(newSession,
+ serviceSession.getLockInstance());
+
+ serviceSession.storeInSession(service, newSession);
serviceSession
.setAttribute(REINITIALIZING_SESSION_MARKER, null);
}
@@ -735,6 +992,19 @@ public abstract class VaadinService implements Serializable {
}
/**
+ * TODO PUSH Document
+ *
+ * TODO Pass UI or VaadinSession?
+ *
+ * @param uI
+ * @param themeName
+ * @param resource
+ * @return
+ */
+ public abstract InputStream getThemeResourceAsStream(UI uI,
+ String themeName, String resource);
+
+ /**
* Creates and returns a unique ID for the DIV where the UI is to be
* rendered.
*
@@ -814,13 +1084,19 @@ public abstract class VaadinService implements Serializable {
*
* @param session
*/
- private void removeClosedUIs(VaadinSession session) {
- for (UI ui : new ArrayList<UI>(session.getUIs())) {
- if (ui.isClosing()) {
- getLogger().log(Level.FINER, "Removing closed UI {0}",
- ui.getUIId());
- session.removeUI(ui);
- }
+ private void removeClosedUIs(final VaadinSession session) {
+ ArrayList<UI> uis = new ArrayList<UI>(session.getUIs());
+ for (final UI ui : uis) {
+ ui.access(new Runnable() {
+ @Override
+ public void run() {
+ if (ui.isClosing()) {
+ getLogger().log(Level.FINER, "Removing closed UI {0}",
+ ui.getUIId());
+ session.removeUI(ui);
+ }
+ }
+ });
}
}
@@ -938,4 +1214,387 @@ public abstract class VaadinService implements Serializable {
private static final Logger getLogger() {
return Logger.getLogger(VaadinService.class.getName());
}
+
+ /**
+ * Called before the framework starts handling a request
+ *
+ * @param request
+ * The request
+ * @param response
+ * The response
+ */
+ public void requestStart(VaadinRequest request, VaadinResponse response) {
+ setCurrentInstances(request, response);
+ request.setAttribute(REQUEST_START_TIME_ATTRIBUTE, System.nanoTime());
+ }
+
+ /**
+ * Called after the framework has handled a request and the response has
+ * been written.
+ *
+ * @param request
+ * The request object
+ * @param response
+ * The response object
+ * @param session
+ * The session which was used during the request or null if the
+ * request did not use a session
+ */
+ public void requestEnd(VaadinRequest request, VaadinResponse response,
+ VaadinSession session) {
+ if (session != null) {
+ final VaadinSession finalSession = session;
+
+ session.access(new Runnable() {
+ @Override
+ public void run() {
+ cleanupSession(finalSession);
+ }
+ });
+
+ final long duration = (System.nanoTime() - (Long) request
+ .getAttribute(REQUEST_START_TIME_ATTRIBUTE)) / 1000000;
+ session.access(new Runnable() {
+ @Override
+ public void run() {
+ finalSession.setLastRequestDuration(duration);
+ }
+ });
+ }
+ CurrentInstance.clearAll();
+ }
+
+ /**
+ * Returns the request handlers that are registered with this service. 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 in the order they are invoked
+ *
+ * @see #createRequestHandlers()
+ *
+ * @since 7.1
+ */
+ public Iterable<RequestHandler> getRequestHandlers() {
+ return requestHandlers;
+ }
+
+ /**
+ * Handles the incoming request and writes the response into the response
+ * object. Uses {@link #getRequestHandlers()} for handling the request.
+ * <p>
+ * If a session expiration is detected during request handling then each
+ * {@link RequestHandler request handler} has an opportunity to handle the
+ * expiration event if it implements {@link SessionExpiredHandler}. If no
+ * request handler handles session expiration a default expiration message
+ * will be written.
+ * </p>
+ *
+ * @param request
+ * The incoming request
+ * @param response
+ * The outgoing response
+ * @throws ServiceException
+ * Any exception that occurs during response handling will be
+ * wrapped in a ServiceException
+ */
+ public void handleRequest(VaadinRequest request, VaadinResponse response)
+ throws ServiceException {
+ requestStart(request, response);
+
+ VaadinSession vaadinSession = null;
+ try {
+ // Find out the service session this request is related to
+ vaadinSession = findVaadinSession(request);
+ if (vaadinSession == null) {
+ return;
+ }
+
+ for (RequestHandler handler : getRequestHandlers()) {
+ if (handler.handleRequest(vaadinSession, request, response)) {
+ return;
+ }
+ }
+
+ // Request not handled by any RequestHandler
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,
+ "Request was not handled by any registered handler.");
+
+ } catch (final SessionExpiredException e) {
+ handleSessionExpired(request, response);
+ } catch (final Throwable e) {
+ handleExceptionDuringRequest(request, response, vaadinSession, e);
+ } finally {
+ requestEnd(request, response, vaadinSession);
+ }
+ }
+
+ private void handleExceptionDuringRequest(VaadinRequest request,
+ VaadinResponse response, VaadinSession vaadinSession, Throwable t)
+ throws ServiceException {
+ if (vaadinSession != null) {
+ vaadinSession.lock();
+ }
+ try {
+ ErrorHandler errorHandler = ErrorEvent
+ .findErrorHandler(vaadinSession);
+
+ // if this was an UIDL request, send UIDL back to the client
+ if (ServletPortletHelper.isUIDLRequest(request)) {
+ SystemMessages ci = getSystemMessages(
+ ServletPortletHelper.findLocale(null, vaadinSession,
+ request), request);
+ try {
+ writeStringResponse(
+ response,
+ JsonConstants.JSON_CONTENT_TYPE,
+ createCriticalNotificationJSON(
+ ci.getInternalErrorCaption(),
+ ci.getInternalErrorMessage(), null,
+ ci.getInternalErrorURL()));
+ } catch (IOException e) {
+ // An exception occured while writing the response. Log
+ // it and continue handling only the original error.
+ getLogger()
+ .log(Level.WARNING,
+ "Failed to write critical notification response to the client",
+ e);
+ }
+ if (errorHandler != null) {
+ errorHandler.error(new ErrorEvent(t));
+ }
+ } else {
+ if (errorHandler != null) {
+ errorHandler.error(new ErrorEvent(t));
+ }
+
+ // Re-throw other exceptions
+ throw new ServiceException(t);
+ }
+ } finally {
+ if (vaadinSession != null) {
+ vaadinSession.unlock();
+ }
+ }
+
+ }
+
+ /**
+ * Writes the given string as a response using the given content type.
+ *
+ * @param response
+ * The response reference
+ * @param contentType
+ * The content type of the response
+ * @param reponseString
+ * The actual response
+ * @throws IOException
+ * If an error occured while writing the response
+ */
+ public void writeStringResponse(VaadinResponse response,
+ String contentType, String reponseString) throws IOException {
+
+ response.setContentType(contentType);
+
+ final OutputStream out = response.getOutputStream();
+ final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
+ new OutputStreamWriter(out, "UTF-8")));
+ outWriter.print(reponseString);
+ outWriter.close();
+ }
+
+ /**
+ * Called when the session has expired and the request handling is therefore
+ * aborted.
+ *
+ * @param request
+ * The request
+ * @param response
+ * The response
+ * @throws ServiceException
+ * Thrown if there was any problem handling the expiration of
+ * the session
+ */
+ protected void handleSessionExpired(VaadinRequest request,
+ VaadinResponse response) throws ServiceException {
+ for (RequestHandler handler : getRequestHandlers()) {
+ if (handler instanceof SessionExpiredHandler) {
+ try {
+ if (((SessionExpiredHandler) handler).handleSessionExpired(
+ request, response)) {
+ return;
+ }
+ } catch (IOException e) {
+ throw new ServiceException(
+ "Handling of session expired failed", e);
+ }
+ }
+ }
+
+ // No request handlers handled the request. Write a normal HTTP response
+
+ try {
+ // If there is a URL, try to redirect there
+ SystemMessages systemMessages = getSystemMessages(
+ ServletPortletHelper.findLocale(null, null, request),
+ request);
+ String sessionExpiredURL = systemMessages.getSessionExpiredURL();
+ if (sessionExpiredURL != null
+ && (response instanceof VaadinServletResponse)) {
+ ((VaadinServletResponse) response)
+ .sendRedirect(sessionExpiredURL);
+ } else {
+ /*
+ * Session expired as a result of a standard http request and we
+ * have nowhere to redirect. Reloading would likely cause an
+ * endless loop. This can at least happen if refreshing a
+ * resource when the session has expired.
+ */
+ response.sendError(HttpServletResponse.SC_GONE,
+ "Session expired");
+ }
+ } catch (IOException e) {
+ throw new ServiceException(e);
+ }
+ }
+
+ /**
+ * Creates a JSON message which, when sent to client as-is, will cause a
+ * critical error to be shown with the given details.
+ *
+ * @param caption
+ * The caption of the error or null to omit
+ * @param message
+ * The error message or null to omit
+ * @param details
+ * Additional error details or null to omit
+ * @param url
+ * A url to redirect to. If no other details are given then the
+ * user will be immediately redirected to this URL. Otherwise the
+ * message will be shown and the browser will redirect to the
+ * given URL only after the user acknowledges the message. If
+ * null then the browser will refresh the current page.
+ * @return A JSON string to be sent to the client
+ */
+ public static String createCriticalNotificationJSON(String caption,
+ String message, String details, String url) {
+ String returnString = "";
+ try {
+ if (message == null) {
+ message = details;
+ } else if (details != null) {
+ message += "<br/><br/>" + details;
+ }
+
+ JSONObject appError = new JSONObject();
+ appError.put("caption", caption);
+ appError.put("message", message);
+ appError.put("url", url);
+
+ JSONObject meta = new JSONObject();
+ meta.put("appError", appError);
+
+ JSONObject json = new JSONObject();
+ json.put("changes", Collections.EMPTY_LIST);
+ json.put("resources", Collections.EMPTY_MAP);
+ json.put("locales", Collections.EMPTY_LIST);
+ json.put("meta", meta);
+ returnString = json.toString();
+ } catch (JSONException e) {
+ getLogger().log(Level.WARNING,
+ "Error creating critical notification JSON message", e);
+ }
+
+ return "for(;;);[" + returnString + "]";
+ }
+
+ /**
+ * @deprecated As of 7.0. Will likely change or be removed in a future
+ * version
+ */
+ @Deprecated
+ public void criticalNotification(VaadinRequest request,
+ VaadinResponse response, String caption, String message,
+ String details, String url) throws IOException {
+ writeStringResponse(response, JsonConstants.JSON_CONTENT_TYPE,
+ createCriticalNotificationJSON(caption, message, details, url));
+ }
+
+ /**
+ * Enables push if push support is available and push has not yet been
+ * enabled.
+ *
+ * If push support is not available, a warning explaining the situation will
+ * be logged at least the first time this method is invoked.
+ *
+ * @return <code>true</code> if push can be used; <code>false</code> if push
+ * is not available.
+ */
+ public boolean ensurePushAvailable() {
+ if (!pushWarningEmitted) {
+ pushWarningEmitted = true;
+ getLogger().log(Level.WARNING, Constants.PUSH_NOT_SUPPORTED_ERROR,
+ getClass().getSimpleName());
+ }
+ // Not supported by default for now, sublcasses may override
+ return false;
+ }
+
+ /**
+ * Checks that another {@link VaadinSession} instance is not locked. This is
+ * internally used by {@link VaadinSession#access(Runnable)} and
+ * {@link UI#access(Runnable)} to help avoid causing deadlocks.
+ *
+ * @since 7.1
+ * @param session
+ * the session that is being locked
+ * @throws IllegalStateException
+ * if the current thread holds the lock for another session
+ */
+ public static void verifyNoOtherSessionLocked(VaadinSession session) {
+ VaadinSession otherSession = VaadinSession.getCurrent();
+ if (otherSession != null && otherSession != session
+ && otherSession.hasLock()) {
+ throw new IllegalStateException(
+ "Can't access session while another session is locked by the same thread. This restriction is intended to help avoid deadlocks.");
+ }
+ }
+
+ /**
+ * Verifies that the given CSRF token (aka double submit cookie) is valid
+ * for the given session. This is used to protect against Cross Site Request
+ * Forgery attacks.
+ * <p>
+ * This protection is enabled by default, but it might need to be disabled
+ * to allow a certain type of testing. For these cases, the check can be
+ * disabled by setting the init parameter
+ * {@value Constants#SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION} to
+ * <code>true</code>.
+ *
+ * @see DeploymentConfiguration#isXsrfProtectionEnabled()
+ *
+ * @since 7.1
+ *
+ * @param session
+ * the vaadin session for which the check should be done
+ * @param requestToken
+ * the CSRF token provided in the request
+ * @return <code>true</code> if the token is valid or if the protection is
+ * disabled; <code>false</code> if protection is enabled and the
+ * token is invalid
+ */
+ public static boolean isCsrfTokenValid(VaadinSession session,
+ String requestToken) {
+
+ if (session.getService().getDeploymentConfiguration()
+ .isXsrfProtectionEnabled()) {
+ String sessionToken = session.getCsrfToken();
+
+ if (sessionToken == null || !sessionToken.equals(requestToken)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
}
diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java
index 35d5fd7cc1..de074941c1 100644
--- a/server/src/com/vaadin/server/VaadinServlet.java
+++ b/server/src/com/vaadin/server/VaadinServlet.java
@@ -24,7 +24,6 @@ import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
-import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Enumeration;
@@ -35,43 +34,18 @@ import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.vaadin.sass.internal.ScssStylesheet;
-import com.vaadin.server.AbstractCommunicationManager.Callback;
-import com.vaadin.shared.ApplicationConstants;
-import com.vaadin.ui.UI;
+import com.vaadin.server.communication.ServletUIInitHandler;
+import com.vaadin.shared.JsonConstants;
import com.vaadin.util.CurrentInstance;
@SuppressWarnings("serial")
public class VaadinServlet extends HttpServlet implements Constants {
- private static class AbstractApplicationServletWrapper implements Callback {
-
- private final VaadinServlet servlet;
-
- public AbstractApplicationServletWrapper(VaadinServlet servlet) {
- this.servlet = servlet;
- }
-
- @Override
- public void criticalNotification(VaadinRequest request,
- VaadinResponse response, String cap, String msg,
- String details, String outOfSyncURL) throws IOException {
- servlet.criticalNotification((VaadinServletRequest) request,
- ((VaadinServletResponse) response), cap, msg, details,
- outOfSyncURL);
- }
- }
-
- // TODO Move some (all?) of the constants to a separate interface (shared
- // with portlet)
-
- private final String resourcePath = null;
-
private VaadinServletService servletService;
/**
@@ -110,7 +84,11 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
DeploymentConfiguration deploymentConfiguration = createDeploymentConfiguration(initParameters);
- servletService = createServletService(deploymentConfiguration);
+ try {
+ servletService = createServletService(deploymentConfiguration);
+ } catch (ServiceException e) {
+ throw new ServletException("Could not initialize VaadinServlet", e);
+ }
// Sets current service even though there are no request and response
servletService.setCurrentInstances(null, null);
@@ -168,8 +146,12 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
protected VaadinServletService createServletService(
- DeploymentConfiguration deploymentConfiguration) {
- return new VaadinServletService(this, deploymentConfiguration);
+ DeploymentConfiguration deploymentConfiguration)
+ throws ServiceException {
+ VaadinServletService service = new VaadinServletService(this,
+ deploymentConfiguration);
+ service.init();
+ return service;
}
/**
@@ -198,7 +180,23 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
CurrentInstance.clearAll();
setCurrent(this);
- service(createVaadinRequest(request), createVaadinResponse(response));
+
+ VaadinServletRequest vaadinRequest = createVaadinRequest(request);
+ VaadinServletResponse vaadinResponse = createVaadinResponse(response);
+ if (!ensureCookiesEnabled(vaadinRequest, vaadinResponse)) {
+ return;
+ }
+
+ if (isStaticResourceRequest(request)) {
+ serveStaticResources(request, response);
+ return;
+ }
+ try {
+ getService().handleRequest(vaadinRequest, vaadinResponse);
+ } catch (ServiceException e) {
+ throw new ServletException(e);
+ }
+
}
/**
@@ -218,7 +216,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
*/
protected boolean handleContextRootWithoutSlash(HttpServletRequest request,
HttpServletResponse response) throws IOException {
- if ("/".equals(request.getPathInfo())
+ if ((request.getPathInfo() == null || "/".equals(request.getPathInfo()))
&& "".equals(request.getServletPath())
&& !request.getRequestURI().endsWith("/")) {
/*
@@ -237,119 +235,6 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
}
- private void service(VaadinServletRequest request,
- VaadinServletResponse response) throws ServletException,
- IOException {
- RequestTimer requestTimer = new RequestTimer();
- requestTimer.start();
-
- getService().setCurrentInstances(request, response);
-
- AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper(
- this);
-
- RequestType requestType = getRequestType(request);
- if (!ensureCookiesEnabled(requestType, request, response)) {
- return;
- }
-
- if (requestType == RequestType.STATIC_FILE) {
- serveStaticResources(request, response);
- return;
- }
-
- VaadinSession vaadinSession = null;
-
- try {
- // If a duplicate "close application" URL is received for an
- // application that is not open, redirect to the application's main
- // page.
- // This is needed as e.g. Spring Security remembers the last
- // URL from the application, which is the logout URL, and repeats
- // it.
- // We can tell apart a real onunload request from a repeated one
- // based on the real one having content (at least the UIDL security
- // key).
- if (requestType == RequestType.UIDL
- && request.getParameterMap().containsKey(
- ApplicationConstants.PARAM_UNLOADBURST)
- && request.getContentLength() < 1
- && getService().getExistingSession(request, false) == null) {
- redirectToApplication(request, response);
- return;
- }
-
- // Find out the service session this request is related to
- vaadinSession = getService().findVaadinSession(request);
- if (vaadinSession == null) {
- return;
- }
-
- CommunicationManager communicationManager = (CommunicationManager) vaadinSession
- .getCommunicationManager();
-
- if (requestType == RequestType.PUBLISHED_FILE) {
- communicationManager.servePublishedFile(request, response);
- return;
- } else if (requestType == RequestType.HEARTBEAT) {
- communicationManager.handleHeartbeatRequest(request, response,
- vaadinSession);
- return;
- }
-
- /* Update browser information from the request */
- vaadinSession.getBrowser().updateRequestDetails(request);
-
- /* Handle the request */
- if (requestType == RequestType.FILE_UPLOAD) {
- // UI is resolved in communication manager
- communicationManager.handleFileUpload(vaadinSession, request,
- response);
- return;
- } else if (requestType == RequestType.UIDL) {
- UI uI = getService().findUI(request);
- if (uI == null) {
- throw new ServletException(ERROR_NO_UI_FOUND);
- }
- // Handles AJAX UIDL requests
- communicationManager.handleUidlRequest(request, response,
- servletWrapper, uI);
-
- // Ensure that the browser does not cache UIDL responses.
- // iOS 6 Safari requires this (#9732)
- response.setHeader("Cache-Control", "no-cache");
-
- return;
- } else if (requestType == RequestType.BROWSER_DETAILS) {
- // Browser details - not related to a specific UI
- communicationManager.handleBrowserDetailsRequest(request,
- response, vaadinSession);
- return;
- }
-
- if (communicationManager.handleOtherRequest(request, response)) {
- return;
- }
-
- // Request not handled by any RequestHandler -> 404
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
-
- } catch (final SessionExpiredException e) {
- // Session has expired, notify user
- handleServiceSessionExpired(request, response);
- } catch (final GeneralSecurityException e) {
- handleServiceSecurityException(request, response);
- } catch (final Throwable e) {
- handleServiceException(request, response, vaadinSession, e);
- } finally {
- if (vaadinSession != null) {
- getService().cleanupSession(vaadinSession);
- requestTimer.stop(vaadinSession);
- }
- CurrentInstance.clearAll();
- }
- }
-
private VaadinServletResponse createVaadinResponse(
HttpServletResponse response) {
return new VaadinServletResponse(response, getService());
@@ -391,10 +276,9 @@ public class VaadinServlet extends HttpServlet implements Constants {
* @return false if cookies are disabled, true otherwise
* @throws IOException
*/
- private boolean ensureCookiesEnabled(RequestType requestType,
- VaadinServletRequest request, VaadinServletResponse response)
- throws IOException {
- if (requestType == RequestType.UIDL) {
+ private boolean ensureCookiesEnabled(VaadinServletRequest request,
+ VaadinServletResponse response) throws IOException {
+ if (ServletPortletHelper.isUIDLRequest(request)) {
// In all other but the first UIDL request a cookie should be
// returned by the browser.
// This can be removed if cookieless mode (#3228) is supported
@@ -403,10 +287,13 @@ public class VaadinServlet extends HttpServlet implements Constants {
SystemMessages systemMessages = getService().getSystemMessages(
ServletPortletHelper.findLocale(null, null, request),
request);
- criticalNotification(request, response,
- systemMessages.getCookiesDisabledCaption(),
- systemMessages.getCookiesDisabledMessage(), null,
- systemMessages.getCookiesDisabledURL());
+ getService().writeStringResponse(
+ response,
+ JsonConstants.JSON_CONTENT_TYPE,
+ VaadinService.createCriticalNotificationJSON(
+ systemMessages.getCookiesDisabledCaption(),
+ systemMessages.getCookiesDisabledMessage(),
+ null, systemMessages.getCookiesDisabledURL()));
return false;
}
}
@@ -437,39 +324,19 @@ public class VaadinServlet extends HttpServlet implements Constants {
* @throws IOException
* if the writing failed due to input/output error.
*
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * @deprecated As of 7.0. This method is retained only for backwards
+ * compatibility and for {@link GAEVaadinServlet}.
*/
@Deprecated
protected void criticalNotification(VaadinServletRequest request,
- HttpServletResponse response, String caption, String message,
+ VaadinServletResponse response, String caption, String message,
String details, String url) throws IOException {
if (ServletPortletHelper.isUIDLRequest(request)) {
-
- if (caption != null) {
- caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\"";
- }
- if (details != null) {
- if (message == null) {
- message = details;
- } else {
- message += "<br/><br/>" + details;
- }
- }
-
- if (message != null) {
- message = "\"" + JsonPaintTarget.escapeJSON(message) + "\"";
- }
- if (url != null) {
- url = "\"" + JsonPaintTarget.escapeJSON(url) + "\"";
- }
-
- String output = "for(;;);[{\"changes\":[], \"meta\" : {"
- + "\"appError\": {" + "\"caption\":" + caption + ","
- + "\"message\" : " + message + "," + "\"url\" : " + url
- + "}}, \"resources\": {}, \"locales\":[]}]";
- writeResponse(response, "application/json; charset=UTF-8", output);
+ String output = VaadinService.createCriticalNotificationJSON(
+ caption, message, details, url);
+ getService().writeStringResponse(response,
+ JsonConstants.JSON_CONTENT_TYPE, output);
} else {
// Create an HTML reponse with the error
String output = "";
@@ -492,10 +359,9 @@ public class VaadinServlet extends HttpServlet implements Constants {
if (url != null) {
output += "</a>";
}
- writeResponse(response, "text/html; charset=UTF-8", output);
-
+ getService().writeStringResponse(response,
+ "text/html; charset=UTF-8", output);
}
-
}
/**
@@ -511,7 +377,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
private void writeResponse(HttpServletResponse response,
String contentType, String output) throws IOException {
response.setContentType(contentType);
- final ServletOutputStream out = response.getOutputStream();
+ final OutputStream out = response.getOutputStream();
// Set the response type
final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(out, "UTF-8")));
@@ -555,33 +421,6 @@ public class VaadinServlet extends HttpServlet implements Constants {
return resultPath;
}
- private void handleServiceException(VaadinServletRequest request,
- VaadinServletResponse response, VaadinSession vaadinSession,
- Throwable e) throws IOException, ServletException {
- ErrorHandler errorHandler = ErrorEvent.findErrorHandler(vaadinSession);
-
- // if this was an UIDL request, response UIDL back to client
- if (getRequestType(request) == RequestType.UIDL) {
- SystemMessages ci = getService().getSystemMessages(
- ServletPortletHelper.findLocale(null, vaadinSession,
- request), request);
- criticalNotification(request, response,
- ci.getInternalErrorCaption(), ci.getInternalErrorMessage(),
- null, ci.getInternalErrorURL());
- if (errorHandler != null) {
- errorHandler.error(new ErrorEvent(e));
- }
- } else {
- if (errorHandler != null) {
- errorHandler.error(new ErrorEvent(e));
- }
-
- // Re-throw other exceptions
- throw new ServletException(e);
- }
-
- }
-
/**
* A helper method to strip away characters that might somehow be used for
* XSS attacs. Leaves at least alphanumeric characters intact. Also removes
@@ -626,74 +465,9 @@ public class VaadinServlet extends HttpServlet implements Constants {
return DEFAULT_THEME_NAME;
}
- /**
- * @param request
- * @param response
- * @throws IOException
- * @throws ServletException
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
- */
- @Deprecated
- void handleServiceSessionExpired(VaadinServletRequest request,
- VaadinServletResponse response) throws IOException,
- ServletException {
-
- if (isOnUnloadRequest(request)) {
- /*
- * Request was an unload request (e.g. window close event) and the
- * client expects no response if it fails.
- */
- return;
- }
-
- try {
- SystemMessages ci = getService().getSystemMessages(
- ServletPortletHelper.findLocale(null, null, request),
- request);
- RequestType requestType = getRequestType(request);
- if (requestType == RequestType.UIDL) {
- /*
- * Invalidate session (weird to have session if we're saying
- * that it's expired, and worse: portal integration will fail
- * since the session is not created by the portal.
- *
- * Session must be invalidated before criticalNotification as it
- * commits the response.
- */
- request.getSession().invalidate();
-
- // send uidl redirect
- criticalNotification(request, response,
- ci.getSessionExpiredCaption(),
- ci.getSessionExpiredMessage(), null,
- ci.getSessionExpiredURL());
-
- } else if (requestType == RequestType.HEARTBEAT) {
- response.sendError(HttpServletResponse.SC_GONE,
- "Session expired");
- } else {
- // 'plain' http req - e.g. browser reload;
- // just go ahead redirect the browser
- response.sendRedirect(ci.getSessionExpiredURL());
- }
- } catch (SystemMessageException ee) {
- throw new ServletException(ee);
- }
-
- }
-
private void handleServiceSecurityException(VaadinServletRequest request,
VaadinServletResponse response) throws IOException,
ServletException {
- if (isOnUnloadRequest(request)) {
- /*
- * Request was an unload request (e.g. window close event) and the
- * client expects no response if it fails.
- */
- return;
- }
try {
/*
@@ -702,20 +476,17 @@ public class VaadinServlet extends HttpServlet implements Constants {
*/
SystemMessages ci = getService().getSystemMessages(
request.getLocale(), request);
- RequestType requestType = getRequestType(request);
- if (requestType == RequestType.UIDL) {
+ if (ServletPortletHelper.isUIDLRequest(request)) {
// send uidl redirect
- criticalNotification(request, response,
- ci.getCommunicationErrorCaption(),
- ci.getCommunicationErrorMessage(),
- INVALID_SECURITY_KEY_MSG, ci.getCommunicationErrorURL());
- /*
- * Invalidate session. Portal integration will fail otherwise
- * since the session is not created by the portal.
- */
- request.getSession().invalidate();
-
- } else if (requestType == RequestType.HEARTBEAT) {
+ getService().writeStringResponse(
+ response,
+ JsonConstants.JSON_CONTENT_TYPE,
+ VaadinService.createCriticalNotificationJSON(
+ ci.getCommunicationErrorCaption(),
+ ci.getCommunicationErrorMessage(),
+ INVALID_SECURITY_KEY_MSG,
+ ci.getCommunicationErrorURL()));
+ } else if (ServletPortletHelper.isHeartbeatRequest(request)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN,
"Forbidden");
} else {
@@ -744,9 +515,8 @@ public class VaadinServlet extends HttpServlet implements Constants {
private boolean serveStaticResources(HttpServletRequest request,
HttpServletResponse response) throws IOException, ServletException {
- // FIXME What does 10 refer to?
String pathInfo = request.getPathInfo();
- if (pathInfo == null || pathInfo.length() <= 10) {
+ if (pathInfo == null) {
return false;
}
@@ -1118,10 +888,12 @@ public class VaadinServlet extends HttpServlet implements Constants {
/**
*
* @author Vaadin Ltd
- * @since 7.0.0
+ * @since 7.0
*
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * @deprecated As of 7.0. This is no longer used and only provided for
+ * backwards compatibility. Each {@link RequestHandler} can
+ * individually decide whether it wants to handle a request or
+ * not.
*/
@Deprecated
protected enum RequestType {
@@ -1132,8 +904,10 @@ public class VaadinServlet extends HttpServlet implements Constants {
* @param request
* @return
*
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * @deprecated As of 7.0. This is no longer used and only provided for
+ * backwards compatibility. Each {@link RequestHandler} can
+ * individually decide whether it wants to handle a request or
+ * not.
*/
@Deprecated
protected RequestType getRequestType(VaadinServletRequest request) {
@@ -1141,7 +915,7 @@ public class VaadinServlet extends HttpServlet implements Constants {
return RequestType.FILE_UPLOAD;
} else if (ServletPortletHelper.isPublishedFileRequest(request)) {
return RequestType.PUBLISHED_FILE;
- } else if (isBrowserDetailsRequest(request)) {
+ } else if (ServletUIInitHandler.isUIInitRequest(request)) {
return RequestType.BROWSER_DETAILS;
} else if (ServletPortletHelper.isUIDLRequest(request)) {
return RequestType.UIDL;
@@ -1156,14 +930,9 @@ public class VaadinServlet extends HttpServlet implements Constants {
}
- private static boolean isBrowserDetailsRequest(HttpServletRequest request) {
- return "POST".equals(request.getMethod())
- && request.getParameter("v-browserDetails") != null;
- }
-
- private boolean isStaticResourceRequest(HttpServletRequest request) {
+ protected boolean isStaticResourceRequest(HttpServletRequest request) {
String pathInfo = request.getPathInfo();
- if (pathInfo == null || pathInfo.length() <= 10) {
+ if (pathInfo == null) {
return false;
}
@@ -1178,10 +947,6 @@ public class VaadinServlet extends HttpServlet implements Constants {
return false;
}
- private boolean isOnUnloadRequest(HttpServletRequest request) {
- return request.getParameter(ApplicationConstants.PARAM_UNLOADBURST) != null;
- }
-
/**
* Remove any heading or trailing "what" from the "string".
*
@@ -1301,4 +1066,5 @@ public class VaadinServlet extends HttpServlet implements Constants {
private static final Logger getLogger() {
return Logger.getLogger(VaadinServlet.class.getName());
}
+
}
diff --git a/server/src/com/vaadin/server/VaadinServletService.java b/server/src/com/vaadin/server/VaadinServletService.java
index 71f47ea217..3b39f17849 100644
--- a/server/src/com/vaadin/server/VaadinServletService.java
+++ b/server/src/com/vaadin/server/VaadinServletService.java
@@ -17,19 +17,38 @@
package com.vaadin.server;
import java.io.File;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
-import com.vaadin.server.VaadinServlet.RequestType;
+import org.atmosphere.util.Version;
+
+import com.vaadin.server.communication.PushRequestHandler;
+import com.vaadin.server.communication.ServletBootstrapHandler;
+import com.vaadin.server.communication.ServletUIInitHandler;
import com.vaadin.ui.UI;
public class VaadinServletService extends VaadinService {
private final VaadinServlet servlet;
+ private final static boolean atmosphereAvailable = checkAtmosphereSupport();
+
+ /**
+ * Keeps track of whether a warning about missing push support has already
+ * been logged. This is used to avoid spamming the log with the same message
+ * every time a new UI is bootstrapped.
+ */
+ private boolean pushWarningLogged = false;
+
public VaadinServletService(VaadinServlet servlet,
- DeploymentConfiguration deploymentConfiguration) {
+ DeploymentConfiguration deploymentConfiguration)
+ throws ServiceException {
super(deploymentConfiguration);
this.servlet = servlet;
@@ -44,7 +63,40 @@ public class VaadinServletService extends VaadinService {
}
}
- protected VaadinServlet getServlet() {
+ private static boolean checkAtmosphereSupport() {
+ try {
+ String rawVersion = Version.getRawVersion();
+ if (!Constants.REQUIRED_ATMOSPHERE_VERSION.equals(rawVersion)) {
+ getLogger().log(
+ Level.WARNING,
+ Constants.INVALID_ATMOSPHERE_VERSION_WARNING,
+ new Object[] { Constants.REQUIRED_ATMOSPHERE_VERSION,
+ rawVersion });
+ }
+ return true;
+ } catch (NoClassDefFoundError e) {
+ return false;
+ }
+ }
+
+ @Override
+ protected List<RequestHandler> createRequestHandlers()
+ throws ServiceException {
+ List<RequestHandler> handlers = super.createRequestHandlers();
+ handlers.add(0, new ServletBootstrapHandler());
+ handlers.add(new ServletUIInitHandler());
+ if (atmosphereAvailable) {
+ handlers.add(new PushRequestHandler(this));
+ }
+ return handlers;
+ }
+
+ /**
+ * Retrieves a reference to the servlet associated with this service.
+ *
+ * @return A reference to the VaadinServlet this service is using
+ */
+ public VaadinServlet getServlet() {
return servlet;
}
@@ -127,12 +179,11 @@ public class VaadinServletService extends VaadinService {
@Override
protected boolean requestCanCreateSession(VaadinRequest request) {
- RequestType requestType = getRequestType(request);
- if (requestType == RequestType.BROWSER_DETAILS) {
+ if (ServletUIInitHandler.isUIInitRequest(request)) {
// This is the first request if you are embedding by writing the
// embedding code yourself
return true;
- } else if (requestType == RequestType.OTHER) {
+ } else if (isOtherRequest(request)) {
/*
* I.e URIs that are not RPC calls or static (theme) files.
*/
@@ -142,25 +193,16 @@ public class VaadinServletService extends VaadinService {
return false;
}
- /**
- * Gets the request type for the request.
- *
- * @param request
- * the request to get a request type for
- * @return the request type
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
- */
- @Deprecated
- protected RequestType getRequestType(VaadinRequest request) {
- RequestType type = (RequestType) request.getAttribute(RequestType.class
- .getName());
- if (type == null) {
- type = getServlet().getRequestType((VaadinServletRequest) request);
- request.setAttribute(RequestType.class.getName(), type);
- }
- return type;
+ private boolean isOtherRequest(VaadinRequest request) {
+ // TODO This should be refactored in some way. It should not be
+ // necessary to check all these types.
+ return (!ServletPortletHelper.isAppRequest(request)
+ && !ServletUIInitHandler.isUIInitRequest(request)
+ && !ServletPortletHelper.isFileUploadRequest(request)
+ && !ServletPortletHelper.isHeartbeatRequest(request)
+ && !ServletPortletHelper.isPublishedFileRequest(request)
+ && !ServletPortletHelper.isUIDLRequest(request) && !ServletPortletHelper
+ .isPushRequest(request));
}
@Override
@@ -169,12 +211,6 @@ public class VaadinServletService extends VaadinService {
return getServlet().getApplicationUrl((VaadinServletRequest) request);
}
- @Override
- protected AbstractCommunicationManager createCommunicationManager(
- VaadinSession session) {
- return new CommunicationManager(session);
- }
-
public static HttpServletRequest getCurrentServletRequest() {
VaadinRequest currentRequest = VaadinService.getCurrentRequest();
if (currentRequest instanceof VaadinServletRequest) {
@@ -194,6 +230,18 @@ public class VaadinServletService extends VaadinService {
}
@Override
+ public InputStream getThemeResourceAsStream(UI uI, String themeName,
+ String resource) {
+ VaadinServletService service = (VaadinServletService) uI.getSession()
+ .getService();
+ ServletContext servletContext = service.getServlet()
+ .getServletContext();
+ return servletContext.getResourceAsStream("/"
+ + VaadinServlet.THEME_DIR_PATH + '/' + themeName + "/"
+ + resource);
+ }
+
+ @Override
public String getMainDivId(VaadinSession session, VaadinRequest request,
Class<? extends UI> uiClass) {
String appId = null;
@@ -220,4 +268,22 @@ public class VaadinServletService extends VaadinService {
appId = appId + "-" + hashCode;
return appId;
}
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(VaadinServletService.class.getName());
+ }
+
+ @Override
+ public boolean ensurePushAvailable() {
+ if (atmosphereAvailable) {
+ return true;
+ } else {
+ if (!pushWarningLogged) {
+ pushWarningLogged = true;
+ getLogger().log(Level.WARNING,
+ Constants.ATMOSPHERE_MISSING_ERROR);
+ }
+ return false;
+ }
+ }
}
diff --git a/server/src/com/vaadin/server/VaadinSession.java b/server/src/com/vaadin/server/VaadinSession.java
index d3619ebabf..317ea6cf7b 100644
--- a/server/src/com/vaadin/server/VaadinSession.java
+++ b/server/src/com/vaadin/server/VaadinSession.java
@@ -25,6 +25,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.UUID;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;
@@ -39,6 +40,7 @@ import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.ConverterFactory;
import com.vaadin.data.util.converter.DefaultConverterFactory;
import com.vaadin.event.EventRouter;
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.Table;
import com.vaadin.ui.UI;
@@ -73,8 +75,6 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
.findMethod(BootstrapListener.class, "modifyBootstrapPage",
BootstrapPageResponse.class);
- private final Lock lock = new ReentrantLock();
-
/**
* Configuration for the session.
*/
@@ -110,7 +110,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
protected WebBrowser browser = new WebBrowser();
- private AbstractCommunicationManager communicationManager;
+ private LegacyCommunicationManager communicationManager;
private long cumulativeRequestDuration = 0;
@@ -128,6 +128,8 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
private transient VaadinService service;
+ private transient Lock lock;
+
/**
* Create a new service session tied to a Vaadin service
*
@@ -162,6 +164,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
+ "This might happen if a session is deserialized but never used before it expires.");
} else if (VaadinService.getCurrentRequest() != null
&& getCurrent() == this) {
+ assert hasLock();
// Ignore if the session is being moved to a different backing
// session
if (getAttribute(VaadinService.REINITIALIZING_SESSION_MARKER) == Boolean.TRUE) {
@@ -192,6 +195,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*/
@Deprecated
public WebBrowser getBrowser() {
+ assert hasLock();
return browser;
}
@@ -200,6 +204,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* milliseconds.
*/
public long getCumulativeRequestDuration() {
+ assert hasLock();
return cumulativeRequestDuration;
}
@@ -211,6 +216,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* The time spent in the last request, in milliseconds.
*/
public void setLastRequestDuration(long time) {
+ assert hasLock();
lastRequestDuration = time;
cumulativeRequestDuration += time;
}
@@ -220,6 +226,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* milliseconds.
*/
public long getLastRequestDuration() {
+ assert hasLock();
return lastRequestDuration;
}
@@ -232,6 +239,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*
*/
public void setLastRequestTimestamp(long timestamp) {
+ assert hasLock();
lastRequestTimestamp = timestamp;
}
@@ -242,6 +250,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the epoch.
*/
public long getLastRequestTimestamp() {
+ assert hasLock();
return lastRequestTimestamp;
}
@@ -252,6 +261,11 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return the wrapped session for this context
*/
public WrappedSession getSession() {
+ /*
+ * This is used to fetch the underlying session and there is no need for
+ * having a lock when doing this. On the contrary this is sometimes done
+ * to be able to lock the session.
+ */
return session;
}
@@ -262,65 +276,97 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* version
*/
@Deprecated
- public AbstractCommunicationManager getCommunicationManager() {
+ public LegacyCommunicationManager getCommunicationManager() {
+ assert hasLock();
return communicationManager;
}
/**
+ * Loads the VaadinSession for the given service and WrappedSession from the
+ * HTTP session.
+ *
* @param service
- * TODO
+ * The service the VaadinSession is associated with
* @param underlyingSession
- * @return
- *
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * The wrapped HTTP session for the user
+ * @return A VaadinSession instance for the service, session combination or
+ * null if none was found.
+ * @deprecated As of 7.0. Should be moved to a separate session storage
+ * class some day.
*/
@Deprecated
public static VaadinSession getForSession(VaadinService service,
WrappedSession underlyingSession) {
- Object attribute = underlyingSession.getAttribute(VaadinSession.class
- .getName() + "." + service.getServiceName());
- if (attribute instanceof VaadinSession) {
- VaadinSession vaadinSession = (VaadinSession) attribute;
- vaadinSession.session = underlyingSession;
- vaadinSession.service = service;
- return vaadinSession;
+ assert hasLock(service, underlyingSession);
+
+ VaadinSession vaadinSession = (VaadinSession) underlyingSession
+ .getAttribute(getSessionAttributeName(service));
+ if (vaadinSession == null) {
+ return null;
}
- return null;
+ vaadinSession.session = underlyingSession;
+ vaadinSession.service = service;
+ vaadinSession.refreshLock();
+ return vaadinSession;
}
/**
+ * Removes this VaadinSession from the HTTP session.
*
* @param service
- * TODO
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * The service this session is associated with
+ * @deprecated As of 7.0. Should be moved to a separate session storage
+ * class some day.
*/
@Deprecated
public void removeFromSession(VaadinService service) {
- assert (getForSession(service, session) == this);
- session.setAttribute(
- VaadinSession.class.getName() + "." + service.getServiceName(),
- null);
+ assert hasLock();
+ session.removeAttribute(getSessionAttributeName(service));
}
/**
- * @param session
+ * Retrieves the name of the attribute used for storing a VaadinSession for
+ * the given service.
*
- * @deprecated As of 7.0. Will likely change or be removed in a future
- * version
+ * @param service
+ * The service associated with the sessio
+ * @return The attribute name used for storing the session
+ */
+ private static String getSessionAttributeName(VaadinService service) {
+ return VaadinSession.class.getName() + "." + service.getServiceName();
+ }
+
+ /**
+ * Stores this VaadinSession in the HTTP session.
+ *
+ * @param service
+ * The service this session is associated with
+ * @param session
+ * The HTTP session this VaadinSession should be stored in
+ * @deprecated As of 7.0. Should be moved to a separate session storage
+ * class some day.
*/
@Deprecated
public void storeInSession(VaadinService service, WrappedSession session) {
- session.setAttribute(
- VaadinSession.class.getName() + "." + service.getServiceName(),
- this);
+ assert hasLock(service, session);
+ session.setAttribute(getSessionAttributeName(service), this);
this.session = session;
+ refreshLock();
+ }
+
+ /**
+ * Updates the transient session lock from VaadinService.
+ */
+ private void refreshLock() {
+ assert lock == null || lock == service.getSessionLock(session) : "Cannot change the lock from one instance to another";
+ assert hasLock(service, session);
+ lock = service.getSessionLock(session);
}
public void setCommunicationManager(
- AbstractCommunicationManager communicationManager) {
+ LegacyCommunicationManager communicationManager) {
+ assert hasLock();
if (communicationManager == null) {
throw new IllegalArgumentException("Can not set to null");
}
@@ -329,6 +375,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
}
public void setConfiguration(DeploymentConfiguration configuration) {
+ assert hasLock();
if (configuration == null) {
throw new IllegalArgumentException("Can not set to null");
}
@@ -342,6 +389,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return the deployment configuration
*/
public DeploymentConfiguration getConfiguration() {
+ assert hasLock();
return configuration;
}
@@ -354,6 +402,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return the locale of this session.
*/
public Locale getLocale() {
+ assert hasLock();
if (locale != null) {
return locale;
}
@@ -371,6 +420,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*
*/
public void setLocale(Locale locale) {
+ assert hasLock();
this.locale = locale;
}
@@ -380,6 +430,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return the current error handler
*/
public ErrorHandler getErrorHandler() {
+ assert hasLock();
return errorHandler;
}
@@ -389,6 +440,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @param errorHandler
*/
public void setErrorHandler(ErrorHandler errorHandler) {
+ assert hasLock();
this.errorHandler = errorHandler;
}
@@ -401,6 +453,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return The converter factory used in the session
*/
public ConverterFactory getConverterFactory() {
+ assert hasLock();
return converterFactory;
}
@@ -426,6 +479,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* The converter factory used in the session
*/
public void setConverterFactory(ConverterFactory converterFactory) {
+ assert hasLock();
this.converterFactory = converterFactory;
}
@@ -446,6 +500,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @since 7.0
*/
public void addRequestHandler(RequestHandler handler) {
+ assert hasLock();
requestHandlers.addFirst(handler);
}
@@ -458,6 +513,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @since 7.0
*/
public void removeRequestHandler(RequestHandler handler) {
+ assert hasLock();
requestHandlers.remove(handler);
}
@@ -475,6 +531,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @since 7.0
*/
public Collection<RequestHandler> getRequestHandlers() {
+ assert hasLock();
return Collections.unmodifiableCollection(requestHandlers);
}
@@ -528,11 +585,14 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @since 7.0
*/
public Collection<UI> getUIs() {
+ assert hasLock();
return Collections.unmodifiableCollection(uIs.values());
}
private int connectorIdSequence = 0;
+ private final String csrfToken = UUID.randomUUID().toString();
+
/**
* Generate an id for the given Connector. Connectors must not call this
* method more than once, the first time they need an id.
@@ -546,6 +606,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*/
@Deprecated
public String createConnectorId(ClientConnector connector) {
+ assert hasLock();
return String.valueOf(connectorIdSequence++);
}
@@ -560,10 +621,32 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return The UI with the given id or null if not found
*/
public UI getUIById(int uiId) {
+ assert hasLock();
return uIs.get(uiId);
}
/**
+ * Checks if the current thread has exclusive access to this VaadinSession
+ *
+ * @return true if the thread has exclusive access, false otherwise
+ */
+ public boolean hasLock() {
+ ReentrantLock l = ((ReentrantLock) getLockInstance());
+ return l.isHeldByCurrentThread();
+ }
+
+ /**
+ * Checks if the current thread has exclusive access to the given
+ * WrappedSession.
+ *
+ * @return true if this thread has exclusive access, false otherwise
+ */
+ private static boolean hasLock(VaadinService service, WrappedSession session) {
+ ReentrantLock l = (ReentrantLock) service.getSessionLock(session);
+ return l.isHeldByCurrentThread();
+ }
+
+ /**
* Adds a listener that will be invoked when the bootstrap HTML is about to
* be generated. This can be used to modify the contents of the HTML that
* loads the Vaadin application in the browser and the HTTP headers that are
@@ -576,6 +659,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the bootstrap listener to add
*/
public void addBootstrapListener(BootstrapListener listener) {
+ assert hasLock();
eventRouter.addListener(BootstrapFragmentResponse.class, listener,
BOOTSTRAP_FRAGMENT_METHOD);
eventRouter.addListener(BootstrapPageResponse.class, listener,
@@ -591,6 +675,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the bootstrap listener to remove
*/
public void removeBootstrapListener(BootstrapListener listener) {
+ assert hasLock();
eventRouter.removeListener(BootstrapFragmentResponse.class, listener,
BOOTSTRAP_FRAGMENT_METHOD);
eventRouter.removeListener(BootstrapPageResponse.class, listener,
@@ -611,6 +696,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*/
@Deprecated
public void modifyBootstrapResponse(BootstrapResponse response) {
+ assert hasLock();
eventRouter.fireEvent(response);
}
@@ -622,6 +708,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the UI to remove
*/
public void removeUI(UI ui) {
+ assert hasLock();
int id = ui.getUIId();
ui.setSession(null);
uIs.remove(id);
@@ -646,6 +733,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @since 7.0.0
*/
public GlobalResourceHandler getGlobalResourceHandler(boolean createOnDemand) {
+ assert hasLock();
if (globalResourceHandler == null && createOnDemand) {
globalResourceHandler = new GlobalResourceHandler();
addRequestHandler(globalResourceHandler);
@@ -677,9 +765,24 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
/**
* Locks this session to protect its data from concurrent access. Accessing
* the UI state from outside the normal request handling should always lock
- * the session and unlock it when done. To ensure that the lock is always
- * released, you should typically wrap the code in a <code>try</code> block
- * and unlock the session in <code>finally</code>:
+ * the session and unlock it when done. The preferred way to ensure locking
+ * is done correctly is to wrap your code using {@link UI#access(Runnable)}
+ * (or {@link VaadinSession#access(Runnable)} if you are only touching the
+ * session and not any UI), e.g.:
+ *
+ * <pre>
+ * myUI.access(new Runnable() {
+ * &#064;Override
+ * public void run() {
+ * // Here it is safe to update the UI.
+ * // UI.getCurrent can also be used
+ * myUI.getContent().setCaption(&quot;Changed safely&quot;);
+ * }
+ * });
+ * </pre>
+ *
+ * If you for whatever reason want to do locking manually, you should do it
+ * like:
*
* <pre>
* session.lock();
@@ -689,7 +792,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* session.unlock();
* }
* </pre>
- * <p>
+ *
* This method will block until the lock can be retrieved.
* <p>
* {@link #getLockInstance()} can be used if more control over the locking
@@ -697,6 +800,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*
* @see #unlock()
* @see #getLockInstance()
+ * @see #hasLock()
*/
public void lock() {
getLockInstance().lock();
@@ -705,11 +809,29 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
/**
* Unlocks this session. This method should always be used in a finally
* block after {@link #lock()} to ensure that the lock is always released.
+ * <p>
+ * If {@link #getPushMode() the push mode} is {@link PushMode#AUTOMATIC
+ * automatic}, pushes the changes in all UIs in this session to their
+ * respective clients.
*
- * @see #unlock()
+ * @see #lock()
+ * @see UI#push()
*/
public void unlock() {
- getLockInstance().unlock();
+ assert hasLock();
+ try {
+ if (((ReentrantLock) getLockInstance()).getHoldCount() == 1) {
+ // Only push if the reentrant lock will actually be released by
+ // this unlock() invocation.
+ for (UI ui : getUIs()) {
+ if (ui.getPushMode() == PushMode.AUTOMATIC) {
+ ui.push();
+ }
+ }
+ }
+ } finally {
+ getLockInstance().unlock();
+ }
}
/**
@@ -728,6 +850,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* remove a previous association.
*/
public void setAttribute(String name, Object value) {
+ assert hasLock();
if (name == null) {
throw new IllegalArgumentException("name can not be null");
}
@@ -759,6 +882,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* remove a previous association.
*/
public <T> void setAttribute(Class<T> type, T value) {
+ assert hasLock();
if (type == null) {
throw new IllegalArgumentException("type can not be null");
}
@@ -783,6 +907,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* it has been set to null.
*/
public Object getAttribute(String name) {
+ assert hasLock();
if (name == null) {
throw new IllegalArgumentException("name can not be null");
}
@@ -808,6 +933,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* it has been set to null.
*/
public <T> T getAttribute(Class<T> type) {
+ assert hasLock();
if (type == null) {
throw new IllegalArgumentException("type can not be null");
}
@@ -825,6 +951,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return a unique UI id
*/
public int getNextUIid() {
+ assert hasLock();
return nextUIId++;
}
@@ -838,6 +965,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return the mapping between window names and UI ids for this session.
*/
public Map<String, Integer> getPreserveOnRefreshUIs() {
+ assert hasLock();
return retainOnRefreshUIs;
}
@@ -848,6 +976,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the initialized UI to add.
*/
public void addUI(UI ui) {
+ assert hasLock();
if (ui.getUIId() == -1) {
throw new IllegalArgumentException(
"Can not add an UI that has not been initialized.");
@@ -867,6 +996,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the UI provider that should be added
*/
public void addUIProvider(UIProvider uiProvider) {
+ assert hasLock();
uiProviders.addFirst(uiProvider);
}
@@ -877,6 +1007,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* the UI provider that should be removed
*/
public void removeUIProvider(UIProvider uiProvider) {
+ assert hasLock();
uiProviders.remove(uiProvider);
}
@@ -886,6 +1017,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
* @return an unmodifiable list of UI providers
*/
public List<UIProvider> getUIProviders() {
+ assert hasLock();
return Collections.unmodifiableList(uiProviders);
}
@@ -910,6 +1042,7 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*
*/
public void close() {
+ assert hasLock();
closing = true;
}
@@ -918,13 +1051,84 @@ public class VaadinSession implements HttpSessionBindingListener, Serializable {
*
* @see #close()
*
- * @return
+ * @return true if this session is marked to be closed, false otherwise
*/
public boolean isClosing() {
+ assert hasLock();
return closing;
}
private static final Logger getLogger() {
return Logger.getLogger(VaadinSession.class.getName());
}
+
+ /**
+ * Provides exclusive access to this session from outside a request handling
+ * thread.
+ * <p>
+ * The given runnable is executed while holding the session lock to ensure
+ * exclusive access to this session. The session and related thread locals
+ * are set properly before executing the runnable.
+ * </p>
+ * <p>
+ * RPC handlers for components inside this session do not need this method
+ * as the session is automatically locked by the framework during request
+ * handling.
+ * </p>
+ * <p>
+ * Note that calling this method while another session is locked by the
+ * current thread will cause an exception. This is to prevent deadlock
+ * situations when two threads have locked one session each and are both
+ * waiting for the lock for the other session.
+ * </p>
+ *
+ * @param runnable
+ * the runnable which accesses the session
+ *
+ * @throws IllegalStateException
+ * if the current thread holds the lock for another session
+ *
+ *
+ * @see #lock()
+ * @see #getCurrent()
+ * @see UI#access(Runnable)
+ */
+ public void access(Runnable runnable) {
+ VaadinService.verifyNoOtherSessionLocked(this);
+
+ Map<Class<?>, CurrentInstance> old = null;
+ lock();
+ try {
+ old = CurrentInstance.setThreadLocals(this);
+ runnable.run();
+ } finally {
+ unlock();
+ if (old != null) {
+ CurrentInstance.restoreThreadLocals(old);
+ }
+ }
+
+ }
+
+ /**
+ * @deprecated As of 7.1.0.beta1, use {@link #access(Runnable)} instead.
+ * This method will be removed before the final 7.1.0 release.
+ */
+ @Deprecated
+ public void runSafely(Runnable runnable) {
+ access(runnable);
+ }
+
+ /**
+ * Gets the CSRF token (aka double submit cookie) that is used to protect
+ * against Cross Site Request Forgery attacks.
+ *
+ * @since 7.1
+ * @return the csrf token string
+ */
+ public String getCsrfToken() {
+ assert hasLock();
+ return csrfToken;
+ }
+
}
diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java
index 4122f053ae..8038bbc207 100644
--- a/server/src/com/vaadin/server/WebBrowser.java
+++ b/server/src/com/vaadin/server/WebBrowser.java
@@ -319,6 +319,17 @@ public class WebBrowser implements Serializable {
* entirely accurate due to varying network latencies, but should provide a
* close-enough value for most cases. Also note that the returned Date
* object uses servers default time zone, not the clients.
+ * <p>
+ * To get the actual date and time shown in the end users computer, you can
+ * do something like:
+ *
+ * <pre>
+ * WebBrowser browser = ...;
+ * SimpleTimeZone timeZone = new SimpleTimeZone(browser.getTimezoneOffset(), "Fake client time zone");
+ * DateFormat format = DateFormat.getDateTimeInstance();
+ * format.setTimeZone(timeZone);
+ * myLabel.setValue(format.format(browser.getCurrentDate()));
+ * </pre>
*
* @return the current date and time of the browser.
* @see #isDSTInEffect()
@@ -413,7 +424,7 @@ public class WebBrowser implements Serializable {
* @param request
* the Vaadin request to read the information from
*/
- void updateRequestDetails(VaadinRequest request) {
+ public void updateRequestDetails(VaadinRequest request) {
locale = request.getLocale();
address = request.getRemoteAddr();
secureConnection = request.isSecure();
diff --git a/server/src/com/vaadin/server/AbstractStreamingEvent.java b/server/src/com/vaadin/server/communication/AbstractStreamingEvent.java
index b7bf4e042f..b97a60fd56 100644
--- a/server/src/com/vaadin/server/AbstractStreamingEvent.java
+++ b/server/src/com/vaadin/server/communication/AbstractStreamingEvent.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.server;
+package com.vaadin.server.communication;
import com.vaadin.server.StreamVariable.StreamingEvent;
diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
new file mode 100644
index 0000000000..0bba65ff1d
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.atmosphere.cpr.AtmosphereResource;
+import org.atmosphere.cpr.AtmosphereResource.TRANSPORT;
+import org.json.JSONException;
+
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.ui.UI;
+
+/**
+ * {@link PushConnection} implementation using the Atmosphere push support that
+ * is by default included in Vaadin.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class AtmospherePushConnection implements Serializable, PushConnection {
+
+ /**
+ * Represents a message that can arrive as multiple fragments.
+ */
+ protected static class FragmentedMessage {
+ private final StringBuilder message = new StringBuilder();
+ private final int messageLength;
+
+ public FragmentedMessage(Reader reader) throws IOException {
+ // Messages are prefixed by the total message length plus '|'
+ String length = "";
+ int c;
+ while ((c = reader.read()) != -1
+ && c != ApplicationConstants.WEBSOCKET_MESSAGE_DELIMITER) {
+ length += (char) c;
+ }
+ try {
+ messageLength = Integer.parseInt(length);
+ } catch (NumberFormatException e) {
+ throw new IOException("Invalid message length " + length, e);
+ }
+ }
+
+ /**
+ * Appends all the data from the given Reader to this message and
+ * returns whether the message was completed.
+ *
+ * @param reader
+ * The Reader from which to read.
+ * @return true if this message is complete, false otherwise.
+ * @throws IOException
+ */
+ public boolean append(Reader reader) throws IOException {
+ char[] buffer = new char[ApplicationConstants.WEBSOCKET_BUFFER_SIZE];
+ int read;
+ while ((read = reader.read(buffer)) != -1) {
+ message.append(buffer, 0, read);
+ assert message.length() <= messageLength : "Received message "
+ + message.length() + "chars, expected " + messageLength;
+ }
+ return message.length() == messageLength;
+ }
+
+ public Reader getReader() {
+ return new StringReader(message.toString());
+ }
+ }
+
+ private UI ui;
+ private transient AtmosphereResource resource;
+ private transient Future<String> outgoingMessage;
+ private transient FragmentedMessage incomingMessage;
+
+ public AtmospherePushConnection(UI ui) {
+ this.ui = ui;
+ }
+
+ @Override
+ public void push() {
+ assert isConnected();
+ try {
+ push(true);
+ } catch (IOException e) {
+ // TODO Error handling
+ throw new RuntimeException("Push failed", e);
+ }
+ }
+
+ /**
+ * Pushes pending state changes and client RPC calls to the client.
+ *
+ * @param async
+ * True if this push asynchronously originates from the server,
+ * false if it is a response to a client request.
+ * @throws IOException
+ */
+ protected void push(boolean async) throws IOException {
+ Writer writer = new StringWriter();
+ try {
+ new UidlWriter().write(getUI(), writer, false, false, async);
+ } catch (JSONException e) {
+ throw new IOException("Error writing UIDL", e);
+ }
+ sendMessage("for(;;);[{" + writer.toString() + "}]");
+ }
+
+ /**
+ * Sends the given message to the current client.
+ *
+ * @param message
+ * The message to send
+ */
+ void sendMessage(String message) {
+ // "Broadcast" the changes to the single client only
+ outgoingMessage = getResource().getBroadcaster().broadcast(message,
+ getResource());
+ }
+
+ /**
+ * Reads and buffers a (possibly partial) message. If a complete message was
+ * received, or if the call resulted in the completion of a partially
+ * received message, returns a {@link Reader} yielding the complete message.
+ * Otherwise, returns null.
+ *
+ * @param reader
+ * A Reader from which to read the (partial) message
+ * @return A Reader yielding a complete message or null if the message is
+ * not yet complete.
+ * @throws IOException
+ */
+ protected Reader receiveMessage(Reader reader) throws IOException {
+
+ if (resource.transport() != TRANSPORT.WEBSOCKET) {
+ return reader;
+ }
+
+ if (incomingMessage == null) {
+ // No existing partially received message
+ incomingMessage = new FragmentedMessage(reader);
+ }
+
+ if (incomingMessage.append(reader)) {
+ // Message is complete
+ Reader completeReader = incomingMessage.getReader();
+ incomingMessage = null;
+ return completeReader;
+ } else {
+ // Only received a partial message
+ return null;
+ }
+ }
+
+ /**
+ * Associates this connection with the given AtmosphereResource. If there is
+ * a push pending, commits it.
+ *
+ * @param resource
+ * The AtmosphereResource representing the push channel.
+ * @throws IOException
+ */
+ protected void connect(AtmosphereResource resource) throws IOException {
+ this.resource = resource;
+ }
+
+ /**
+ * Returns whether this connection is currently open.
+ */
+ @Override
+ public boolean isConnected() {
+ return resource != null
+ && resource.getBroadcaster().getAtmosphereResources()
+ .contains(resource);
+ }
+
+ /**
+ * @return the UI associated with this connection.
+ */
+ protected UI getUI() {
+ return ui;
+ }
+
+ /**
+ * @return The AtmosphereResource associated with this connection or null if
+ * connection not open.
+ */
+ protected AtmosphereResource getResource() {
+ return resource;
+ }
+
+ @Override
+ public void disconnect() {
+ if (outgoingMessage != null) {
+ // Wait for the last message to be sent before closing the
+ // connection (assumes that futures are completed in order)
+ try {
+ outgoingMessage.get(1000, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ getLogger()
+ .log(Level.INFO,
+ "Timeout waiting for messages to be sent to client before disconnect");
+ } catch (Exception e) {
+ getLogger()
+ .log(Level.INFO,
+ "Error waiting for messages to be sent to client before disconnect");
+ }
+ outgoingMessage = null;
+ }
+
+ resource.resume();
+ assert !resource.getBroadcaster().getAtmosphereResources()
+ .contains(resource);
+ resource = null;
+ }
+
+ /**
+ * @since
+ * @return
+ */
+ private static Logger getLogger() {
+ return Logger.getLogger(AtmospherePushConnection.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/ClientRpcWriter.java b/server/src/com/vaadin/server/communication/ClientRpcWriter.java
new file mode 100644
index 0000000000..285adac7a5
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/ClientRpcWriter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.ClientMethodInvocation;
+import com.vaadin.server.EncodeResult;
+import com.vaadin.server.JsonCodec;
+import com.vaadin.server.PaintException;
+import com.vaadin.shared.communication.ClientRpc;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes {@link ClientRpc client RPC} invocations to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class ClientRpcWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing all pending client RPC invocations in the
+ * given UI.
+ *
+ * @param ui
+ * The {@link UI} whose RPC calls to write.
+ * @param writer
+ * The {@link Writer} used to write the JSON.
+ * @throws IOException
+ * If the serialization fails.
+ */
+ public void write(UI ui, Writer writer) throws IOException {
+
+ Collection<ClientMethodInvocation> pendingInvocations = collectPendingRpcCalls(ui
+ .getConnectorTracker().getDirtyVisibleConnectors());
+
+ JSONArray rpcCalls = new JSONArray();
+ for (ClientMethodInvocation invocation : pendingInvocations) {
+ // add invocation to rpcCalls
+ try {
+ JSONArray invocationJson = new JSONArray();
+ invocationJson.put(invocation.getConnector().getConnectorId());
+ invocationJson.put(invocation.getInterfaceName());
+ invocationJson.put(invocation.getMethodName());
+ JSONArray paramJson = new JSONArray();
+ for (int i = 0; i < invocation.getParameterTypes().length; ++i) {
+ Type parameterType = invocation.getParameterTypes()[i];
+ Object referenceParameter = null;
+ // TODO Use default values for RPC parameter types
+ // if (!JsonCodec.isInternalType(parameterType)) {
+ // try {
+ // referenceParameter = parameterType.newInstance();
+ // } catch (Exception e) {
+ // logger.log(Level.WARNING,
+ // "Error creating reference object for parameter of type "
+ // + parameterType.getName());
+ // }
+ // }
+ EncodeResult encodeResult = JsonCodec.encode(
+ invocation.getParameters()[i], referenceParameter,
+ parameterType, ui.getConnectorTracker());
+ paramJson.put(encodeResult.getEncodedValue());
+ }
+ invocationJson.put(paramJson);
+ rpcCalls.put(invocationJson);
+ } catch (JSONException e) {
+ throw new PaintException(
+ "Failed to serialize RPC method call parameters for connector "
+ + invocation.getConnector().getConnectorId()
+ + " method " + invocation.getInterfaceName()
+ + "." + invocation.getMethodName() + ": "
+ + e.getMessage(), e);
+ }
+ }
+ writer.write(rpcCalls.toString());
+ }
+
+ /**
+ * Collects all pending RPC calls from listed {@link ClientConnector}s and
+ * clears their RPC queues.
+ *
+ * @param rpcPendingQueue
+ * list of {@link ClientConnector} of interest
+ * @return ordered list of pending RPC calls
+ */
+ private Collection<ClientMethodInvocation> collectPendingRpcCalls(
+ Collection<ClientConnector> rpcPendingQueue) {
+ List<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>();
+ for (ClientConnector connector : rpcPendingQueue) {
+ List<ClientMethodInvocation> paintablePendingRpc = connector
+ .retrievePendingRpcCalls();
+ if (null != paintablePendingRpc && !paintablePendingRpc.isEmpty()) {
+ List<ClientMethodInvocation> oldPendingRpc = pendingInvocations;
+ int totalCalls = pendingInvocations.size()
+ + paintablePendingRpc.size();
+ pendingInvocations = new ArrayList<ClientMethodInvocation>(
+ totalCalls);
+
+ // merge two ordered comparable lists
+ for (int destIndex = 0, oldIndex = 0, paintableIndex = 0; destIndex < totalCalls; destIndex++) {
+ if (paintableIndex >= paintablePendingRpc.size()
+ || (oldIndex < oldPendingRpc.size() && ((Comparable<ClientMethodInvocation>) oldPendingRpc
+ .get(oldIndex))
+ .compareTo(paintablePendingRpc
+ .get(paintableIndex)) <= 0)) {
+ pendingInvocations.add(oldPendingRpc.get(oldIndex++));
+ } else {
+ pendingInvocations.add(paintablePendingRpc
+ .get(paintableIndex++));
+ }
+ }
+ }
+ }
+ return pendingInvocations;
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/ConnectorHierarchyWriter.java b/server/src/com/vaadin/server/communication/ConnectorHierarchyWriter.java
new file mode 100644
index 0000000000..467bddbdce
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/ConnectorHierarchyWriter.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.Collection;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.vaadin.server.AbstractClientConnector;
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.LegacyCommunicationManager;
+import com.vaadin.server.PaintException;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes a connector hierarchy to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class ConnectorHierarchyWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing the connector hierarchy (parent-child
+ * mappings) of the dirty connectors in the given UI.
+ *
+ * @param ui
+ * The {@link UI} whose hierarchy to write.
+ * @param writer
+ * The {@link Writer} used to write the JSON.
+ * @throws IOException
+ * If the serialization fails.
+ */
+ public void write(UI ui, Writer writer) throws IOException {
+
+ Collection<ClientConnector> dirtyVisibleConnectors = ui
+ .getConnectorTracker().getDirtyVisibleConnectors();
+
+ JSONObject hierarchyInfo = new JSONObject();
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ String connectorId = connector.getConnectorId();
+ JSONArray children = new JSONArray();
+
+ for (ClientConnector child : AbstractClientConnector
+ .getAllChildrenIterable(connector)) {
+ if (LegacyCommunicationManager
+ .isConnectorVisibleToClient(child)) {
+ children.put(child.getConnectorId());
+ }
+ }
+ try {
+ hierarchyInfo.put(connectorId, children);
+ } catch (JSONException e) {
+ throw new PaintException(
+ "Failed to send hierarchy information about "
+ + connectorId + " to the client: "
+ + e.getMessage(), e);
+ }
+ }
+ writer.write(hierarchyInfo.toString());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/ConnectorTypeWriter.java b/server/src/com/vaadin/server/communication/ConnectorTypeWriter.java
new file mode 100644
index 0000000000..eaa1c83ff2
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/ConnectorTypeWriter.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.Collection;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.PaintException;
+import com.vaadin.server.PaintTarget;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes connector type mappings to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class ConnectorTypeWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing connector-ID-to-type-ID mappings for each
+ * dirty Connector in the given UI.
+ *
+ * @param ui
+ * The {@link UI} containing dirty connectors
+ * @param writer
+ * The {@link Writer} used to write the JSON.
+ * @param target
+ * The paint target containing the connector type IDs.
+ * @throws IOException
+ * If the serialization fails.
+ */
+ public void write(UI ui, Writer writer, PaintTarget target)
+ throws IOException {
+
+ Collection<ClientConnector> dirtyVisibleConnectors = ui
+ .getConnectorTracker().getDirtyVisibleConnectors();
+
+ JSONObject connectorTypes = new JSONObject();
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ String connectorType = target.getTag(connector);
+ try {
+ connectorTypes.put(connector.getConnectorId(), connectorType);
+ } catch (JSONException e) {
+ throw new PaintException(
+ "Failed to send connector type for connector "
+ + connector.getConnectorId() + ": "
+ + e.getMessage(), e);
+ }
+ }
+ writer.write(connectorTypes.toString());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java
new file mode 100644
index 0000000000..e875a4e861
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java
@@ -0,0 +1,645 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.NoInputStreamException;
+import com.vaadin.server.NoOutputStreamException;
+import com.vaadin.server.RequestHandler;
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.StreamVariable;
+import com.vaadin.server.StreamVariable.StreamingEndEvent;
+import com.vaadin.server.StreamVariable.StreamingErrorEvent;
+import com.vaadin.server.UploadException;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.UI;
+
+/**
+ * Handles a file upload request submitted via an Upload component.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class FileUploadHandler implements RequestHandler {
+
+ /**
+ * Stream that extracts content from another stream until the boundary
+ * string is encountered.
+ *
+ * Public only for unit tests, should be considered private for all other
+ * purposes.
+ */
+ public static class SimpleMultiPartInputStream extends InputStream {
+
+ /**
+ * Counter of how many characters have been matched to boundary string
+ * from the stream
+ */
+ int matchedCount = -1;
+
+ /**
+ * Used as pointer when returning bytes after partly matched boundary
+ * string.
+ */
+ int curBoundaryIndex = 0;
+ /**
+ * The byte found after a "promising start for boundary"
+ */
+ private int bufferedByte = -1;
+ private boolean atTheEnd = false;
+
+ private final char[] boundary;
+
+ private final InputStream realInputStream;
+
+ public SimpleMultiPartInputStream(InputStream realInputStream,
+ String boundaryString) {
+ boundary = (CRLF + DASHDASH + boundaryString).toCharArray();
+ this.realInputStream = realInputStream;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (atTheEnd) {
+ // End boundary reached, nothing more to read
+ return -1;
+ } else if (bufferedByte >= 0) {
+ /* Purge partially matched boundary if there was such */
+ return getBuffered();
+ } else if (matchedCount != -1) {
+ /*
+ * Special case where last "failed" matching ended with first
+ * character from boundary string
+ */
+ return matchForBoundary();
+ } else {
+ int fromActualStream = realInputStream.read();
+ if (fromActualStream == -1) {
+ // unexpected end of stream
+ throw new IOException(
+ "The multipart stream ended unexpectedly");
+ }
+ if (boundary[0] == fromActualStream) {
+ /*
+ * If matches the first character in boundary string, start
+ * checking if the boundary is fetched.
+ */
+ return matchForBoundary();
+ }
+ return fromActualStream;
+ }
+ }
+
+ /**
+ * Reads the input to expect a boundary string. Expects that the first
+ * character has already been matched.
+ *
+ * @return -1 if the boundary was matched, else returns the first byte
+ * from boundary
+ * @throws IOException
+ */
+ private int matchForBoundary() throws IOException {
+ matchedCount = 0;
+ /*
+ * Going to "buffered mode". Read until full boundary match or a
+ * different character.
+ */
+ while (true) {
+ matchedCount++;
+ if (matchedCount == boundary.length) {
+ /*
+ * The whole boundary matched so we have reached the end of
+ * file
+ */
+ atTheEnd = true;
+ return -1;
+ }
+ int fromActualStream = realInputStream.read();
+ if (fromActualStream != boundary[matchedCount]) {
+ /*
+ * Did not find full boundary, cache the mismatching byte
+ * and start returning the partially matched boundary.
+ */
+ bufferedByte = fromActualStream;
+ return getBuffered();
+ }
+ }
+ }
+
+ /**
+ * Returns the partly matched boundary string and the byte following
+ * that.
+ *
+ * @return
+ * @throws IOException
+ */
+ private int getBuffered() throws IOException {
+ int b;
+ if (matchedCount == 0) {
+ // The boundary has been returned, return the buffered byte.
+ b = bufferedByte;
+ bufferedByte = -1;
+ matchedCount = -1;
+ } else {
+ b = boundary[curBoundaryIndex++];
+ if (curBoundaryIndex == matchedCount) {
+ // The full boundary has been returned, remaining is the
+ // char that did not match the boundary.
+
+ curBoundaryIndex = 0;
+ if (bufferedByte != boundary[0]) {
+ /*
+ * next call for getBuffered will return the
+ * bufferedByte that came after the partial boundary
+ * match
+ */
+ matchedCount = 0;
+ } else {
+ /*
+ * Special case where buffered byte again matches the
+ * boundaryString. This could be the start of the real
+ * end boundary.
+ */
+ matchedCount = 0;
+ bufferedByte = -1;
+ }
+ }
+ }
+ if (b == -1) {
+ throw new IOException("The multipart stream ended unexpectedly");
+ }
+ return b;
+ }
+ }
+
+ private static class UploadInterruptedException extends Exception {
+ public UploadInterruptedException() {
+ super("Upload interrupted by other thread");
+ }
+ }
+
+ private static final int LF = "\n".getBytes()[0];
+
+ private static final String CRLF = "\r\n";
+
+ private static final String UTF8 = "UTF-8";
+
+ private static final String DASHDASH = "--";
+
+ /* Same as in apache commons file upload library that was previously used. */
+ private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024;
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ if (!ServletPortletHelper.isFileUploadRequest(request)) {
+ return false;
+ }
+
+ /*
+ * URI pattern: APP/UPLOAD/[UIID]/[PID]/[NAME]/[SECKEY] See
+ * #createReceiverUrl
+ */
+
+ String pathInfo = request.getPathInfo();
+ // strip away part until the data we are interested starts
+ int startOfData = pathInfo
+ .indexOf(ServletPortletHelper.UPLOAD_URL_PREFIX)
+ + ServletPortletHelper.UPLOAD_URL_PREFIX.length();
+ String uppUri = pathInfo.substring(startOfData);
+ String[] parts = uppUri.split("/", 4); // 0= UIid, 1 = cid, 2= name, 3
+ // = sec key
+ String uiId = parts[0];
+ String connectorId = parts[1];
+ String variableName = parts[2];
+
+ // These are retrieved while session is locked
+ ClientConnector source;
+ StreamVariable streamVariable;
+
+ session.lock();
+ try {
+ UI uI = session.getUIById(Integer.parseInt(uiId));
+ UI.setCurrent(uI);
+
+ streamVariable = uI.getConnectorTracker().getStreamVariable(
+ connectorId, variableName);
+ String secKey = uI.getConnectorTracker().getSeckey(streamVariable);
+ if (!secKey.equals(parts[3])) {
+ // TODO Should rethink error handling
+ return true;
+ }
+
+ source = session.getCommunicationManager().getConnector(uI,
+ connectorId);
+ } finally {
+ session.unlock();
+ }
+
+ String contentType = request.getContentType();
+ if (contentType.contains("boundary")) {
+ // Multipart requests contain boundary string
+ doHandleSimpleMultipartFileUpload(session, 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(session, request, response, streamVariable,
+ variableName, source, request.getContentLength());
+ }
+ return true;
+ }
+
+ private static String readLine(InputStream stream) throws IOException {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ int readByte = stream.read();
+ while (readByte != LF) {
+ bout.write(readByte);
+ readByte = stream.read();
+ }
+ byte[] bytes = bout.toByteArray();
+ return new String(bytes, 0, bytes.length - 1, UTF8);
+ }
+
+ /**
+ * Method used to stream content from a multipart request (either from
+ * servlet or portlet request) to given StreamVariable.
+ * <p>
+ * This method takes care of locking the session as needed and does not
+ * assume the caller has locked the session. This allows the session to be
+ * locked only when needed and not when handling the upload data.
+ * </p>
+ *
+ * @param session
+ * The session containing the stream variable
+ * @param request
+ * The upload request
+ * @param response
+ * The upload response
+ * @param streamVariable
+ * The destination stream variable
+ * @param variableName
+ * The name of the destination stream variable
+ * @param owner
+ * The owner of the stream variable
+ * @param boundary
+ * The mime boundary used in the upload request
+ * @throws IOException
+ * If there is a problem reading the request or writing the
+ * response
+ */
+ protected void doHandleSimpleMultipartFileUpload(VaadinSession session,
+ VaadinRequest request, VaadinResponse response,
+ StreamVariable streamVariable, String variableName,
+ ClientConnector owner, String boundary) throws IOException {
+ // multipart parsing, supports only one file for request, but that is
+ // fine for our current terminal
+
+ final InputStream inputStream = request.getInputStream();
+
+ int contentLength = request.getContentLength();
+
+ boolean atStart = false;
+ boolean firstFileFieldFound = false;
+
+ String rawfilename = "unknown";
+ String rawMimeType = "application/octet-stream";
+
+ /*
+ * Read the stream until the actual file starts (empty line). Read
+ * filename and content type from multipart headers.
+ */
+ while (!atStart) {
+ String readLine = readLine(inputStream);
+ contentLength -= (readLine.getBytes(UTF8).length + CRLF.length());
+ if (readLine.startsWith("Content-Disposition:")
+ && readLine.indexOf("filename=") > 0) {
+ rawfilename = readLine.replaceAll(".*filename=", "");
+ char quote = rawfilename.charAt(0);
+ rawfilename = rawfilename.substring(1);
+ rawfilename = rawfilename.substring(0,
+ rawfilename.indexOf(quote));
+ firstFileFieldFound = true;
+ } else if (firstFileFieldFound && readLine.equals("")) {
+ atStart = true;
+ } else if (readLine.startsWith("Content-Type")) {
+ rawMimeType = readLine.split(": ")[1];
+ }
+ }
+
+ contentLength -= (boundary.length() + CRLF.length() + 2
+ * DASHDASH.length() + CRLF.length());
+
+ /*
+ * Reads bytes from the underlying stream. Compares the read bytes to
+ * the boundary string and returns -1 if met.
+ *
+ * The matching happens so that if the read byte equals to the first
+ * char of boundary string, the stream goes to "buffering mode". In
+ * buffering mode bytes are read until the character does not match the
+ * corresponding from boundary string or the full boundary string is
+ * found.
+ *
+ * Note, if this is someday needed elsewhere, don't shoot yourself to
+ * foot and split to a top level helper class.
+ */
+ InputStream simpleMultiPartReader = new SimpleMultiPartInputStream(
+ inputStream, boundary);
+
+ /*
+ * Should report only the filename even if the browser sends the path
+ */
+ final String filename = removePath(rawfilename);
+ final String mimeType = rawMimeType;
+
+ try {
+ handleFileUploadValidationAndData(session, simpleMultiPartReader,
+ streamVariable, filename, mimeType, contentLength, owner,
+ variableName);
+ } catch (UploadException e) {
+ session.getCommunicationManager().handleConnectorRelatedException(
+ owner, e);
+ }
+ sendUploadResponse(request, response);
+
+ }
+
+ private void handleFileUploadValidationAndData(VaadinSession session,
+ InputStream inputStream, StreamVariable streamVariable,
+ String filename, String mimeType, int contentLength,
+ ClientConnector connector, String variableName)
+ throws UploadException {
+ session.lock();
+ try {
+ if (connector == null) {
+ throw new UploadException(
+ "File upload ignored because the connector for the stream variable was not found");
+ }
+ if (!connector.isConnectorEnabled()) {
+ throw new UploadException("Warning: file upload ignored for "
+ + connector.getConnectorId()
+ + " because the component was disabled");
+ }
+ if ((connector instanceof Component)
+ && ((Component) connector).isReadOnly()) {
+ // Only checked for legacy reasons
+ throw new UploadException(
+ "File upload ignored because the component is read-only");
+ }
+ } finally {
+ session.unlock();
+ }
+ try {
+ boolean forgetVariable = streamToReceiver(session, inputStream,
+ streamVariable, filename, mimeType, contentLength);
+ if (forgetVariable) {
+ cleanStreamVariable(session, connector, variableName);
+ }
+ } catch (Exception e) {
+ session.lock();
+ try {
+ session.getCommunicationManager()
+ .handleConnectorRelatedException(connector, e);
+ } finally {
+ session.unlock();
+ }
+ }
+ }
+
+ /**
+ * Used to stream plain file post (aka XHR2.post(File))
+ * <p>
+ * This method takes care of locking the session as needed and does not
+ * assume the caller has locked the session. This allows the session to be
+ * locked only when needed and not when handling the upload data.
+ * </p>
+ *
+ * @param session
+ * The session containing the stream variable
+ * @param request
+ * The upload request
+ * @param response
+ * The upload response
+ * @param streamVariable
+ * The destination stream variable
+ * @param variableName
+ * The name of the destination stream variable
+ * @param owner
+ * The owner of the stream variable
+ * @param contentLength
+ * The length of the request content
+ * @throws IOException
+ * If there is a problem reading the request or writing the
+ * response
+ */
+ protected void doHandleXhrFilePost(VaadinSession session,
+ VaadinRequest request, VaadinResponse response,
+ StreamVariable streamVariable, String variableName,
+ ClientConnector owner, int contentLength) throws IOException {
+
+ // These are unknown in filexhr ATM, maybe add to Accept header that
+ // is accessible in portlets
+ final String filename = "unknown";
+ final String mimeType = filename;
+ final InputStream stream = request.getInputStream();
+
+ try {
+ handleFileUploadValidationAndData(session, stream, streamVariable,
+ filename, mimeType, contentLength, owner, variableName);
+ } catch (UploadException e) {
+ session.getCommunicationManager().handleConnectorRelatedException(
+ owner, e);
+ }
+ sendUploadResponse(request, response);
+ }
+
+ /**
+ * @param in
+ * @param streamVariable
+ * @param filename
+ * @param type
+ * @param contentLength
+ * @return true if the streamvariable has informed that the terminal can
+ * forget this variable
+ * @throws UploadException
+ */
+ protected final boolean streamToReceiver(VaadinSession session,
+ final InputStream in, StreamVariable streamVariable,
+ String filename, String type, int contentLength)
+ throws UploadException {
+ if (streamVariable == null) {
+ throw new IllegalStateException(
+ "StreamVariable for the post not found");
+ }
+
+ OutputStream out = null;
+ int totalBytes = 0;
+ StreamingStartEventImpl startedEvent = new StreamingStartEventImpl(
+ filename, type, contentLength);
+ try {
+ boolean listenProgress;
+ session.lock();
+ try {
+ streamVariable.streamingStarted(startedEvent);
+ out = streamVariable.getOutputStream();
+ listenProgress = streamVariable.listenProgress();
+ } finally {
+ session.unlock();
+ }
+
+ // Gets the output target stream
+ if (out == null) {
+ throw new NoOutputStreamException();
+ }
+
+ if (null == in) {
+ // No file, for instance non-existent filename in html upload
+ throw new NoInputStreamException();
+ }
+
+ final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE];
+ int bytesReadToBuffer = 0;
+ while ((bytesReadToBuffer = in.read(buffer)) > 0) {
+ out.write(buffer, 0, bytesReadToBuffer);
+ totalBytes += bytesReadToBuffer;
+ if (listenProgress) {
+ // update progress if listener set and contentLength
+ // received
+ session.lock();
+ try {
+ StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl(
+ filename, type, contentLength, totalBytes);
+ streamVariable.onProgress(progressEvent);
+ } finally {
+ session.unlock();
+ }
+ }
+ if (streamVariable.isInterrupted()) {
+ throw new UploadInterruptedException();
+ }
+ }
+
+ // upload successful
+ out.close();
+ StreamingEndEvent event = new StreamingEndEventImpl(filename, type,
+ totalBytes);
+ session.lock();
+ try {
+ streamVariable.streamingFinished(event);
+ } finally {
+ session.unlock();
+ }
+
+ } catch (UploadInterruptedException e) {
+ // Download interrupted by application code
+ tryToCloseStream(out);
+ StreamingErrorEvent event = new StreamingErrorEventImpl(filename,
+ type, contentLength, totalBytes, e);
+ session.lock();
+ try {
+ streamVariable.streamingFailed(event);
+ } finally {
+ session.unlock();
+ }
+ // Note, we are not throwing interrupted exception forward as it is
+ // not a terminal level error like all other exception.
+ } catch (final Exception e) {
+ tryToCloseStream(out);
+ session.lock();
+ try {
+ StreamingErrorEvent event = new StreamingErrorEventImpl(
+ filename, type, contentLength, totalBytes, e);
+ streamVariable.streamingFailed(event);
+ // throw exception for terminal to be handled (to be passed to
+ // terminalErrorHandler)
+ throw new UploadException(e);
+ } finally {
+ session.unlock();
+ }
+ }
+ return startedEvent.isDisposed();
+ }
+
+ static void tryToCloseStream(OutputStream out) {
+ try {
+ // try to close output stream (e.g. file handle)
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException e1) {
+ // NOP
+ }
+ }
+
+ /**
+ * Removes any possible path information from the filename and returns the
+ * filename. Separators / and \\ are used.
+ *
+ * @param name
+ * @return
+ */
+ private static String removePath(String filename) {
+ if (filename != null) {
+ filename = filename.replaceAll("^.*[/\\\\]", "");
+ }
+
+ return filename;
+ }
+
+ /**
+ * TODO document
+ *
+ * @param request
+ * @param response
+ * @throws IOException
+ */
+ protected void sendUploadResponse(VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ response.setContentType("text/html");
+ final OutputStream out = response.getOutputStream();
+ final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
+ new OutputStreamWriter(out, "UTF-8")));
+ outWriter.print("<html><body>download handled</body></html>");
+ outWriter.flush();
+ out.close();
+ }
+
+ private void cleanStreamVariable(VaadinSession session,
+ final ClientConnector owner, final String variableName) {
+ session.access(new Runnable() {
+ @Override
+ public void run() {
+ owner.getUI()
+ .getConnectorTracker()
+ .cleanStreamVariable(owner.getConnectorId(),
+ variableName);
+ }
+ });
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/HeartbeatHandler.java b/server/src/com/vaadin/server/communication/HeartbeatHandler.java
new file mode 100644
index 0000000000..16c21224ab
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/HeartbeatHandler.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.SessionExpiredHandler;
+import com.vaadin.server.SynchronizedRequestHandler;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.ui.ui.UIConstants;
+import com.vaadin.ui.UI;
+
+/**
+ * Handles heartbeat requests. Heartbeat requests are periodically sent by the
+ * client-side to inform the server that the UI sending the heartbeat is still
+ * alive (the browser window is open, the connection is up) even when there are
+ * no UIDL requests for a prolonged period of time. UIs that do not receive
+ * either heartbeat or UIDL requests are eventually removed from the session and
+ * garbage collected.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class HeartbeatHandler extends SynchronizedRequestHandler implements
+ SessionExpiredHandler {
+
+ /**
+ * Handles a heartbeat request for the given session. Reads the GET
+ * parameter named {@link UIConstants#UI_ID_PARAMETER} to identify the UI.
+ * If the UI is found in the session, sets it
+ * {@link UI#getLastHeartbeatTimestamp() heartbeat timestamp} to the current
+ * time. Otherwise, writes a HTTP Not Found error to the response.
+ */
+ @Override
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
+ if (!ServletPortletHelper.isHeartbeatRequest(request)) {
+ return false;
+ }
+
+ UI ui = session.getService().findUI(request);
+ if (ui != null) {
+ ui.setLastHeartbeatTimestamp(System.currentTimeMillis());
+ // Ensure that the browser does not cache heartbeat responses.
+ // iOS 6 Safari requires this (#10370)
+ response.setHeader("Cache-Control", "no-cache");
+ } else {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, "UI not found");
+ }
+
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.server.SessionExpiredHandler#handleSessionExpired(com.vaadin
+ * .server.VaadinRequest, com.vaadin.server.VaadinResponse)
+ */
+ @Override
+ public boolean handleSessionExpired(VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ if (!ServletPortletHelper.isHeartbeatRequest(request)) {
+ return false;
+ }
+
+ response.sendError(HttpServletResponse.SC_GONE, "Session expired");
+ return true;
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/LegacyUidlWriter.java b/server/src/com/vaadin/server/communication/LegacyUidlWriter.java
new file mode 100644
index 0000000000..ad99a2d8b5
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/LegacyUidlWriter.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.logging.Logger;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.LegacyPaint;
+import com.vaadin.server.PaintTarget;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.LegacyComponent;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes legacy UIDL changes to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class LegacyUidlWriter implements Serializable {
+
+ /**
+ * Writes a JSON array containing the changes of all dirty
+ * {@link LegacyComponent}s in the given UI.
+ *
+ * @param ui
+ * The {@link UI} whose legacy changes to write
+ * @param writer
+ * The {@link Writer} to write the JSON with
+ * @param target
+ * The {@link PaintTarget} to use
+ * @throws IOException
+ * If the serialization fails.
+ */
+ public void write(UI ui, Writer writer, PaintTarget target)
+ throws IOException {
+
+ Collection<ClientConnector> dirtyVisibleConnectors = ui
+ .getConnectorTracker().getDirtyVisibleConnectors();
+
+ List<Component> legacyComponents = new ArrayList<Component>();
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ // All Components that want to use paintContent must implement
+ // LegacyComponent
+ if (connector instanceof LegacyComponent) {
+ legacyComponents.add((Component) connector);
+ }
+ }
+ sortByHierarchy(legacyComponents);
+
+ writer.write("[");
+ for (Component c : legacyComponents) {
+ getLogger().fine(
+ "Painting LegacyComponent " + c.getClass().getName() + "@"
+ + Integer.toHexString(c.hashCode()));
+ target.startTag("change");
+ final String pid = c.getConnectorId();
+ target.addAttribute("pid", pid);
+ LegacyPaint.paint(c, target);
+ target.endTag("change");
+ }
+ writer.write("]");
+ }
+
+ private void sortByHierarchy(List<Component> paintables) {
+ // Vaadin 6 requires parents to be painted before children as component
+ // containers rely on that their updateFromUIDL method has been called
+ // before children start calling e.g. updateCaption
+ Collections.sort(paintables, new Comparator<Component>() {
+ @Override
+ public int compare(Component c1, Component c2) {
+ int depth1 = 0;
+ while (c1.getParent() != null) {
+ depth1++;
+ c1 = c1.getParent();
+ }
+ int depth2 = 0;
+ while (c2.getParent() != null) {
+ depth2++;
+ c2 = c2.getParent();
+ }
+ if (depth1 < depth2) {
+ return -1;
+ }
+ if (depth1 > depth2) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(LegacyUidlWriter.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/LocaleWriter.java b/server/src/com/vaadin/server/communication/LocaleWriter.java
new file mode 100644
index 0000000000..c05649da19
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/LocaleWriter.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Locale;
+import java.util.logging.Logger;
+
+/**
+ * Serializes locale information to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ * @deprecated See <a href="http://dev.vaadin.com/ticket/11378">ticket
+ * #11378</a>.
+ */
+@Deprecated
+public class LocaleWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing localized strings of the given locales.
+ *
+ * @param locales
+ * The list of {@link Locale}s to write.
+ * @param writer
+ * The {@link Writer} used to write the JSON.
+ * @throws IOException
+ * If the serialization fails.
+ *
+ */
+ public void write(List<String> locales, Writer writer) throws IOException {
+
+ // Send locale informations to client
+ writer.write("[");
+ // TODO locales are currently sent on each request; this will be fixed
+ // by implementing #11378.
+ for (int pendingLocalesIndex = 0; pendingLocalesIndex < locales.size(); pendingLocalesIndex++) {
+
+ final Locale l = generateLocale(locales.get(pendingLocalesIndex));
+ // Locale name
+ writer.write("{\"name\":\"" + l.toString() + "\",");
+
+ /*
+ * Month names (both short and full)
+ */
+ final DateFormatSymbols dfs = new DateFormatSymbols(l);
+ final String[] short_months = dfs.getShortMonths();
+ final String[] months = dfs.getMonths();
+ writer.write("\"smn\":[\""
+ + // ShortMonthNames
+ short_months[0] + "\",\"" + short_months[1] + "\",\""
+ + short_months[2] + "\",\"" + short_months[3] + "\",\""
+ + short_months[4] + "\",\"" + short_months[5] + "\",\""
+ + short_months[6] + "\",\"" + short_months[7] + "\",\""
+ + short_months[8] + "\",\"" + short_months[9] + "\",\""
+ + short_months[10] + "\",\"" + short_months[11] + "\""
+ + "],");
+ writer.write("\"mn\":[\""
+ + // MonthNames
+ months[0] + "\",\"" + months[1] + "\",\"" + months[2]
+ + "\",\"" + months[3] + "\",\"" + months[4] + "\",\""
+ + months[5] + "\",\"" + months[6] + "\",\"" + months[7]
+ + "\",\"" + months[8] + "\",\"" + months[9] + "\",\""
+ + months[10] + "\",\"" + months[11] + "\"" + "],");
+
+ /*
+ * Weekday names (both short and full)
+ */
+ final String[] short_days = dfs.getShortWeekdays();
+ final String[] days = dfs.getWeekdays();
+ writer.write("\"sdn\":[\""
+ + // ShortDayNames
+ short_days[1] + "\",\"" + short_days[2] + "\",\""
+ + short_days[3] + "\",\"" + short_days[4] + "\",\""
+ + short_days[5] + "\",\"" + short_days[6] + "\",\""
+ + short_days[7] + "\"" + "],");
+ writer.write("\"dn\":[\""
+ + // DayNames
+ days[1] + "\",\"" + days[2] + "\",\"" + days[3] + "\",\""
+ + days[4] + "\",\"" + days[5] + "\",\"" + days[6] + "\",\""
+ + days[7] + "\"" + "],");
+
+ /*
+ * First day of week (0 = sunday, 1 = monday)
+ */
+ final Calendar cal = new GregorianCalendar(l);
+ writer.write("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ",");
+
+ /*
+ * Date formatting (MM/DD/YYYY etc.)
+ */
+
+ DateFormat dateFormat = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT, DateFormat.SHORT, l);
+ if (!(dateFormat instanceof SimpleDateFormat)) {
+ getLogger().warning(
+ "Unable to get default date pattern for locale "
+ + l.toString());
+ dateFormat = new SimpleDateFormat();
+ }
+ final String df = ((SimpleDateFormat) dateFormat).toPattern();
+
+ int timeStart = df.indexOf("H");
+ if (timeStart < 0) {
+ timeStart = df.indexOf("h");
+ }
+ final int ampm_first = df.indexOf("a");
+ // E.g. in Korean locale AM/PM is before h:mm
+ // TODO should take that into consideration on client-side as well,
+ // now always h:mm a
+ if (ampm_first > 0 && ampm_first < timeStart) {
+ timeStart = ampm_first;
+ }
+ // Hebrew locale has time before the date
+ final boolean timeFirst = timeStart == 0;
+ String dateformat;
+ if (timeFirst) {
+ int dateStart = df.indexOf(' ');
+ if (ampm_first > dateStart) {
+ dateStart = df.indexOf(' ', ampm_first);
+ }
+ dateformat = df.substring(dateStart + 1);
+ } else {
+ dateformat = df.substring(0, timeStart - 1);
+ }
+
+ writer.write("\"df\":\"" + dateformat.trim() + "\",");
+
+ /*
+ * Time formatting (24 or 12 hour clock and AM/PM suffixes)
+ */
+ final String timeformat = df.substring(timeStart, df.length());
+ /*
+ * Doesn't return second or milliseconds.
+ *
+ * We use timeformat to determine 12/24-hour clock
+ */
+ final boolean twelve_hour_clock = timeformat.indexOf("a") > -1;
+ // TODO there are other possibilities as well, like 'h' in french
+ // (ignore them, too complicated)
+ final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "."
+ : ":";
+ // outWriter.print("\"tf\":\"" + timeformat + "\",");
+ writer.write("\"thc\":" + twelve_hour_clock + ",");
+ writer.write("\"hmd\":\"" + hour_min_delimiter + "\"");
+ if (twelve_hour_clock) {
+ final String[] ampm = dfs.getAmPmStrings();
+ writer.write(",\"ampm\":[\"" + ampm[0] + "\",\"" + ampm[1]
+ + "\"]");
+ }
+ writer.write("}");
+ if (pendingLocalesIndex < locales.size() - 1) {
+ writer.write(",");
+ }
+ }
+ writer.write("]"); // Close locales
+ }
+
+ /**
+ * Constructs a {@link Locale} instance to be sent to the client based on a
+ * short locale description string.
+ *
+ * @see #requireLocale(String)
+ *
+ * @param value
+ * @return
+ */
+ private Locale generateLocale(String value) {
+ final String[] temp = value.split("_");
+ if (temp.length == 1) {
+ return new Locale(temp[0]);
+ } else if (temp.length == 2) {
+ return new Locale(temp[0], temp[1]);
+ } else {
+ return new Locale(temp[0], temp[1], temp[2]);
+ }
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(LocaleWriter.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/MetadataWriter.java b/server/src/com/vaadin/server/communication/MetadataWriter.java
new file mode 100644
index 0000000000..1a3f0e946a
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/MetadataWriter.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.List;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.ComponentSizeValidator;
+import com.vaadin.server.ComponentSizeValidator.InvalidLayout;
+import com.vaadin.server.SystemMessages;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.Window;
+
+/**
+ * Serializes miscellaneous metadata to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class MetadataWriter implements Serializable {
+
+ private int timeoutInterval = -1;
+
+ /**
+ * Writes a JSON object containing metadata related to the given UI.
+ *
+ * @param ui
+ * The UI whose metadata to write.
+ * @param writer
+ * The writer used.
+ * @param repaintAll
+ * Whether the client should repaint everything.
+ * @param analyzeLayouts
+ * Whether detected layout problems should be reported in client
+ * and server console.
+ * @param async
+ * True if this message is sent by the server asynchronously,
+ * false if it is a response to a client message.
+ * @param hilightedConnector
+ * The connector that should be highlighted on the client or null
+ * if none.
+ * @param messages
+ * a {@link SystemMessages} containing client-side error
+ * messages.
+ * @throws IOException
+ * If the serialization fails.
+ *
+ */
+ public void write(UI ui, Writer writer, boolean repaintAll,
+ boolean analyzeLayouts, boolean async,
+ ClientConnector hilightedConnector, SystemMessages messages)
+ throws IOException {
+
+ List<InvalidLayout> invalidComponentRelativeSizes = null;
+
+ if (analyzeLayouts) {
+ invalidComponentRelativeSizes = ComponentSizeValidator
+ .validateComponentRelativeSizes(ui.getContent(), null, null);
+
+ // Also check any existing subwindows
+ if (ui.getWindows() != null) {
+ for (Window subWindow : ui.getWindows()) {
+ invalidComponentRelativeSizes = ComponentSizeValidator
+ .validateComponentRelativeSizes(
+ subWindow.getContent(),
+ invalidComponentRelativeSizes, null);
+ }
+ }
+ }
+
+ writer.write("{");
+
+ boolean metaOpen = false;
+ if (repaintAll) {
+ metaOpen = true;
+ writer.write("\"repaintAll\":true");
+ if (analyzeLayouts) {
+ writer.write(", \"invalidLayouts\":");
+ writer.write("[");
+ if (invalidComponentRelativeSizes != null) {
+ boolean first = true;
+ for (InvalidLayout invalidLayout : invalidComponentRelativeSizes) {
+ if (!first) {
+ writer.write(",");
+ } else {
+ first = false;
+ }
+ invalidLayout.reportErrors(new PrintWriter(writer),
+ System.err);
+ }
+ }
+ writer.write("]");
+ }
+ if (hilightedConnector != null) {
+ writer.write(", \"hl\":\"");
+ writer.write(hilightedConnector.getConnectorId());
+ writer.write("\"");
+ }
+ }
+
+ if (async) {
+ if (metaOpen) {
+ writer.write(", ");
+ }
+ writer.write("\"async\":true");
+ }
+
+ // meta instruction for client to enable auto-forward to
+ // sessionExpiredURL after timer expires.
+ if (messages != null && messages.getSessionExpiredMessage() == null
+ && messages.getSessionExpiredCaption() == null
+ && messages.isSessionExpiredNotificationEnabled()) {
+ int newTimeoutInterval = ui.getSession().getSession()
+ .getMaxInactiveInterval();
+ if (repaintAll || (timeoutInterval != newTimeoutInterval)) {
+ String escapedURL = messages.getSessionExpiredURL() == null ? ""
+ : messages.getSessionExpiredURL().replace("/", "\\/");
+ if (metaOpen) {
+ writer.write(",");
+ }
+ writer.write("\"timedRedirect\":{\"interval\":"
+ + (newTimeoutInterval + 15) + ",\"url\":\""
+ + escapedURL + "\"}");
+ metaOpen = true;
+ }
+ timeoutInterval = newTimeoutInterval;
+ }
+ writer.write("}");
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java
new file mode 100644
index 0000000000..2458951ada
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PortletBootstrapHandler.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.ResourceURL;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.vaadin.server.BootstrapHandler;
+import com.vaadin.server.PaintException;
+import com.vaadin.server.VaadinPortlet;
+import com.vaadin.server.VaadinPortletRequest;
+import com.vaadin.server.VaadinPortletResponse;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.ApplicationConstants;
+
+public class PortletBootstrapHandler extends BootstrapHandler {
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ PortletRequest portletRequest = ((VaadinPortletRequest) request)
+ .getPortletRequest();
+ if (portletRequest instanceof RenderRequest) {
+ return super.handleRequest(session, request, response);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ protected String getServiceUrl(BootstrapContext context) {
+ ResourceURL portletResourceUrl = getRenderResponse(context)
+ .createResourceURL();
+ portletResourceUrl.setResourceID(VaadinPortlet.RESOURCE_URL_ID);
+ return portletResourceUrl.toString();
+ }
+
+ private RenderResponse getRenderResponse(BootstrapContext context) {
+ PortletResponse response = ((VaadinPortletResponse) context
+ .getResponse()).getPortletResponse();
+
+ RenderResponse renderResponse = (RenderResponse) response;
+ return renderResponse;
+ }
+
+ @Override
+ protected void appendMainScriptTagContents(BootstrapContext context,
+ StringBuilder builder) throws JSONException, IOException {
+ // fixed base theme to use - all portal pages with Vaadin
+ // applications will load this exactly once
+ String portalTheme = ((VaadinPortletRequest) context.getRequest())
+ .getPortalProperty(VaadinPortlet.PORTAL_PARAMETER_VAADIN_THEME);
+ if (portalTheme != null && !portalTheme.equals(context.getThemeName())) {
+ String portalThemeUri = getThemeUri(context, portalTheme);
+ // XSS safe - originates from portal properties
+ builder.append("vaadin.loadTheme('" + portalThemeUri + "');");
+ }
+
+ super.appendMainScriptTagContents(context, builder);
+ }
+
+ @Override
+ protected String getMainDivStyle(BootstrapContext context) {
+ VaadinService vaadinService = context.getRequest().getService();
+ return vaadinService.getDeploymentConfiguration()
+ .getApplicationOrSystemProperty(
+ VaadinPortlet.PORTLET_PARAMETER_STYLE, null);
+ }
+
+ @Override
+ protected JSONObject getApplicationParameters(BootstrapContext context)
+ throws JSONException, PaintException {
+ JSONObject parameters = super.getApplicationParameters(context);
+ VaadinPortletResponse response = (VaadinPortletResponse) context
+ .getResponse();
+ MimeResponse portletResponse = (MimeResponse) response
+ .getPortletResponse();
+ ResourceURL resourceURL = portletResponse.createResourceURL();
+ resourceURL.setResourceID("v-browserDetails");
+ parameters.put("browserDetailsUrl", resourceURL.toString());
+
+ // Always send path info as a query parameter
+ parameters
+ .put(ApplicationConstants.SERVICE_URL_PATH_AS_PARAMETER, true);
+
+ return parameters;
+ }
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java b/server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java
new file mode 100644
index 0000000000..8383cf607b
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PortletDummyRequestHandler.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server.communication;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+
+import javax.portlet.PortletResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+
+import com.vaadin.server.RequestHandler;
+import com.vaadin.server.VaadinPortletResponse;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+
+/**
+ * Request handler which provides a dummy HTML response to any resource request
+ * with the resource id DUMMY.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class PortletDummyRequestHandler implements RequestHandler {
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ if (!isDummyRequest(request)) {
+ return false;
+ }
+
+ /*
+ * This dummy page is used by action responses to redirect to, in order
+ * to prevent the boot strap code from being rendered into strange
+ * places such as iframes.
+ */
+ PortletResponse portletResponse = ((VaadinPortletResponse) response)
+ .getPortletResponse();
+ if (portletResponse instanceof ResourceResponse) {
+ ((ResourceResponse) portletResponse).setContentType("text/html");
+ }
+
+ final OutputStream out = ((ResourceResponse) response)
+ .getPortletOutputStream();
+ final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
+ new OutputStreamWriter(out, "UTF-8")));
+ outWriter.print("<html><body>dummy page</body></html>");
+ outWriter.close();
+
+ return true;
+ }
+
+ public static boolean isDummyRequest(VaadinRequest request) {
+ ResourceRequest resourceRequest = PortletUIInitHandler
+ .getResourceRequest(request);
+ if (resourceRequest == null) {
+ return false;
+ }
+
+ return resourceRequest.getResourceID() != null
+ && resourceRequest.getResourceID().equals("DUMMY");
+ }
+
+}
diff --git a/server/src/com/vaadin/server/communication/PortletListenerNotifier.java b/server/src/com/vaadin/server/communication/PortletListenerNotifier.java
new file mode 100644
index 0000000000..5c03a6f4dc
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PortletListenerNotifier.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+
+import javax.portlet.ActionRequest;
+import javax.portlet.ActionResponse;
+import javax.portlet.EventRequest;
+import javax.portlet.EventResponse;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import javax.portlet.RenderRequest;
+import javax.portlet.RenderResponse;
+import javax.portlet.ResourceRequest;
+import javax.portlet.ResourceResponse;
+
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.SynchronizedRequestHandler;
+import com.vaadin.server.VaadinPortletRequest;
+import com.vaadin.server.VaadinPortletResponse;
+import com.vaadin.server.VaadinPortletSession;
+import com.vaadin.server.VaadinPortletSession.PortletListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.UI;
+
+/**
+ * Notifies {@link PortletListener}s of a received portlet request.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class PortletListenerNotifier extends SynchronizedRequestHandler {
+
+ /**
+ * Fires portlet request events to any {@link PortletListener}s registered
+ * to the given session using
+ * {@link VaadinPortletSession#addPortletListener(PortletListener)}. The
+ * PortletListener method corresponding to the request type is invoked.
+ */
+ @Override
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
+
+ VaadinPortletSession sess = (VaadinPortletSession) session;
+ PortletRequest req = ((VaadinPortletRequest) request)
+ .getPortletRequest();
+ PortletResponse resp = ((VaadinPortletResponse) response)
+ .getPortletResponse();
+
+ // Finds the right UI
+ UI uI = null;
+ if (ServletPortletHelper.isUIDLRequest(request)) {
+ uI = session.getService().findUI(request);
+ }
+
+ if (request instanceof RenderRequest) {
+ sess.firePortletRenderRequest(uI, (RenderRequest) req,
+ (RenderResponse) resp);
+ } else if (request instanceof ActionRequest) {
+ sess.firePortletActionRequest(uI, (ActionRequest) req,
+ (ActionResponse) resp);
+ } else if (request instanceof EventRequest) {
+ sess.firePortletEventRequest(uI, (EventRequest) req,
+ (EventResponse) resp);
+ } else if (request instanceof ResourceRequest) {
+ sess.firePortletResourceRequest(uI, (ResourceRequest) req,
+ (ResourceResponse) resp);
+ }
+
+ return false;
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/PortletUIInitHandler.java b/server/src/com/vaadin/server/communication/PortletUIInitHandler.java
new file mode 100644
index 0000000000..d5d1e6b98d
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PortletUIInitHandler.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server.communication;
+
+import javax.portlet.PortletRequest;
+import javax.portlet.ResourceRequest;
+
+import com.vaadin.server.VaadinPortletRequest;
+import com.vaadin.server.VaadinRequest;
+
+public class PortletUIInitHandler extends UIInitHandler {
+
+ @Override
+ protected boolean isInitRequest(VaadinRequest request) {
+ return isUIInitRequest(request);
+ }
+
+ public static boolean isUIInitRequest(VaadinRequest request) {
+ ResourceRequest resourceRequest = getResourceRequest(request);
+ if (resourceRequest == null) {
+ return false;
+ }
+
+ return UIInitHandler.BROWSER_DETAILS_PARAMETER.equals(resourceRequest
+ .getResourceID());
+ }
+
+ /**
+ * Returns the {@link ResourceRequest} for the given request or null if none
+ * could be found.
+ *
+ * @param request
+ * The original request, must be a {@link VaadinPortletRequest}
+ * @return The resource request from the request parameter or null
+ */
+ static ResourceRequest getResourceRequest(VaadinRequest request) {
+ if (!(request instanceof VaadinPortletRequest)) {
+ throw new IllegalArgumentException(
+ "Request must a VaadinPortletRequest");
+ }
+ PortletRequest portletRequest = ((VaadinPortletRequest) request)
+ .getPortletRequest();
+ if (!(portletRequest instanceof ResourceRequest)) {
+ return null;
+ }
+
+ return (ResourceRequest) portletRequest;
+
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/PublishedFileHandler.java b/server/src/com/vaadin/server/communication/PublishedFileHandler.java
new file mode 100644
index 0000000000..8fe0f7085f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PublishedFileHandler.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.logging.Logger;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.vaadin.annotations.JavaScript;
+import com.vaadin.annotations.StyleSheet;
+import com.vaadin.server.Constants;
+import com.vaadin.server.LegacyCommunicationManager;
+import com.vaadin.server.RequestHandler;
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.ApplicationConstants;
+
+/**
+ * Serves a connector resource from the classpath if the resource has previously
+ * been registered by calling
+ * {@link LegacyCommunicationManager#registerDependency(String, Class)}. Sending
+ * arbitrary files from the classpath is prevented by only accepting resource
+ * names that have explicitly been registered. Resources can currently only be
+ * registered by including a {@link JavaScript} or {@link StyleSheet} annotation
+ * on a Connector class.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class PublishedFileHandler implements RequestHandler {
+
+ /**
+ * Writes the connector resource identified by the request URI to the
+ * response. If a published resource corresponding to the URI path is not
+ * found, writes a HTTP Not Found error to the response.
+ */
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ if (!ServletPortletHelper.isPublishedFileRequest(request)) {
+ return false;
+ }
+
+ String pathInfo = request.getPathInfo();
+ // + 2 to also remove beginning and ending slashes
+ String fileName = pathInfo
+ .substring(ApplicationConstants.PUBLISHED_FILE_PATH.length() + 2);
+
+ final String mimetype = response.getService().getMimeType(fileName);
+
+ // Security check: avoid accidentally serving from the UI of the
+ // classpath instead of relative to the context class
+ if (fileName.startsWith("/")) {
+ getLogger().warning(
+ "Published file request starting with / rejected: "
+ + fileName);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, fileName);
+ return true;
+ }
+
+ // Check that the resource name has been registered
+ session.lock();
+ Class<?> context;
+ try {
+ context = session.getCommunicationManager().getDependencies()
+ .get(fileName);
+ } finally {
+ session.unlock();
+ }
+
+ // Security check: don't serve resource if the name hasn't been
+ // registered in the map
+ if (context == null) {
+ getLogger().warning(
+ "Rejecting published file request for file that has not been published: "
+ + fileName);
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, fileName);
+ return true;
+ }
+
+ // Resolve file relative to the location of the context class
+ InputStream in = context.getResourceAsStream(fileName);
+ if (in == null) {
+ getLogger().warning(
+ fileName + " published by " + context.getName()
+ + " not found. Verify that the file "
+ + context.getPackage().getName().replace('.', '/')
+ + '/' + fileName
+ + " is available on the classpath.");
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, fileName);
+ return true;
+ }
+
+ // TODO Check and set cache headers
+
+ OutputStream out = null;
+ try {
+ if (mimetype != null) {
+ response.setContentType(mimetype);
+ }
+
+ out = response.getOutputStream();
+
+ final byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE];
+
+ int bytesRead = 0;
+ while ((bytesRead = in.read(buffer)) > 0) {
+ out.write(buffer, 0, bytesRead);
+ }
+ out.flush();
+ } finally {
+ try {
+ in.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ if (out != null) {
+ try {
+ out.close();
+ } catch (Exception e) {
+ // Do nothing
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(PublishedFileHandler.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/PushConnection.java b/server/src/com/vaadin/server/communication/PushConnection.java
new file mode 100644
index 0000000000..4e043f565f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PushConnection.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import com.vaadin.ui.UI;
+
+/**
+ * Represents a bidirectional ("push") connection between a single UI and its
+ * client-side.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public interface PushConnection {
+
+ /**
+ * Pushes pending state changes and client RPC calls to the client. It is
+ * NOT safe to invoke this method if not holding the session lock.
+ * <p>
+ * This is internal API; please use {@link UI#push()} instead.
+ */
+ public void push();
+
+ /**
+ * Disconnects the connection.
+ */
+ public void disconnect();
+
+ /**
+ * Returns whether this connection is currently open.
+ */
+ public boolean isConnected();
+
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/server/communication/PushHandler.java b/server/src/com/vaadin/server/communication/PushHandler.java
new file mode 100644
index 0000000000..e740db410d
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PushHandler.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.atmosphere.cpr.AtmosphereHandler;
+import org.atmosphere.cpr.AtmosphereRequest;
+import org.atmosphere.cpr.AtmosphereResource;
+import org.atmosphere.cpr.AtmosphereResource.TRANSPORT;
+import org.atmosphere.cpr.AtmosphereResourceEvent;
+import org.json.JSONException;
+
+import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
+import com.vaadin.server.ServiceException;
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.SessionExpiredException;
+import com.vaadin.server.SystemMessages;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinServletRequest;
+import com.vaadin.server.VaadinServletService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.server.WebBrowser;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.ui.UI;
+
+/**
+ * Establishes bidirectional ("push") communication channels
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class PushHandler implements AtmosphereHandler {
+
+ /**
+ * Callback interface used internally to process an event with the
+ * corresponding UI properly locked.
+ */
+ private interface PushEventCallback {
+ public void run(AtmosphereResource resource, UI ui) throws IOException;
+ }
+
+ /**
+ * Callback used when we receive a request to establish a push channel for a
+ * UI. Associate the AtmosphereResource with the UI and leave the connection
+ * open by calling resource.suspend(). If there is a pending push, send it
+ * now.
+ */
+ private static PushEventCallback establishCallback = new PushEventCallback() {
+ @Override
+ public void run(AtmosphereResource resource, UI ui) throws IOException {
+ getLogger().log(Level.FINER,
+ "New push connection with transport {0}",
+ resource.transport());
+ resource.getResponse().setContentType("text/plain; charset=UTF-8");
+
+ VaadinSession session = ui.getSession();
+ if (resource.transport() == TRANSPORT.STREAMING) {
+ // IE8 requires a longer padding to work properly if the
+ // initial message is small (#11573). Chrome does not work
+ // without the original padding...
+ WebBrowser browser = session.getBrowser();
+ if (browser.isIE() && browser.getBrowserMajorVersion() == 8) {
+ resource.padding(LONG_PADDING);
+ }
+ }
+
+ String requestToken = resource.getRequest().getParameter(
+ ApplicationConstants.CSRF_TOKEN_PARAMETER);
+ if (!VaadinService.isCsrfTokenValid(session, requestToken)) {
+ getLogger()
+ .log(Level.WARNING,
+ "Invalid CSRF token in new connection received from {0}",
+ resource.getRequest().getRemoteHost());
+ // Refresh on client side, create connection just for
+ // sending a message
+ sendRefreshAndDisconnect(resource);
+ return;
+ }
+
+ resource.suspend();
+
+ AtmospherePushConnection connection = new AtmospherePushConnection(
+ ui);
+ connection.connect(resource);
+
+ ui.setPushConnection(connection);
+ }
+ };
+
+ /**
+ * Callback used when we receive a UIDL request through Atmosphere. If the
+ * push channel is bidirectional (websockets), the request was sent via the
+ * same channel. Otherwise, the client used a separate AJAX request. Handle
+ * the request and send changed UI state via the push channel (we do not
+ * respond to the request directly.)
+ */
+ private static PushEventCallback receiveCallback = new PushEventCallback() {
+ @Override
+ public void run(AtmosphereResource resource, UI ui) throws IOException {
+ AtmosphereRequest req = resource.getRequest();
+
+ AtmospherePushConnection connection = getConnectionForUI(ui);
+
+ assert connection != null : "Got push from the client "
+ + "even though the connection does not seem to be "
+ + "valid. This might happen if a HttpSession is "
+ + "serialized and deserialized while the push "
+ + "connection is kept open or if the UI has a "
+ + "connection of unexpected type.";
+
+ Reader reader = connection.receiveMessage(req.getReader());
+ if (reader == null) {
+ // The whole message was not yet received
+ return;
+ }
+
+ // Should be set up by caller
+ VaadinRequest vaadinRequest = VaadinService.getCurrentRequest();
+ assert vaadinRequest != null;
+
+ try {
+ new ServerRpcHandler().handleRpc(ui, reader, vaadinRequest);
+ connection.push(false);
+ } catch (JSONException e) {
+ getLogger().log(Level.SEVERE, "Error writing JSON to response",
+ e);
+ // Refresh on client side
+ sendRefreshAndDisconnect(resource);
+ } catch (InvalidUIDLSecurityKeyException e) {
+ getLogger().log(Level.WARNING,
+ "Invalid security key received from {0}",
+ resource.getRequest().getRemoteHost());
+ // Refresh on client side
+ sendRefreshAndDisconnect(resource);
+ }
+ }
+ };
+
+ /**
+ * Callback used when a connection is closed by the client.
+ */
+ PushEventCallback disconnectCallback = new PushEventCallback() {
+ @Override
+ public void run(AtmosphereResource resource, UI ui) throws IOException {
+ PushMode pushMode = ui.getPushMode();
+ AtmospherePushConnection pushConnection = getConnectionForUI(ui);
+
+ String id = resource.uuid();
+
+ if (pushConnection == null) {
+ getLogger()
+ .log(Level.WARNING,
+ "Could not find push connection to close: {0} with transport {1}",
+ new Object[] { id, resource.transport() });
+ } else {
+ if (!pushMode.isEnabled()) {
+ /*
+ * The client is expected to close the connection after push
+ * mode has been set to disabled, just clean up some stuff
+ * and be done with it
+ */
+ getLogger().log(Level.FINEST,
+ "Connection closed for resource {0}", id);
+ } else {
+ /*
+ * Unexpected cancel, e.g. if the user closes the browser
+ * tab.
+ */
+ getLogger()
+ .log(Level.FINE,
+ "Connection unexpectedly closed for resource {0} with transport {1}",
+ new Object[] { id, resource.transport() });
+ }
+ ui.setPushConnection(null);
+ }
+ }
+ };
+
+ private static final String LONG_PADDING;
+
+ static {
+ char[] array = new char[4096];
+ Arrays.fill(array, '-');
+ LONG_PADDING = String.copyValueOf(array);
+
+ }
+ private VaadinServletService service;
+
+ public PushHandler(VaadinServletService service) {
+ this.service = service;
+ }
+
+ /**
+ * Find the UI for the atmosphere resource, lock it and invoke the callback.
+ *
+ * @param resource
+ * the atmosphere resource for the current request
+ * @param callback
+ * the push callback to call when a UI is found and locked
+ */
+ private void callWithUi(final AtmosphereResource resource,
+ final PushEventCallback callback) {
+ AtmosphereRequest req = resource.getRequest();
+ VaadinServletRequest vaadinRequest = new VaadinServletRequest(req,
+ service);
+ VaadinSession session = null;
+
+ service.requestStart(vaadinRequest, null);
+ try {
+ try {
+ session = service.findVaadinSession(vaadinRequest);
+ } catch (ServiceException e) {
+ getLogger().log(Level.SEVERE,
+ "Could not get session. This should never happen", e);
+ } catch (SessionExpiredException e) {
+ SystemMessages msg = service.getSystemMessages(
+ ServletPortletHelper.findLocale(null, null,
+ vaadinRequest), vaadinRequest);
+ try {
+ resource.getResponse()
+ .getWriter()
+ .write(VaadinService
+ .createCriticalNotificationJSON(
+ msg.getSessionExpiredCaption(),
+ msg.getSessionExpiredMessage(),
+ null, msg.getSessionExpiredURL()));
+ } catch (IOException e1) {
+ getLogger()
+ .log(Level.WARNING,
+ "Failed to notify client about unavailable session",
+ e);
+ }
+ return;
+ }
+
+ session.lock();
+ try {
+ VaadinSession.setCurrent(session);
+ // Sets UI.currentInstance
+ final UI ui = service.findUI(vaadinRequest);
+ if (ui == null) {
+ // This a request through an already open push connection to
+ // a UI which no longer exists.
+ resource.getResponse()
+ .getWriter()
+ .write(UidlRequestHandler.getUINotFoundErrorJSON(
+ service, vaadinRequest));
+ // End the connection
+ resource.resume();
+ return;
+ }
+
+ callback.run(resource, ui);
+ } catch (IOException e) {
+ getLogger().log(Level.INFO,
+ "An error occured while writing a push response", e);
+ } finally {
+ session.unlock();
+ }
+ } finally {
+ service.requestEnd(vaadinRequest, null, session);
+ }
+ }
+
+ @Override
+ public void onRequest(AtmosphereResource resource) {
+ AtmosphereRequest req = resource.getRequest();
+
+ if (req.getMethod().equalsIgnoreCase("GET")) {
+ callWithUi(resource, establishCallback);
+ } else if (req.getMethod().equalsIgnoreCase("POST")) {
+ callWithUi(resource, receiveCallback);
+ }
+ }
+
+ private static AtmospherePushConnection getConnectionForUI(UI ui) {
+ PushConnection pushConnection = ui.getPushConnection();
+ if (pushConnection instanceof AtmospherePushConnection) {
+ AtmospherePushConnection apc = (AtmospherePushConnection) pushConnection;
+ if (apc.isConnected()) {
+ return apc;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void onStateChange(AtmosphereResourceEvent event) throws IOException {
+ AtmosphereResource resource = event.getResource();
+
+ String id = resource.uuid();
+ if (event.isCancelled()) {
+ callWithUi(resource, disconnectCallback);
+ } else if (event.isResuming()) {
+ // A connection that was suspended earlier was resumed (committed to
+ // the client.) Should only happen if the transport is JSONP or
+ // long-polling.
+ getLogger().log(Level.FINER, "Resuming request for resource {0}",
+ id);
+ } else {
+ // A message was broadcast to this resource and should be sent to
+ // the client. We don't do any actual broadcasting, in the sense of
+ // sending to multiple recipients; any UIDL message is specific to a
+ // single client.
+ getLogger().log(Level.FINER, "Writing message to resource {0}", id);
+
+ Writer writer = resource.getResponse().getWriter();
+ writer.write(event.getMessage().toString());
+
+ switch (resource.transport()) {
+ case SSE:
+ case WEBSOCKET:
+ break;
+ case STREAMING:
+ writer.flush();
+ break;
+ case JSONP:
+ case LONG_POLLING:
+ resource.resume();
+ break;
+ default:
+ getLogger().log(Level.SEVERE, "Unknown transport {0}",
+ resource.transport());
+ }
+ }
+ }
+
+ @Override
+ public void destroy() {
+ }
+
+ /**
+ * Sends a refresh message to the given atmosphere resource. Uses an
+ * AtmosphereResource instead of an AtmospherePushConnection even though it
+ * might be possible to look up the AtmospherePushConnection from the UI to
+ * ensure border cases work correctly, especially when there temporarily are
+ * two push connections which try to use the same UI. Using the
+ * AtmosphereResource directly guarantees the message goes to the correct
+ * recipient.
+ *
+ * @param resource
+ * The atmosphere resource to send refresh to
+ *
+ */
+ private static void sendRefreshAndDisconnect(AtmosphereResource resource)
+ throws IOException {
+ AtmospherePushConnection connection = new AtmospherePushConnection(null);
+ connection.connect(resource);
+ connection.sendMessage(VaadinService.createCriticalNotificationJSON(
+ null, null, null, null));
+ connection.disconnect();
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(PushHandler.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/PushRequestHandler.java b/server/src/com/vaadin/server/communication/PushRequestHandler.java
new file mode 100644
index 0000000000..8360e08af9
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/PushRequestHandler.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+
+import org.atmosphere.client.TrackMessageSizeInterceptor;
+import org.atmosphere.cpr.ApplicationConfig;
+import org.atmosphere.cpr.AtmosphereFramework;
+import org.atmosphere.cpr.AtmosphereRequest;
+import org.atmosphere.cpr.AtmosphereResponse;
+
+import com.vaadin.server.RequestHandler;
+import com.vaadin.server.ServiceException;
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.SessionExpiredHandler;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinServletRequest;
+import com.vaadin.server.VaadinServletResponse;
+import com.vaadin.server.VaadinServletService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.ApplicationConstants;
+
+/**
+ * Handles requests to open a push (bidirectional) communication channel between
+ * the client and the server. After the initial request, communication through
+ * the push channel is managed by {@link PushHandler}.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class PushRequestHandler implements RequestHandler,
+ SessionExpiredHandler {
+
+ private AtmosphereFramework atmosphere;
+ private PushHandler pushHandler;
+
+ public PushRequestHandler(VaadinServletService service)
+ throws ServiceException {
+
+ atmosphere = new AtmosphereFramework();
+
+ pushHandler = new PushHandler(service);
+ atmosphere.addAtmosphereHandler("/*", pushHandler);
+ atmosphere.addInitParameter(ApplicationConfig.PROPERTY_SESSION_SUPPORT,
+ "true");
+
+ final String bufferSize = String
+ .valueOf(ApplicationConstants.WEBSOCKET_BUFFER_SIZE);
+ atmosphere.addInitParameter(ApplicationConfig.WEBSOCKET_BUFFER_SIZE,
+ bufferSize);
+ atmosphere.addInitParameter(ApplicationConfig.WEBSOCKET_MAXTEXTSIZE,
+ bufferSize);
+ atmosphere.addInitParameter(ApplicationConfig.WEBSOCKET_MAXBINARYSIZE,
+ bufferSize);
+
+ // Disable Atmosphere's message about commercial support
+ atmosphere.addInitParameter("org.atmosphere.cpr.showSupportMessage",
+ "false");
+
+ // Required to ensure the client-side knows at which points to split the
+ // message stream into individual messages when using certain transports
+ atmosphere.interceptor(new TrackMessageSizeInterceptor());
+
+ try {
+ atmosphere.init(service.getServlet().getServletConfig());
+ } catch (ServletException e) {
+ throw new ServiceException("Could not read atmosphere settings", e);
+ }
+ }
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+
+ if (!ServletPortletHelper.isPushRequest(request)) {
+ return false;
+ }
+
+ if (request instanceof VaadinServletRequest) {
+ try {
+ atmosphere.doCometSupport(AtmosphereRequest
+ .wrap((VaadinServletRequest) request),
+ AtmosphereResponse
+ .wrap((VaadinServletResponse) response));
+ } catch (ServletException e) {
+ // TODO PUSH decide how to handle
+ throw new RuntimeException(e);
+ }
+ } else {
+ throw new IllegalArgumentException(
+ "Portlets not currently supported");
+ }
+
+ return true;
+ }
+
+ public void destroy() {
+ atmosphere.destroy();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.server.SessionExpiredHandler#handleSessionExpired(com.vaadin
+ * .server.VaadinRequest, com.vaadin.server.VaadinResponse)
+ */
+ @Override
+ public boolean handleSessionExpired(VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ // Websockets request must be handled by accepting the websocket
+ // connection and then sending session expired so we let
+ // PushRequestHandler handle it
+ return handleRequest(null, request, response);
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/ResourceWriter.java b/server/src/com/vaadin/server/communication/ResourceWriter.java
new file mode 100644
index 0000000000..080027943f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/ResourceWriter.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.vaadin.server.JsonPaintTarget;
+import com.vaadin.server.LegacyCommunicationManager;
+import com.vaadin.ui.CustomLayout;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes resources to JSON. Currently only used for {@link CustomLayout}
+ * templates.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class ResourceWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing registered resources.
+ *
+ * @param ui
+ * The {@link UI} whose resources to write.
+ * @param writer
+ * The {@link Writer} to use.
+ * @param target
+ * The {@link JsonPaintTarget} containing the resources.
+ * @throws IOException
+ */
+ public void write(UI ui, Writer writer, JsonPaintTarget target)
+ throws IOException {
+
+ // TODO PUSH Refactor so that this is not needed
+ LegacyCommunicationManager manager = ui.getSession()
+ .getCommunicationManager();
+
+ // Precache custom layouts
+
+ // TODO We should only precache the layouts that are not
+ // cached already (plagiate from usedPaintableTypes)
+
+ writer.write("{");
+ int resourceIndex = 0;
+ for (final Iterator<Object> i = target.getUsedResources().iterator(); i
+ .hasNext();) {
+ final String resource = (String) i.next();
+ InputStream is = null;
+ try {
+ is = ui.getSession()
+ .getService()
+ .getThemeResourceAsStream(ui, manager.getTheme(ui),
+ resource);
+ } catch (final Exception e) {
+ // FIXME: Handle exception
+ getLogger().log(Level.FINER,
+ "Failed to get theme resource stream.", e);
+ }
+ if (is != null) {
+
+ writer.write((resourceIndex++ > 0 ? ", " : "") + "\""
+ + resource + "\" : ");
+ final StringBuffer layout = new StringBuffer();
+
+ try {
+ final InputStreamReader r = new InputStreamReader(is,
+ "UTF-8");
+ final char[] buffer = new char[20000];
+ int charsRead = 0;
+ while ((charsRead = r.read(buffer)) > 0) {
+ layout.append(buffer, 0, charsRead);
+ }
+ r.close();
+ } catch (final java.io.IOException e) {
+ // FIXME: Handle exception
+ getLogger().log(Level.INFO, "Resource transfer failed", e);
+ }
+ writer.write("\""
+ + JsonPaintTarget.escapeJSON(layout.toString()) + "\"");
+ } else {
+ // FIXME: Handle exception
+ getLogger().severe("CustomLayout not found: " + resource);
+ }
+ }
+ writer.write("}");
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(ResourceWriter.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/ServerRpcHandler.java b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
new file mode 100644
index 0000000000..3cc85909ee
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/ServerRpcHandler.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Serializable;
+import java.lang.reflect.Type;
+import java.text.CharacterIterator;
+import java.text.StringCharacterIterator;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.JsonCodec;
+import com.vaadin.server.LegacyCommunicationManager;
+import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
+import com.vaadin.server.ServerRpcManager;
+import com.vaadin.server.ServerRpcManager.RpcInvocationException;
+import com.vaadin.server.ServerRpcMethodInvocation;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VariableOwner;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.Connector;
+import com.vaadin.shared.communication.LegacyChangeVariablesInvocation;
+import com.vaadin.shared.communication.MethodInvocation;
+import com.vaadin.shared.communication.ServerRpc;
+import com.vaadin.shared.communication.UidlValue;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.ConnectorTracker;
+import com.vaadin.ui.UI;
+
+/**
+ * Handles a client-to-server message containing serialized {@link ServerRpc
+ * server RPC} invocations.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class ServerRpcHandler implements Serializable {
+
+ /* Variable records indexes */
+ public static final char VAR_BURST_SEPARATOR = '\u001d';
+
+ public static final char VAR_ESCAPE_CHARACTER = '\u001b';
+
+ private static final int MAX_BUFFER_SIZE = 64 * 1024;
+
+ /**
+ * Reads JSON containing zero or more serialized RPC calls (including legacy
+ * variable changes) and executes the calls.
+ *
+ * @param ui
+ * The {@link UI} receiving the calls. Cannot be null.
+ * @param reader
+ * The {@link Reader} used to read the JSON.
+ * @param request
+ * @throws IOException
+ * If reading the message fails.
+ * @throws InvalidUIDLSecurityKeyException
+ * If the received security key does not match the one stored in
+ * the session.
+ * @throws JSONException
+ * If deserializing the JSON fails.
+ */
+ public void handleRpc(UI ui, Reader reader, VaadinRequest request)
+ throws IOException, InvalidUIDLSecurityKeyException, JSONException {
+ ui.getSession().setLastRequestTimestamp(System.currentTimeMillis());
+
+ String changes = getMessage(reader);
+
+ final String[] bursts = changes.split(String
+ .valueOf(VAR_BURST_SEPARATOR));
+
+ if (bursts.length > 2) {
+ throw new RuntimeException(
+ "Multiple variable bursts not supported in Vaadin 7");
+ } else if (bursts.length <= 1) {
+ // The client sometimes sends empty messages, this is probably a bug
+ return;
+ }
+
+ // Security: double cookie submission pattern unless disabled by
+ // property
+ if (!VaadinService.isCsrfTokenValid(ui.getSession(), bursts[0])) {
+ throw new InvalidUIDLSecurityKeyException("");
+ }
+ handleBurst(ui, unescapeBurst(bursts[1]));
+ }
+
+ /**
+ * Processes a message burst received from the client.
+ *
+ * A burst can contain any number of RPC calls, including legacy variable
+ * change calls that are processed separately.
+ *
+ * Consecutive changes to the value of the same variable are combined and
+ * changeVariables() is only called once for them. This preserves the Vaadin
+ * 6 semantics for components and add-ons that do not use Vaadin 7 RPC
+ * directly.
+ *
+ * @param source
+ * @param uI
+ * the UI receiving the burst
+ * @param burst
+ * the content of the burst as a String to be parsed
+ */
+ private void handleBurst(UI uI, String burst) {
+ // TODO PUSH Refactor so that this is not needed
+ LegacyCommunicationManager manager = uI.getSession()
+ .getCommunicationManager();
+
+ try {
+ Set<Connector> enabledConnectors = new HashSet<Connector>();
+
+ List<MethodInvocation> invocations = parseInvocations(
+ uI.getConnectorTracker(), burst);
+ for (MethodInvocation invocation : invocations) {
+ final ClientConnector connector = manager.getConnector(uI,
+ invocation.getConnectorId());
+
+ if (connector != null && connector.isConnectorEnabled()) {
+ enabledConnectors.add(connector);
+ }
+ }
+
+ for (int i = 0; i < invocations.size(); i++) {
+ MethodInvocation invocation = invocations.get(i);
+
+ final ClientConnector connector = manager.getConnector(uI,
+ invocation.getConnectorId());
+ if (connector == null) {
+ getLogger()
+ .log(Level.WARNING,
+ "Received RPC call for unknown connector with id {0} (tried to invoke {1}.{2})",
+ new Object[] { invocation.getConnectorId(),
+ invocation.getInterfaceName(),
+ invocation.getMethodName() });
+ continue;
+ }
+
+ if (!enabledConnectors.contains(connector)) {
+
+ if (invocation instanceof LegacyChangeVariablesInvocation) {
+ LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
+ // TODO convert window close to a separate RPC call and
+ // handle above - not a variable change
+
+ // Handle special case where window-close is called
+ // after the window has been removed from the
+ // application or the application has closed
+ Map<String, Object> changes = legacyInvocation
+ .getVariableChanges();
+ if (changes.size() == 1 && changes.containsKey("close")
+ && Boolean.TRUE.equals(changes.get("close"))) {
+ // Silently ignore this
+ continue;
+ }
+ }
+
+ // Connector is disabled, log a warning and move to the next
+ String msg = "Ignoring RPC call for disabled connector "
+ + connector.getClass().getName();
+ if (connector instanceof Component) {
+ String caption = ((Component) connector).getCaption();
+ if (caption != null) {
+ msg += ", caption=" + caption;
+ }
+ }
+ getLogger().warning(msg);
+ continue;
+ }
+ // DragAndDropService has null UI
+ if (connector.getUI() != null && connector.getUI().isClosing()) {
+ String msg = "Ignoring RPC call for connector "
+ + connector.getClass().getName();
+ if (connector instanceof Component) {
+ String caption = ((Component) connector).getCaption();
+ if (caption != null) {
+ msg += ", caption=" + caption;
+ }
+ }
+ msg += " in closed UI";
+ getLogger().warning(msg);
+ continue;
+
+ }
+
+ if (invocation instanceof ServerRpcMethodInvocation) {
+ try {
+ ServerRpcManager.applyInvocation(connector,
+ (ServerRpcMethodInvocation) invocation);
+ } catch (RpcInvocationException e) {
+ manager.handleConnectorRelatedException(connector, e);
+ }
+ } else {
+
+ // All code below is for legacy variable changes
+ LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation;
+ Map<String, Object> changes = legacyInvocation
+ .getVariableChanges();
+ try {
+ if (connector instanceof VariableOwner) {
+ // The source parameter is never used anywhere
+ changeVariables(null, (VariableOwner) connector,
+ changes);
+ } else {
+ throw new IllegalStateException(
+ "Received legacy variable change for "
+ + connector.getClass().getName()
+ + " ("
+ + connector.getConnectorId()
+ + ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: "
+ + changes.keySet());
+ }
+ } catch (Exception e) {
+ manager.handleConnectorRelatedException(connector, e);
+ }
+ }
+ }
+ } catch (JSONException e) {
+ getLogger().warning(
+ "Unable to parse RPC call from the client: "
+ + e.getMessage());
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Parse a message burst from the client into a list of MethodInvocation
+ * instances.
+ *
+ * @param connectorTracker
+ * The ConnectorTracker used to lookup connectors
+ * @param burst
+ * message string (JSON)
+ * @return list of MethodInvocation to perform
+ * @throws JSONException
+ */
+ private List<MethodInvocation> parseInvocations(
+ ConnectorTracker connectorTracker, String burst)
+ throws JSONException {
+ JSONArray invocationsJson = new JSONArray(burst);
+
+ ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>();
+
+ MethodInvocation previousInvocation = null;
+ // parse JSON to MethodInvocations
+ for (int i = 0; i < invocationsJson.length(); ++i) {
+
+ JSONArray invocationJson = invocationsJson.getJSONArray(i);
+
+ MethodInvocation invocation = parseInvocation(invocationJson,
+ previousInvocation, connectorTracker);
+ if (invocation != null) {
+ // Can be null if the invocation was a legacy invocation and it
+ // was merged with the previous one or if the invocation was
+ // rejected because of an error.
+ invocations.add(invocation);
+ previousInvocation = invocation;
+ }
+ }
+ return invocations;
+ }
+
+ private MethodInvocation parseInvocation(JSONArray invocationJson,
+ MethodInvocation previousInvocation,
+ ConnectorTracker connectorTracker) throws JSONException {
+ String connectorId = invocationJson.getString(0);
+ String interfaceName = invocationJson.getString(1);
+ String methodName = invocationJson.getString(2);
+
+ if (connectorTracker.getConnector(connectorId) == null
+ && !connectorId
+ .equals(ApplicationConstants.DRAG_AND_DROP_CONNECTOR_ID)) {
+ getLogger()
+ .log(Level.WARNING,
+ "RPC call to "
+ + interfaceName
+ + "."
+ + methodName
+ + " received for connector "
+ + connectorId
+ + " but no such connector could be found. Resynchronizing client.");
+ // This is likely an out of sync issue (client tries to update a
+ // connector which is not present). Force resync.
+ connectorTracker.markAllConnectorsDirty();
+ return null;
+ }
+
+ JSONArray parametersJson = invocationJson.getJSONArray(3);
+
+ if (LegacyChangeVariablesInvocation.isLegacyVariableChange(
+ interfaceName, methodName)) {
+ if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) {
+ previousInvocation = null;
+ }
+
+ return parseLegacyChangeVariablesInvocation(connectorId,
+ interfaceName, methodName,
+ (LegacyChangeVariablesInvocation) previousInvocation,
+ parametersJson, connectorTracker);
+ } else {
+ return parseServerRpcInvocation(connectorId, interfaceName,
+ methodName, parametersJson, connectorTracker);
+ }
+
+ }
+
+ private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation(
+ String connectorId, String interfaceName, String methodName,
+ LegacyChangeVariablesInvocation previousInvocation,
+ JSONArray parametersJson, ConnectorTracker connectorTracker)
+ throws JSONException {
+ if (parametersJson.length() != 2) {
+ throw new JSONException(
+ "Invalid parameters in legacy change variables call. Expected 2, was "
+ + parametersJson.length());
+ }
+ String variableName = parametersJson.getString(0);
+ UidlValue uidlValue = (UidlValue) JsonCodec.decodeInternalType(
+ UidlValue.class, true, parametersJson.get(1), connectorTracker);
+
+ Object value = uidlValue.getValue();
+
+ if (previousInvocation != null
+ && previousInvocation.getConnectorId().equals(connectorId)) {
+ previousInvocation.setVariableChange(variableName, value);
+ return null;
+ } else {
+ return new LegacyChangeVariablesInvocation(connectorId,
+ variableName, value);
+ }
+ }
+
+ private ServerRpcMethodInvocation parseServerRpcInvocation(
+ String connectorId, String interfaceName, String methodName,
+ JSONArray parametersJson, ConnectorTracker connectorTracker)
+ throws JSONException {
+ ClientConnector connector = connectorTracker.getConnector(connectorId);
+
+ ServerRpcManager<?> rpcManager = connector.getRpcManager(interfaceName);
+ if (rpcManager == null) {
+ /*
+ * Security: Don't even decode the json parameters if no RpcManager
+ * corresponding to the received method invocation has been
+ * registered.
+ */
+ getLogger().warning(
+ "Ignoring RPC call to " + interfaceName + "." + methodName
+ + " in connector " + connector.getClass().getName()
+ + "(" + connectorId
+ + ") as no RPC implementation is regsitered");
+ return null;
+ }
+
+ // Use interface from RpcManager instead of loading the class based on
+ // the string name to avoid problems with OSGi
+ Class<? extends ServerRpc> rpcInterface = rpcManager.getRpcInterface();
+
+ ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation(
+ connectorId, rpcInterface, methodName, parametersJson.length());
+
+ Object[] parameters = new Object[parametersJson.length()];
+ Type[] declaredRpcMethodParameterTypes = invocation.getMethod()
+ .getGenericParameterTypes();
+
+ for (int j = 0; j < parametersJson.length(); ++j) {
+ Object parameterValue = parametersJson.get(j);
+ Type parameterType = declaredRpcMethodParameterTypes[j];
+ parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType,
+ parameterValue, connectorTracker);
+ }
+ invocation.setParameters(parameters);
+ return invocation;
+ }
+
+ protected void changeVariables(Object source, VariableOwner owner,
+ Map<String, Object> m) {
+ owner.changeVariables(source, m);
+ }
+
+ /**
+ * Unescape encoded burst separator characters in a burst received from the
+ * client. This protects from separator injection attacks.
+ *
+ * @param encodedValue
+ * to decode
+ * @return decoded value
+ */
+ protected String unescapeBurst(String encodedValue) {
+ final StringBuilder result = new StringBuilder();
+ final StringCharacterIterator iterator = new StringCharacterIterator(
+ encodedValue);
+ char character = iterator.current();
+ while (character != CharacterIterator.DONE) {
+ if (VAR_ESCAPE_CHARACTER == character) {
+ character = iterator.next();
+ switch (character) {
+ case VAR_ESCAPE_CHARACTER + 0x30:
+ // escaped escape character
+ result.append(VAR_ESCAPE_CHARACTER);
+ break;
+ case VAR_BURST_SEPARATOR + 0x30:
+ // +0x30 makes these letters for easier reading
+ result.append((char) (character - 0x30));
+ break;
+ case CharacterIterator.DONE:
+ // error
+ throw new RuntimeException(
+ "Communication error: Unexpected end of message");
+ default:
+ // other escaped character - probably a client-server
+ // version mismatch
+ throw new RuntimeException(
+ "Invalid escaped character from the client - check that the widgetset and server versions match");
+ }
+ } else {
+ // not a special character - add it to the result as is
+ result.append(character);
+ }
+ character = iterator.next();
+ }
+ return result.toString();
+ }
+
+ protected String getMessage(Reader reader) throws IOException {
+
+ StringBuilder sb = new StringBuilder(MAX_BUFFER_SIZE);
+ char[] buffer = new char[MAX_BUFFER_SIZE];
+
+ while (true) {
+ int read = reader.read(buffer);
+ if (read == -1) {
+ break;
+ }
+ sb.append(buffer, 0, read);
+ }
+
+ return sb.toString();
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(ServerRpcHandler.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/ServletBootstrapHandler.java b/server/src/com/vaadin/server/communication/ServletBootstrapHandler.java
new file mode 100644
index 0000000000..4b6517c30f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/ServletBootstrapHandler.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import com.vaadin.server.BootstrapHandler;
+import com.vaadin.server.VaadinServlet;
+import com.vaadin.server.VaadinServletService;
+
+public class ServletBootstrapHandler extends BootstrapHandler {
+ @Override
+ protected String getServiceUrl(BootstrapContext context) {
+ String pathInfo = context.getRequest().getPathInfo();
+ if (pathInfo == null) {
+ return null;
+ } else {
+ /*
+ * Make a relative URL to the servlet by adding one ../ for each
+ * path segment in pathInfo (i.e. the part of the requested path
+ * that comes after the servlet mapping)
+ */
+ return VaadinServletService.getCancelingRelativePath(pathInfo);
+ }
+ }
+
+ @Override
+ public String getThemeName(BootstrapContext context) {
+ String themeName = context.getRequest().getParameter(
+ VaadinServlet.URL_PARAMETER_THEME);
+ if (themeName == null) {
+ themeName = super.getThemeName(context);
+ }
+ return themeName;
+ }
+} \ No newline at end of file
diff --git a/client/src/com/vaadin/client/SynchronousXHR.java b/server/src/com/vaadin/server/communication/ServletUIInitHandler.java
index a19c9bad16..6286c161f2 100644
--- a/client/src/com/vaadin/client/SynchronousXHR.java
+++ b/server/src/com/vaadin/server/communication/ServletUIInitHandler.java
@@ -13,24 +13,21 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.client;
+package com.vaadin.server.communication;
-import com.google.gwt.xhr.client.XMLHttpRequest;
+import com.vaadin.server.VaadinRequest;
-public class SynchronousXHR extends XMLHttpRequest {
+public class ServletUIInitHandler extends UIInitHandler {
- protected SynchronousXHR() {
+ @Override
+ protected boolean isInitRequest(VaadinRequest request) {
+ return isUIInitRequest(request);
}
- public native final void synchronousPost(String uri, String requestData)
- /*-{
- try {
- this.open("POST", uri, false);
- this.setRequestHeader("Content-Type", "text/plain;charset=utf-8");
- this.send(requestData);
- } catch (e) {
- // No errors are managed as this is synchronous forceful send that can just fail
- }
- }-*/;
+ public static boolean isUIInitRequest(VaadinRequest request) {
+ return "POST".equals(request.getMethod())
+ && request
+ .getParameter(UIInitHandler.BROWSER_DETAILS_PARAMETER) != null;
+ }
}
diff --git a/server/src/com/vaadin/server/communication/SessionRequestHandler.java b/server/src/com/vaadin/server/communication/SessionRequestHandler.java
new file mode 100644
index 0000000000..244cb0121d
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/SessionRequestHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import com.vaadin.server.RequestHandler;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinSession;
+
+/**
+ * Handles a request by passing it to each registered {@link RequestHandler} in
+ * the session in turn until one produces a response. This method is used for
+ * requests that have not been handled by any specific functionality in the
+ * servlet/portlet.
+ * <p>
+ * The request handlers are invoked in the reverse order in which they were
+ * added to the session 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 session is invoked towards the end unless any previous
+ * handler has already produced a response.
+ * </p>
+ * <p>
+ * The session is not locked during execution of the request handlers. The
+ * request handler can itself decide if it needs to lock the session or not.
+ * </p>
+ *
+ * @see VaadinSession#addRequestHandler(RequestHandler)
+ * @see RequestHandler
+ *
+ * @since 7.1
+ */
+public class SessionRequestHandler implements RequestHandler {
+
+ @Override
+ public boolean handleRequest(VaadinSession session, VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ // Use a copy to avoid ConcurrentModificationException
+ session.lock();
+ ArrayList<RequestHandler> requestHandlers;
+ try {
+ requestHandlers = new ArrayList<RequestHandler>(
+ session.getRequestHandlers());
+ } finally {
+ session.unlock();
+ }
+ for (RequestHandler handler : requestHandlers) {
+ if (handler.handleRequest(session, request, response)) {
+ return true;
+ }
+ }
+ // If not handled
+ return false;
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/SharedStateWriter.java b/server/src/com/vaadin/server/communication/SharedStateWriter.java
new file mode 100644
index 0000000000..fdf834387f
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/SharedStateWriter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.Collection;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.PaintException;
+import com.vaadin.shared.communication.SharedState;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes {@link SharedState shared state} changes to JSON.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class SharedStateWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing the pending state changes of the dirty
+ * connectors of the given UI.
+ *
+ * @param ui
+ * The UI whose state changes should be written.
+ * @param writer
+ * The writer to use.
+ * @throws IOException
+ * If the serialization fails.
+ */
+ public void write(UI ui, Writer writer) throws IOException {
+
+ Collection<ClientConnector> dirtyVisibleConnectors = ui
+ .getConnectorTracker().getDirtyVisibleConnectors();
+
+ JSONObject sharedStates = new JSONObject();
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ // encode and send shared state
+ try {
+ JSONObject stateJson = connector.encodeState();
+
+ if (stateJson != null && stateJson.length() != 0) {
+ sharedStates.put(connector.getConnectorId(), stateJson);
+ }
+ } catch (JSONException e) {
+ throw new PaintException(
+ "Failed to serialize shared state for connector "
+ + connector.getClass().getName() + " ("
+ + connector.getConnectorId() + "): "
+ + e.getMessage(), e);
+ }
+ }
+ writer.write(sharedStates.toString());
+ }
+}
diff --git a/server/src/com/vaadin/server/StreamingEndEventImpl.java b/server/src/com/vaadin/server/communication/StreamingEndEventImpl.java
index 756cadee6b..f8cfb160be 100644
--- a/server/src/com/vaadin/server/StreamingEndEventImpl.java
+++ b/server/src/com/vaadin/server/communication/StreamingEndEventImpl.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.server;
+package com.vaadin.server.communication;
import com.vaadin.server.StreamVariable.StreamingEndEvent;
diff --git a/server/src/com/vaadin/server/StreamingErrorEventImpl.java b/server/src/com/vaadin/server/communication/StreamingErrorEventImpl.java
index 53e25399cd..9d9a19e4fe 100644
--- a/server/src/com/vaadin/server/StreamingErrorEventImpl.java
+++ b/server/src/com/vaadin/server/communication/StreamingErrorEventImpl.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.server;
+package com.vaadin.server.communication;
import com.vaadin.server.StreamVariable.StreamingErrorEvent;
diff --git a/server/src/com/vaadin/server/StreamingProgressEventImpl.java b/server/src/com/vaadin/server/communication/StreamingProgressEventImpl.java
index 610cd30c13..69f3bfb29c 100644
--- a/server/src/com/vaadin/server/StreamingProgressEventImpl.java
+++ b/server/src/com/vaadin/server/communication/StreamingProgressEventImpl.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.server;
+package com.vaadin.server.communication;
import com.vaadin.server.StreamVariable.StreamingProgressEvent;
diff --git a/server/src/com/vaadin/server/StreamingStartEventImpl.java b/server/src/com/vaadin/server/communication/StreamingStartEventImpl.java
index 3cd41bbb6d..bd16f08801 100644
--- a/server/src/com/vaadin/server/StreamingStartEventImpl.java
+++ b/server/src/com/vaadin/server/communication/StreamingStartEventImpl.java
@@ -13,7 +13,7 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
-package com.vaadin.server;
+package com.vaadin.server.communication;
import com.vaadin.server.StreamVariable.StreamingStartEvent;
diff --git a/server/src/com/vaadin/server/communication/UIInitHandler.java b/server/src/com/vaadin/server/communication/UIInitHandler.java
new file mode 100644
index 0000000000..e4b5360b49
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/UIInitHandler.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import com.vaadin.annotations.PreserveOnRefresh;
+import com.vaadin.server.LegacyApplicationUIProvider;
+import com.vaadin.server.SynchronizedRequestHandler;
+import com.vaadin.server.UIClassSelectionEvent;
+import com.vaadin.server.UICreateEvent;
+import com.vaadin.server.UIProvider;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.shared.ui.ui.UIConstants;
+import com.vaadin.ui.UI;
+
+/**
+ * Handles an initial request from the client to initialize a {@link UI}.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public abstract class UIInitHandler extends SynchronizedRequestHandler {
+
+ public static final String BROWSER_DETAILS_PARAMETER = "v-browserDetails";
+
+ protected abstract boolean isInitRequest(VaadinRequest request);
+
+ @Override
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
+ if (!isInitRequest(request)) {
+ return false;
+ }
+
+ StringWriter stringWriter = new StringWriter();
+
+ try {
+ assert UI.getCurrent() == null;
+
+ // Set browser information from the request
+ session.getBrowser().updateRequestDetails(request);
+
+ UI uI = getBrowserDetailsUI(request, session);
+
+ session.getCommunicationManager().repaintAll(uI);
+
+ JSONObject params = new JSONObject();
+ params.put(UIConstants.UI_ID_PARAMETER, uI.getUIId());
+ String initialUIDL = getInitialUidl(request, uI);
+ params.put("uidl", initialUIDL);
+
+ stringWriter.write(params.toString());
+ } catch (JSONException e) {
+ throw new IOException("Error producing initial UIDL", e);
+ } finally {
+ stringWriter.close();
+ }
+
+ return commitJsonResponse(request, response, stringWriter.toString());
+ }
+
+ /**
+ * Commit the JSON response. We can't write immediately to the output stream
+ * as we want to write only a critical notification if something goes wrong
+ * during the response handling.
+ *
+ * @param request
+ * The request that resulted in this response
+ * @param response
+ * The response to write to
+ * @param json
+ * The JSON to write
+ * @return true if the JSON was written successfully, false otherwise
+ * @throws IOException
+ * If there was an exception while writing to the output
+ */
+ static boolean commitJsonResponse(VaadinRequest request,
+ VaadinResponse response, String json) throws IOException {
+ // The response was produced without errors so write it to the client
+ response.setContentType("application/json; charset=UTF-8");
+
+ // Ensure that the browser does not cache UIDL responses.
+ // iOS 6 Safari requires this (#9732)
+ response.setHeader("Cache-Control", "no-cache");
+
+ // NOTE! GateIn requires, for some weird reason, getOutputStream
+ // to be used instead of getWriter() (it seems to interpret
+ // application/json as a binary content type)
+ OutputStreamWriter outputWriter = new OutputStreamWriter(
+ response.getOutputStream(), "UTF-8");
+ try {
+ outputWriter.write(json);
+ // NOTE GateIn requires the buffers to be flushed to work
+ outputWriter.flush();
+ } finally {
+ outputWriter.close();
+ }
+
+ return true;
+ }
+
+ private UI getBrowserDetailsUI(VaadinRequest request, VaadinSession session) {
+ VaadinService vaadinService = request.getService();
+
+ List<UIProvider> uiProviders = session.getUIProviders();
+
+ UIClassSelectionEvent classSelectionEvent = new UIClassSelectionEvent(
+ request);
+
+ UIProvider provider = null;
+ Class<? extends UI> uiClass = null;
+ for (UIProvider p : uiProviders) {
+ // Check for existing LegacyWindow
+ if (p instanceof LegacyApplicationUIProvider) {
+ LegacyApplicationUIProvider legacyProvider = (LegacyApplicationUIProvider) p;
+
+ UI existingUi = legacyProvider
+ .getExistingUI(classSelectionEvent);
+ if (existingUi != null) {
+ reinitUI(existingUi, request);
+ return existingUi;
+ }
+ }
+
+ uiClass = p.getUIClass(classSelectionEvent);
+ if (uiClass != null) {
+ provider = p;
+ break;
+ }
+ }
+
+ if (provider == null || uiClass == null) {
+ return null;
+ }
+
+ // Check for an existing UI based on window.name
+
+ // Special parameter sent by vaadinBootstrap.js
+ String windowName = request.getParameter("v-wn");
+
+ Map<String, Integer> retainOnRefreshUIs = session
+ .getPreserveOnRefreshUIs();
+ if (windowName != null && !retainOnRefreshUIs.isEmpty()) {
+ // Check for a known UI
+
+ Integer retainedUIId = retainOnRefreshUIs.get(windowName);
+
+ if (retainedUIId != null) {
+ UI retainedUI = session.getUIById(retainedUIId.intValue());
+ if (uiClass.isInstance(retainedUI)) {
+ reinitUI(retainedUI, request);
+ return retainedUI;
+ } else {
+ getLogger().info(
+ "Not using retained UI in " + windowName
+ + " because retained UI was of type "
+ + retainedUI.getClass() + " but " + uiClass
+ + " is expected for the request.");
+ }
+ }
+ }
+
+ // No existing UI found - go on by creating and initializing one
+
+ Integer uiId = Integer.valueOf(session.getNextUIid());
+
+ // Explicit Class.cast to detect if the UIProvider does something
+ // unexpected
+ UICreateEvent event = new UICreateEvent(request, uiClass, uiId);
+ UI ui = uiClass.cast(provider.createInstance(event));
+
+ // Initialize some fields for a newly created UI
+ if (ui.getSession() != session) {
+ // Session already set for LegacyWindow
+ ui.setSession(session);
+ }
+
+ PushMode pushMode = provider.getPushMode(event);
+ if (pushMode == null) {
+ pushMode = session.getService().getDeploymentConfiguration()
+ .getPushMode();
+ }
+ ui.setPushMode(pushMode);
+
+ // Set thread local here so it is available in init
+ UI.setCurrent(ui);
+
+ ui.doInit(request, uiId.intValue());
+
+ session.addUI(ui);
+
+ // Remember if it should be remembered
+ if (vaadinService.preserveUIOnRefresh(provider, event)) {
+ // Remember this UI
+ if (windowName == null) {
+ getLogger().warning(
+ "There is no window.name available for UI " + uiClass
+ + " that should be preserved.");
+ } else {
+ session.getPreserveOnRefreshUIs().put(windowName, uiId);
+ }
+ }
+
+ return ui;
+ }
+
+ /**
+ * Updates a UI that has already been initialized but is now loaded again,
+ * e.g. because of {@link PreserveOnRefresh}.
+ *
+ * @param ui
+ * @param request
+ */
+ private void reinitUI(UI ui, VaadinRequest request) {
+ UI.setCurrent(ui);
+
+ // Fire fragment change if the fragment has changed
+ String location = request.getParameter("v-loc");
+ if (location != null) {
+ ui.getPage().updateLocation(location);
+ }
+ }
+
+ /**
+ * 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 uI
+ * the UI for which the UIDL should be generated
+ * @return a string with the initial UIDL message
+ * @throws JSONException
+ * if an exception occurs while encoding output
+ * @throws IOException
+ */
+ protected String getInitialUidl(VaadinRequest request, UI uI)
+ throws JSONException, IOException {
+ StringWriter writer = new StringWriter();
+ try {
+ writer.write("{");
+
+ VaadinSession session = uI.getSession();
+ if (session.getConfiguration().isXsrfProtectionEnabled()) {
+ writer.write(getSecurityKeyUIDL(session));
+ }
+ new UidlWriter().write(uI, writer, true, false, false);
+ writer.write("}");
+
+ String initialUIDL = writer.toString();
+ getLogger().log(Level.FINE, "Initial UIDL:" + initialUIDL);
+ return initialUIDL;
+ } finally {
+ writer.close();
+ }
+ }
+
+ /**
+ * Gets the security key (and generates one if needed) as UIDL.
+ *
+ * @param session
+ * the vaadin session to which the security key belongs
+ * @return the security key UIDL or "" if the feature is turned off
+ */
+ private static String getSecurityKeyUIDL(VaadinSession session) {
+ String seckey = session.getCsrfToken();
+
+ return "\"" + ApplicationConstants.UIDL_SECURITY_TOKEN_ID + "\":\""
+ + seckey + "\",";
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(UIInitHandler.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/communication/UidlRequestHandler.java b/server/src/com/vaadin/server/communication/UidlRequestHandler.java
new file mode 100644
index 0000000000..73ff92f8bd
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/UidlRequestHandler.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.LinkedList;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.json.JSONException;
+
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.Constants;
+import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
+import com.vaadin.server.ServletPortletHelper;
+import com.vaadin.server.SessionExpiredHandler;
+import com.vaadin.server.SynchronizedRequestHandler;
+import com.vaadin.server.SystemMessages;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.shared.ApplicationConstants;
+import com.vaadin.shared.JsonConstants;
+import com.vaadin.shared.Version;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.UI;
+
+/**
+ * Processes a UIDL request from the client.
+ *
+ * Uses {@link ServerRpcHandler} to execute client-to-server RPC invocations and
+ * {@link UidlWriter} to write state changes and client RPC calls back to the
+ * client.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class UidlRequestHandler extends SynchronizedRequestHandler implements
+ SessionExpiredHandler {
+
+ public static final String UIDL_PATH = "UIDL/";
+
+ private ServerRpcHandler rpcHandler = new ServerRpcHandler();
+
+ public UidlRequestHandler() {
+ }
+
+ @Override
+ public boolean synchronizedHandleRequest(VaadinSession session,
+ VaadinRequest request, VaadinResponse response) throws IOException {
+ if (!ServletPortletHelper.isUIDLRequest(request)) {
+ return false;
+ }
+ UI uI = session.getService().findUI(request);
+ if (uI == null) {
+ // This should not happen but it will if the UI has been closed. We
+ // really don't want to see it in the server logs though
+ response.getWriter().write(
+ getUINotFoundErrorJSON(session.getService(), request));
+ return true;
+ }
+
+ checkWidgetsetVersion(request);
+ String requestThemeName = request.getParameter("theme");
+ ClientConnector highlightedConnector;
+ // repaint requested or session has timed out and new one is created
+ boolean repaintAll;
+
+ // TODO PUSH repaintAll, analyzeLayouts, highlightConnector should be
+ // part of the message payload to make the functionality transport
+ // agnostic
+
+ repaintAll = (request
+ .getParameter(ApplicationConstants.URL_PARAMETER_REPAINT_ALL) != null);
+
+ boolean analyzeLayouts = false;
+ if (repaintAll) {
+ // analyzing can be done only with repaintAll
+ analyzeLayouts = (request
+ .getParameter(ApplicationConstants.PARAM_ANALYZE_LAYOUTS) != null);
+
+ String pid = request
+ .getParameter(ApplicationConstants.PARAM_HIGHLIGHT_CONNECTOR);
+ if (pid != null) {
+ highlightedConnector = uI.getConnectorTracker().getConnector(
+ pid);
+ highlightConnector(highlightedConnector);
+ }
+ }
+
+ StringWriter stringWriter = new StringWriter();
+
+ try {
+ rpcHandler.handleRpc(uI, request.getReader(), request);
+
+ if (repaintAll) {
+ session.getCommunicationManager().repaintAll(uI);
+ }
+
+ writeUidl(request, response, uI, stringWriter, repaintAll,
+ analyzeLayouts);
+ } catch (JSONException e) {
+ getLogger().log(Level.SEVERE, "Error writing JSON to response", e);
+ // Refresh on client side
+ response.getWriter().write(
+ VaadinService.createCriticalNotificationJSON(null, null,
+ null, null));
+ return true;
+ } catch (InvalidUIDLSecurityKeyException e) {
+ getLogger().log(Level.WARNING,
+ "Invalid security key received from {0}",
+ request.getRemoteHost());
+ // Refresh on client side
+ response.getWriter().write(
+ VaadinService.createCriticalNotificationJSON(null, null,
+ null, null));
+ return true;
+ } finally {
+ stringWriter.close();
+ requestThemeName = null;
+ }
+
+ return UIInitHandler.commitJsonResponse(request, response,
+ stringWriter.toString());
+ }
+
+ /**
+ * Checks that the version reported by the client (widgetset) matches that
+ * of the server.
+ *
+ * @param request
+ */
+ private void checkWidgetsetVersion(VaadinRequest request) {
+ String widgetsetVersion = request.getParameter("v-wsver");
+ if (widgetsetVersion == null) {
+ // Only check when the widgetset version is reported. It is reported
+ // in the first UIDL request (not the initial request as it is a
+ // plain GET /)
+ return;
+ }
+
+ if (!Version.getFullVersion().equals(widgetsetVersion)) {
+ getLogger().warning(
+ String.format(Constants.WIDGETSET_MISMATCH_INFO,
+ Version.getFullVersion(), widgetsetVersion));
+ }
+ }
+
+ private void writeUidl(VaadinRequest request, VaadinResponse response,
+ UI ui, Writer writer, boolean repaintAll, boolean analyzeLayouts)
+ throws IOException, JSONException {
+ openJsonMessage(writer, response);
+
+ new UidlWriter().write(ui, writer, repaintAll, analyzeLayouts, false);
+
+ closeJsonMessage(writer);
+ }
+
+ protected void closeJsonMessage(Writer outWriter) throws IOException {
+ outWriter.write("}]");
+ }
+
+ /**
+ * Writes the opening of JSON message to be sent to client.
+ *
+ * @param outWriter
+ * @param response
+ * @throws IOException
+ */
+ protected void openJsonMessage(Writer outWriter, VaadinResponse response)
+ throws IOException {
+ // some dirt to prevent cross site scripting
+ outWriter.write("for(;;);[{");
+ }
+
+ // TODO Does this belong here?
+ protected void highlightConnector(ClientConnector highlightedConnector) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("*** Debug details of a connector: *** \n");
+ sb.append("Type: ");
+ sb.append(highlightedConnector.getClass().getName());
+ sb.append("\nId:");
+ sb.append(highlightedConnector.getConnectorId());
+ if (highlightedConnector instanceof Component) {
+ Component component = (Component) highlightedConnector;
+ if (component.getCaption() != null) {
+ sb.append("\nCaption:");
+ sb.append(component.getCaption());
+ }
+ }
+ printHighlightedConnectorHierarchy(sb, highlightedConnector);
+ getLogger().info(sb.toString());
+ }
+
+ // TODO Does this belong here?
+ protected void printHighlightedConnectorHierarchy(StringBuilder sb,
+ ClientConnector connector) {
+ LinkedList<ClientConnector> h = new LinkedList<ClientConnector>();
+ h.add(connector);
+ ClientConnector parent = connector.getParent();
+ while (parent != null) {
+ h.addFirst(parent);
+ parent = parent.getParent();
+ }
+
+ sb.append("\nConnector hierarchy:\n");
+ VaadinSession session2 = connector.getUI().getSession();
+ sb.append(session2.getClass().getName());
+ sb.append("(");
+ sb.append(session2.getClass().getSimpleName());
+ sb.append(".java");
+ sb.append(":1)");
+ int l = 1;
+ for (ClientConnector connector2 : h) {
+ sb.append("\n");
+ for (int i = 0; i < l; i++) {
+ sb.append(" ");
+ }
+ l++;
+ Class<? extends ClientConnector> connectorClass = connector2
+ .getClass();
+ Class<?> topClass = connectorClass;
+ while (topClass.getEnclosingClass() != null) {
+ topClass = topClass.getEnclosingClass();
+ }
+ sb.append(connectorClass.getName());
+ sb.append("(");
+ sb.append(topClass.getSimpleName());
+ sb.append(".java:1)");
+ }
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(UidlRequestHandler.class.getName());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.server.SessionExpiredHandler#handleSessionExpired(com.vaadin
+ * .server.VaadinRequest, com.vaadin.server.VaadinResponse)
+ */
+ @Override
+ public boolean handleSessionExpired(VaadinRequest request,
+ VaadinResponse response) throws IOException {
+ if (!ServletPortletHelper.isUIDLRequest(request)) {
+ return false;
+ }
+ VaadinService service = request.getService();
+ SystemMessages systemMessages = service.getSystemMessages(
+ ServletPortletHelper.findLocale(null, null, request), request);
+
+ service.writeStringResponse(response, JsonConstants.JSON_CONTENT_TYPE,
+ VaadinService.createCriticalNotificationJSON(
+ systemMessages.getSessionExpiredCaption(),
+ systemMessages.getSessionExpiredMessage(), null,
+ systemMessages.getSessionExpiredURL()));
+
+ return true;
+ }
+
+ /**
+ * Returns the JSON which should be returned to the client when a request
+ * for a non-existent UI arrives.
+ *
+ * @param service
+ * The VaadinService
+ * @param vaadinRequest
+ * The request which triggered this, or null if not available
+ * @since 7.1
+ * @return A JSON string
+ */
+ static String getUINotFoundErrorJSON(VaadinService service,
+ VaadinRequest vaadinRequest) {
+ SystemMessages ci = service.getSystemMessages(
+ vaadinRequest.getLocale(), vaadinRequest);
+ // Session Expired is not really the correct message as the
+ // session exists but the requested UI does not.
+ // Using Communication Error for now.
+ String json = VaadinService.createCriticalNotificationJSON(
+ ci.getCommunicationErrorCaption(),
+ ci.getCommunicationErrorMessage(), null,
+ ci.getCommunicationErrorURL());
+
+ return json;
+ }
+
+}
diff --git a/server/src/com/vaadin/server/communication/UidlWriter.java b/server/src/com/vaadin/server/communication/UidlWriter.java
new file mode 100644
index 0000000000..fbe2fb86d5
--- /dev/null
+++ b/server/src/com/vaadin/server/communication/UidlWriter.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.server.communication;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import com.vaadin.annotations.JavaScript;
+import com.vaadin.annotations.StyleSheet;
+import com.vaadin.server.ClientConnector;
+import com.vaadin.server.JsonPaintTarget;
+import com.vaadin.server.LegacyCommunicationManager;
+import com.vaadin.server.LegacyCommunicationManager.ClientCache;
+import com.vaadin.server.SystemMessages;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.ConnectorTracker;
+import com.vaadin.ui.UI;
+
+/**
+ * Serializes pending server-side changes to UI state to JSON. This includes
+ * shared state, client RPC invocations, connector hierarchy changes, connector
+ * type information among others.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class UidlWriter implements Serializable {
+
+ /**
+ * Writes a JSON object containing all pending changes to the given UI.
+ *
+ * @param ui
+ * The {@link UI} whose changes to write
+ * @param writer
+ * The writer to use
+ * @param repaintAll
+ * Whether the client should re-render the whole UI.
+ * @param analyzeLayouts
+ * Whether detected layout problems should be logged.
+ * @param async
+ * True if this message is sent by the server asynchronously,
+ * false if it is a response to a client message.
+ *
+ * @throws IOException
+ * If the writing fails.
+ * @throws JSONException
+ * If the JSON serialization fails.
+ */
+ public void write(UI ui, Writer writer, boolean repaintAll,
+ boolean analyzeLayouts, boolean async) throws IOException,
+ JSONException {
+ ArrayList<ClientConnector> dirtyVisibleConnectors = ui
+ .getConnectorTracker().getDirtyVisibleConnectors();
+ VaadinSession session = ui.getSession();
+ LegacyCommunicationManager manager = session.getCommunicationManager();
+ // Paints components
+ ConnectorTracker uiConnectorTracker = ui.getConnectorTracker();
+ getLogger().log(Level.FINE, "* Creating response to client");
+
+ getLogger().log(
+ Level.FINE,
+ "Found " + dirtyVisibleConnectors.size()
+ + " dirty connectors to paint");
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ boolean initialized = uiConnectorTracker
+ .isClientSideInitialized(connector);
+ connector.beforeClientResponse(!initialized);
+ }
+
+ uiConnectorTracker.setWritingResponse(true);
+ try {
+ writer.write("\"changes\" : ");
+
+ JsonPaintTarget paintTarget = new JsonPaintTarget(manager, writer,
+ !repaintAll);
+
+ new LegacyUidlWriter().write(ui, writer, paintTarget);
+
+ paintTarget.close();
+ writer.write(", "); // close changes
+
+ // send shared state to client
+
+ // for now, send the complete state of all modified and new
+ // components
+
+ // Ideally, all this would be sent before "changes", but that causes
+ // complications with legacy components that create sub-components
+ // in their paint phase. Nevertheless, this will be processed on the
+ // client after component creation but before legacy UIDL
+ // processing.
+
+ writer.write("\"state\":");
+ new SharedStateWriter().write(ui, writer);
+ writer.write(", "); // close states
+
+ // TODO This should be optimized. The type only needs to be
+ // sent once for each connector id + on refresh. Use the same cache
+ // as
+ // widget mapping
+
+ writer.write("\"types\":");
+ new ConnectorTypeWriter().write(ui, writer, paintTarget);
+ writer.write(", "); // close states
+
+ // Send update hierarchy information to the client.
+
+ // This could be optimized aswell to send only info if hierarchy has
+ // actually changed. Much like with the shared state. Note though
+ // that an empty hierarchy is information aswell (e.g. change from 1
+ // child to 0 children)
+
+ writer.write("\"hierarchy\":");
+ new ConnectorHierarchyWriter().write(ui, writer);
+ writer.write(", "); // close hierarchy
+
+ // send server to client RPC calls for components in the UI, in call
+ // order
+
+ // collect RPC calls from components in the UI in the order in
+ // which they were performed, remove the calls from components
+
+ writer.write("\"rpc\" : ");
+ new ClientRpcWriter().write(ui, writer);
+ writer.write(", "); // close rpc
+
+ uiConnectorTracker.markAllConnectorsClean();
+
+ writer.write("\"meta\" : ");
+
+ SystemMessages messages = ui.getSession().getService()
+ .getSystemMessages(ui.getLocale(), null);
+ // TODO hilightedConnector
+ new MetadataWriter().write(ui, writer, repaintAll, analyzeLayouts,
+ async, null, messages);
+ writer.write(", ");
+
+ writer.write("\"resources\" : ");
+ new ResourceWriter().write(ui, writer, paintTarget);
+
+ Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget
+ .getUsedClientConnectors();
+ boolean typeMappingsOpen = false;
+ ClientCache clientCache = manager.getClientCache(ui);
+
+ List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>();
+
+ for (Class<? extends ClientConnector> class1 : usedClientConnectors) {
+ if (clientCache.cache(class1)) {
+ // client does not know the mapping key for this type, send
+ // mapping to client
+ newConnectorTypes.add(class1);
+
+ if (!typeMappingsOpen) {
+ typeMappingsOpen = true;
+ writer.write(", \"typeMappings\" : { ");
+ } else {
+ writer.write(" , ");
+ }
+ String canonicalName = class1.getCanonicalName();
+ writer.write("\"");
+ writer.write(canonicalName);
+ writer.write("\" : ");
+ writer.write(manager.getTagForType(class1));
+ }
+ }
+ if (typeMappingsOpen) {
+ writer.write(" }");
+ }
+
+ // TODO PUSH Refactor to TypeInheritanceWriter or something
+ boolean typeInheritanceMapOpen = false;
+ if (typeMappingsOpen) {
+ // send the whole type inheritance map if any new mappings
+ for (Class<? extends ClientConnector> class1 : usedClientConnectors) {
+ if (!ClientConnector.class.isAssignableFrom(class1
+ .getSuperclass())) {
+ continue;
+ }
+ if (!typeInheritanceMapOpen) {
+ typeInheritanceMapOpen = true;
+ writer.write(", \"typeInheritanceMap\" : { ");
+ } else {
+ writer.write(" , ");
+ }
+ writer.write("\"");
+ writer.write(manager.getTagForType(class1));
+ writer.write("\" : ");
+ writer.write(manager
+ .getTagForType((Class<? extends ClientConnector>) class1
+ .getSuperclass()));
+ }
+ if (typeInheritanceMapOpen) {
+ writer.write(" }");
+ }
+ }
+
+ // TODO Refactor to DependencyWriter or something
+ /*
+ * Ensure super classes come before sub classes to get script
+ * dependency order right. Sub class @JavaScript might assume that
+ *
+ * @JavaScript defined by super class is already loaded.
+ */
+ Collections.sort(newConnectorTypes, new Comparator<Class<?>>() {
+ @Override
+ public int compare(Class<?> o1, Class<?> o2) {
+ // TODO optimize using Class.isAssignableFrom?
+ return hierarchyDepth(o1) - hierarchyDepth(o2);
+ }
+
+ private int hierarchyDepth(Class<?> type) {
+ if (type == Object.class) {
+ return 0;
+ } else {
+ return hierarchyDepth(type.getSuperclass()) + 1;
+ }
+ }
+ });
+
+ List<String> scriptDependencies = new ArrayList<String>();
+ List<String> styleDependencies = new ArrayList<String>();
+
+ for (Class<? extends ClientConnector> class1 : newConnectorTypes) {
+ JavaScript jsAnnotation = class1
+ .getAnnotation(JavaScript.class);
+ if (jsAnnotation != null) {
+ for (String uri : jsAnnotation.value()) {
+ scriptDependencies.add(manager.registerDependency(uri,
+ class1));
+ }
+ }
+
+ StyleSheet styleAnnotation = class1
+ .getAnnotation(StyleSheet.class);
+ if (styleAnnotation != null) {
+ for (String uri : styleAnnotation.value()) {
+ styleDependencies.add(manager.registerDependency(uri,
+ class1));
+ }
+ }
+ }
+
+ // Include script dependencies in output if there are any
+ if (!scriptDependencies.isEmpty()) {
+ writer.write(", \"scriptDependencies\": "
+ + new JSONArray(scriptDependencies).toString());
+ }
+
+ // Include style dependencies in output if there are any
+ if (!styleDependencies.isEmpty()) {
+ writer.write(", \"styleDependencies\": "
+ + new JSONArray(styleDependencies).toString());
+ }
+
+ // add any pending locale definitions requested by the client
+ writer.write(", \"locales\": ");
+ manager.printLocaleDeclarations(writer);
+
+ if (manager.getDragAndDropService() != null) {
+ manager.getDragAndDropService().printJSONResponse(writer);
+ }
+
+ for (ClientConnector connector : dirtyVisibleConnectors) {
+ uiConnectorTracker.markClientSideInitialized(connector);
+ }
+
+ assert (uiConnectorTracker.getDirtyConnectors().isEmpty()) : "Connectors have been marked as dirty during the end of the paint phase. This is most certainly not intended.";
+
+ writePerformanceData(ui, writer);
+ } finally {
+ uiConnectorTracker.setWritingResponse(false);
+ uiConnectorTracker.cleanConnectorMap();
+ }
+ }
+
+ /**
+ * Adds the performance timing data (used by TestBench 3) to the UIDL
+ * response.
+ *
+ * @throws IOException
+ */
+ private void writePerformanceData(UI ui, Writer writer) throws IOException {
+ writer.write(String.format(", \"timings\":[%d, %d]", ui.getSession()
+ .getCumulativeRequestDuration(), ui.getSession()
+ .getLastRequestDuration()));
+ }
+
+ private static final Logger getLogger() {
+ return Logger.getLogger(UidlWriter.class.getName());
+ }
+}
diff --git a/server/src/com/vaadin/server/themeutils/SASSAddonImportFileCreator.java b/server/src/com/vaadin/server/themeutils/SASSAddonImportFileCreator.java
new file mode 100644
index 0000000000..f199c347eb
--- /dev/null
+++ b/server/src/com/vaadin/server/themeutils/SASSAddonImportFileCreator.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server.themeutils;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+
+import com.vaadin.server.widgetsetutils.ClassPathExplorer;
+import com.vaadin.server.widgetsetutils.ClassPathExplorer.LocationInfo;
+
+/**
+ * Helper class for managing the addon imports and creating an a SCSS file for
+ * importing all your addon themes. The helper method searches the classpath for
+ * Vaadin addons and uses the 'Vaadin-Themes' metadata to create the imports.
+ *
+ * <p>
+ * The addons.scss is always overwritten when this tool is invoked.
+ * </p>
+ *
+ * @since 7.1
+ */
+public class SASSAddonImportFileCreator {
+
+ private static final String ADDON_IMPORTS_FILE = "addons.scss";
+
+ private static final String ADDON_IMPORTS_FILE_TEXT = "This file is automatically managed and "
+ + "will be overwritten from time to time.";
+
+ /**
+ *
+ * @param args
+ * Theme directory where the addons.scss file should be created
+ */
+ public static void main(String[] args) throws IOException {
+ if (args.length == 0) {
+ printUsage();
+ } else {
+ String themeDirectory = args[0];
+ updateTheme(themeDirectory);
+ }
+ }
+
+ /**
+ * Updates a themes addons.scss with the addon themes found on the classpath
+ *
+ * @param themeDirectory
+ * The target theme directory
+ */
+ public static void updateTheme(String themeDirectory) throws IOException {
+
+ File addonImports = new File(themeDirectory, ADDON_IMPORTS_FILE);
+
+ if (!addonImports.exists()) {
+
+ // Ensure directory exists
+ addonImports.getParentFile().mkdirs();
+
+ // Ensure file exists
+ addonImports.createNewFile();
+ }
+
+ LocationInfo info = ClassPathExplorer
+ .getAvailableWidgetSetsAndStylesheets();
+
+ try {
+ PrintStream printStream = new PrintStream(new FileOutputStream(
+ addonImports));
+
+ printStream.println("/* " + ADDON_IMPORTS_FILE_TEXT + " */");
+
+ printStream.println("/* Do not manually edit this file. */");
+
+ printStream.println();
+
+ Map<String, URL> addonThemes = info.getAddonStyles();
+
+ // Sort addon styles so that CSS imports are first and SCSS import
+ // last
+ List<String> paths = new ArrayList<String>(addonThemes.keySet());
+ Collections.sort(paths, new Comparator<String>() {
+
+ @Override
+ public int compare(String path1, String path2) {
+ if (path1.toLowerCase().endsWith(".css")
+ && path2.toLowerCase().endsWith(".scss")) {
+ return -1;
+ }
+ if (path1.toLowerCase().endsWith(".scss")
+ && path2.toLowerCase().endsWith(".css")) {
+ return 1;
+ }
+ return 0;
+ }
+ });
+
+ List<String> mixins = new ArrayList<String>();
+ for (String path : paths) {
+ mixins.addAll(addImport(printStream, path,
+ addonThemes.get(path)));
+ printStream.println();
+ }
+
+ createAddonsMixin(printStream, mixins);
+
+ } catch (FileNotFoundException e) {
+ // Should not happen since file is checked before this
+ e.printStackTrace();
+ }
+ }
+
+ private static List<String> addImport(PrintStream stream, String file,
+ URL location) {
+
+ // Add import comment
+ printImportComment(stream, location);
+
+ List<String> foundMixins = new ArrayList<String>();
+
+ if (file.endsWith(".css")) {
+ stream.print("@import url(\"../../../" + file + "\");\n");
+ } else {
+ // Assume SASS
+ stream.print("@import \"../../../" + file + "\";\n");
+
+ // Convention is to name the mixin after the stylesheet. Strip
+ // .scss from filename
+ String mixin = file.substring(file.lastIndexOf("/") + 1,
+ file.length() - ".scss".length());
+
+ foundMixins.add(mixin);
+ }
+
+ stream.println();
+
+ return foundMixins;
+ }
+
+ private static void printImportComment(PrintStream stream, URL location) {
+
+ // file:/absolute/path/to/addon.jar!/
+ String path = location.getPath();
+
+ try {
+ // Try to parse path for better readability
+ path = path.substring(path.lastIndexOf(":") + 1,
+ path.lastIndexOf("!"));
+
+ // Extract jar archive filename
+ path = path.substring(path.lastIndexOf("/") + 1);
+
+ } catch (Exception e) {
+ // Parsing failed but no worries, we then use whatever
+ // location.getPath() returns
+ }
+
+ stream.println("/* Provided by " + path + " */");
+ }
+
+ private static void createAddonsMixin(PrintStream stream,
+ List<String> mixins) {
+
+ stream.println("/* Import and include this mixin into your project theme to include the addon themes */");
+ stream.println("@mixin addons {");
+ for (String addon : mixins) {
+ stream.println("\t@include " + addon + ";");
+ }
+ stream.println("}");
+ stream.println();
+ }
+
+ private static void printUsage() {
+ String className = SASSAddonImportFileCreator.class.getSimpleName();
+ PrintStream o = System.out;
+ o.println(className + " usage:");
+ o.println();
+ o.println("./" + className + " [Path to target theme folder]");
+ }
+}
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java b/server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java
index 34024f1616..cc04e50b3c 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java
+++ b/server/src/com/vaadin/server/widgetsetutils/ClassPathExplorer.java
@@ -72,6 +72,32 @@ public class ClassPathExplorer {
};
/**
+ * Contains information about widgetsets and themes found on the classpath
+ *
+ * @since 7.1
+ */
+ public static class LocationInfo {
+
+ private final Map<String, URL> widgetsets;
+
+ private final Map<String, URL> addonStyles;
+
+ public LocationInfo(Map<String, URL> widgetsets, Map<String, URL> themes) {
+ this.widgetsets = widgetsets;
+ addonStyles = themes;
+ }
+
+ public Map<String, URL> getWidgetsets() {
+ return widgetsets;
+ }
+
+ public Map<String, URL> getAddonStyles() {
+ return addonStyles;
+ }
+
+ }
+
+ /**
* Raw class path entries as given in the java class path string. Only
* entries that could include widgets/widgetsets are listed (primarily
* directories, Vaadin JARs and add-on JARs).
@@ -95,13 +121,26 @@ public class ClassPathExplorer {
* Finds the names and locations of widgetsets available on the class path.
*
* @return map from widgetset classname to widgetset location URL
+ * @deprecated Use {@link #getAvailableWidgetSetsAndStylesheets()} instead
*/
+ @Deprecated
public static Map<String, URL> getAvailableWidgetSets() {
+ return getAvailableWidgetSetsAndStylesheets().getWidgetsets();
+ }
+
+ /**
+ * Finds the names and locations of widgetsets and themes available on the
+ * class path.
+ *
+ * @return
+ */
+ public static LocationInfo getAvailableWidgetSetsAndStylesheets() {
long start = System.currentTimeMillis();
Map<String, URL> widgetsets = new HashMap<String, URL>();
+ Map<String, URL> themes = new HashMap<String, URL>();
Set<String> keySet = classpathLocations.keySet();
for (String location : keySet) {
- searchForWidgetSets(location, widgetsets);
+ searchForWidgetSetsAndAddonStyles(location, widgetsets, themes);
}
long end = System.currentTimeMillis();
@@ -114,14 +153,25 @@ public class ClassPathExplorer {
sb.append(widgetsets.get(ws));
sb.append("\n");
}
+
+ sb.append("Addon styles found from classpath:\n");
+ for (String theme : themes.keySet()) {
+ sb.append("\t");
+ sb.append(theme);
+ sb.append(" in ");
+ sb.append(themes.get(theme));
+ sb.append("\n");
+ }
+
final Logger logger = getLogger();
logger.info(sb.toString());
logger.info("Search took " + (end - start) + "ms");
- return widgetsets;
+ return new LocationInfo(widgetsets, themes);
}
/**
- * Finds all GWT modules / Vaadin widgetsets in a valid location.
+ * Finds all GWT modules / Vaadin widgetsets and Addon styles in a valid
+ * location.
*
* If the location is a directory, all GWT modules (files with the
* ".gwt.xml" extension) are added to widgetsets.
@@ -136,8 +186,9 @@ public class ClassPathExplorer {
* separators) to a URL (see {@link #classpathLocations}) - new
* entries are added to this map
*/
- private static void searchForWidgetSets(String locationString,
- Map<String, URL> widgetsets) {
+ private static void searchForWidgetSetsAndAddonStyles(
+ String locationString, Map<String, URL> widgetsets,
+ Map<String, URL> addonStyles) {
URL location = classpathLocations.get(locationString);
File directory = new File(location.getFile());
@@ -197,18 +248,32 @@ public class ClassPathExplorer {
// No manifest so this is not a Vaadin Add-on
return;
}
+
+ // Check for widgetset attribute
String value = manifest.getMainAttributes().getValue(
"Vaadin-Widgetsets");
if (value != null) {
String[] widgetsetNames = value.split(",");
for (int i = 0; i < widgetsetNames.length; i++) {
- String widgetsetname = widgetsetNames[i].trim()
- .intern();
+ String widgetsetname = widgetsetNames[i].trim();
if (!widgetsetname.equals("")) {
widgetsets.put(widgetsetname, location);
}
}
}
+
+ // Check for theme attribute
+ value = manifest.getMainAttributes().getValue(
+ "Vaadin-Stylesheets");
+ if (value != null) {
+ String[] stylesheets = value.split(",");
+ for (int i = 0; i < stylesheets.length; i++) {
+ String stylesheet = stylesheets[i].trim();
+ if (!stylesheet.equals("")) {
+ addonStyles.put(stylesheet, location);
+ }
+ }
+ }
}
} catch (IOException e) {
getLogger().log(Level.WARNING, "Error parsing jar file", e);
@@ -323,6 +388,9 @@ public class ClassPathExplorer {
if (mainAttributes.getValue("Vaadin-Widgetsets") != null) {
return true;
}
+ if (mainAttributes.getValue("Vaadin-Stylesheets") != null) {
+ return true;
+ }
}
} catch (MalformedURLException e) {
getLogger().log(Level.FINEST, "Failed to inspect JAR file",
@@ -457,14 +525,10 @@ public class ClassPathExplorer {
* Test method for helper tool
*/
public static void main(String[] args) {
- getLogger().info("Searching available widgetsets...");
+ getLogger().info(
+ "Searching for available widgetsets and stylesheets...");
- Map<String, URL> availableWidgetSets = ClassPathExplorer
- .getAvailableWidgetSets();
- for (String string : availableWidgetSets.keySet()) {
-
- getLogger().info(string + " in " + availableWidgetSets.get(string));
- }
+ ClassPathExplorer.getAvailableWidgetSetsAndStylesheets();
}
private static final Logger getLogger() {
diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/WidgetSetBuilder.java b/server/src/com/vaadin/server/widgetsetutils/WidgetSetBuilder.java
index 3a0e59df71..3a0e59df71 100644
--- a/client-compiler/src/com/vaadin/server/widgetsetutils/WidgetSetBuilder.java
+++ b/server/src/com/vaadin/server/widgetsetutils/WidgetSetBuilder.java
diff --git a/server/src/com/vaadin/ui/AbstractColorPicker.java b/server/src/com/vaadin/ui/AbstractColorPicker.java
index d7037e366d..c3bdd49155 100644
--- a/server/src/com/vaadin/ui/AbstractColorPicker.java
+++ b/server/src/com/vaadin/ui/AbstractColorPicker.java
@@ -405,6 +405,7 @@ public abstract class AbstractColorPicker extends AbstractComponent implements
window.setImmediate(true);
window.addCloseListener(this);
window.addColorChangeListener(new ColorChangeListener() {
+ @Override
public void colorChanged(ColorChangeEvent event) {
AbstractColorPicker.this.colorChanged(event);
}
diff --git a/server/src/com/vaadin/ui/AbstractField.java b/server/src/com/vaadin/ui/AbstractField.java
index 422e0a1796..6648f69ff9 100644
--- a/server/src/com/vaadin/ui/AbstractField.java
+++ b/server/src/com/vaadin/ui/AbstractField.java
@@ -25,13 +25,13 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
-import java.util.logging.Logger;
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.LegacyPropertyHelper;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.Converter.ConversionException;
import com.vaadin.data.util.converter.ConverterUtil;
@@ -42,6 +42,7 @@ import com.vaadin.server.AbstractErrorMessage;
import com.vaadin.server.CompositeErrorMessage;
import com.vaadin.server.ErrorMessage;
import com.vaadin.shared.AbstractFieldState;
+import com.vaadin.shared.util.SharedUtil;
/**
* <p>
@@ -74,9 +75,6 @@ public abstract class AbstractField<T> extends AbstractComponent implements
/* Private members */
- private static final Logger logger = Logger.getLogger(AbstractField.class
- .getName());
-
/**
* Value of the abstract field.
*/
@@ -370,13 +368,24 @@ public abstract class AbstractField<T> extends AbstractComponent implements
return buffered;
}
- /* Property interface implementation */
-
/**
- * Returns the (field) value converted to a String using toString().
+ * Returns a string representation of this object. The returned string
+ * representation depends on if the legacy Property toString mode is enabled
+ * or disabled.
+ * <p>
+ * If legacy Property toString mode is enabled, returns the value of this
+ * <code>Field</code> converted to a String.
+ * </p>
+ * <p>
+ * If legacy Property toString mode is disabled, the string representation
+ * has no special meaning
+ * </p>
+ *
+ * @see LegacyPropertyHelper#isLegacyToStringEnabled()
*
- * @see java.lang.Object#toString()
- * @deprecated As of 7.0, use {@link #getValue()} to get the value of the
+ * @return A string representation of the value value stored in the Property
+ * or a string representation of the Property object.
+ * @deprecated As of 7.0. 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
@@ -385,17 +394,15 @@ public abstract class AbstractField<T> extends AbstractComponent implements
@Deprecated
@Override
public String toString() {
- logger.warning("You are using AbstractField.toString() to get the value for a "
- + getClass().getSimpleName()
- + ". This will not be supported starting from Vaadin 7.1 "
- + "(your debugger might call toString() and cause this message to appear).");
- final Object value = getFieldValue();
- if (value == null) {
- return null;
+ if (!LegacyPropertyHelper.isLegacyToStringEnabled()) {
+ return super.toString();
+ } else {
+ return LegacyPropertyHelper.legacyPropertyToString(this);
}
- return value.toString();
}
+ /* Property interface implementation */
+
/**
* Gets the current value of the field.
*
@@ -451,7 +458,7 @@ public abstract class AbstractField<T> extends AbstractComponent implements
throws Property.ReadOnlyException, Converter.ConversionException,
InvalidValueException {
- if (!equals(newFieldValue, getInternalValue())) {
+ if (!SharedUtil.equals(newFieldValue, getInternalValue())) {
// Read only fields can not be changed
if (isReadOnly()) {
@@ -459,7 +466,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements
}
try {
T doubleConvertedFieldValue = convertFromModel(convertToModel(newFieldValue));
- if (!equals(newFieldValue, doubleConvertedFieldValue)) {
+ if (!SharedUtil
+ .equals(newFieldValue, doubleConvertedFieldValue)) {
newFieldValue = doubleConvertedFieldValue;
repaintIsNotNeeded = false;
}
@@ -536,11 +544,9 @@ public abstract class AbstractField<T> extends AbstractComponent implements
}
}
+ @Deprecated
static boolean equals(Object value1, Object value2) {
- if (value1 == null) {
- return value2 == null;
- }
- return value1.equals(value2);
+ return SharedUtil.equals(value1, value2);
}
/* External data source */
@@ -1228,8 +1234,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements
public void valueChange(Property.ValueChangeEvent event) {
if (!isBuffered()) {
if (committingValueToDataSource) {
- boolean propertyNotifiesOfTheBufferedValue = equals(event
- .getProperty().getValue(), getInternalValue());
+ boolean propertyNotifiesOfTheBufferedValue = SharedUtil.equals(
+ event.getProperty().getValue(), getInternalValue());
if (!propertyNotifiesOfTheBufferedValue) {
/*
* Property (or chained property like PropertyFormatter) now
@@ -1345,15 +1351,33 @@ public abstract class AbstractField<T> extends AbstractComponent implements
}
private void localeMightHaveChanged() {
- if (!equals(valueLocale, getLocale()) && dataSource != null
- && !isModified()) {
- // When we have a data source and the internal value is directly
- // read from that we want to update the value
- T newInternalValue = convertFromModel(getPropertyDataSource()
- .getValue());
- if (!equals(newInternalValue, getInternalValue())) {
- setInternalValue(newInternalValue);
- fireValueChange(false);
+ if (!SharedUtil.equals(valueLocale, getLocale())) {
+ // The locale HAS actually changed
+
+ if (dataSource != null && !isModified()) {
+ // When we have a data source and the internal value is directly
+ // read from that we want to update the value
+ T newInternalValue = convertFromModel(getPropertyDataSource()
+ .getValue());
+ if (!SharedUtil.equals(newInternalValue, getInternalValue())) {
+ setInternalValue(newInternalValue);
+ fireValueChange(false);
+ }
+ } else if (dataSource == null && converter != null) {
+ /*
+ * No data source but a converter has been set. The same issues
+ * as above but we cannot use propertyDataSource. Convert the
+ * current value back to a model value using the old locale and
+ * then convert back using the new locale. If this does not
+ * match the field value we need to set the converted value
+ * again.
+ */
+ Object convertedValue = convertToModel(getInternalValue(),
+ valueLocale);
+ T newinternalValue = convertFromModel(convertedValue);
+ if (!SharedUtil.equals(getInternalValue(), newinternalValue)) {
+ setConvertedValue(convertedValue);
+ }
}
}
}
@@ -1600,7 +1624,7 @@ public abstract class AbstractField<T> extends AbstractComponent implements
setModified(false);
// If the new value differs from the previous one
- if (!equals(newFieldValue, getInternalValue())) {
+ if (!SharedUtil.equals(newFieldValue, getInternalValue())) {
setInternalValue(newFieldValue);
fireValueChange(false);
} else if (wasModified) {
diff --git a/server/src/com/vaadin/ui/AbstractMedia.java b/server/src/com/vaadin/ui/AbstractMedia.java
index 41677467bb..97947b568d 100644
--- a/server/src/com/vaadin/ui/AbstractMedia.java
+++ b/server/src/com/vaadin/ui/AbstractMedia.java
@@ -25,6 +25,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.vaadin.server.ConnectorResource;
+import com.vaadin.server.DownloadStream;
import com.vaadin.server.Resource;
import com.vaadin.server.ResourceReference;
import com.vaadin.server.VaadinRequest;
@@ -83,7 +84,14 @@ public abstract class AbstractMedia extends AbstractComponent {
public boolean handleConnectorRequest(VaadinRequest request,
VaadinResponse response, String path) throws IOException {
Matcher matcher = Pattern.compile("(\\d+)(/.*)?").matcher(path);
- if (matcher.matches()) {
+ if (!matcher.matches()) {
+ return super.handleConnectorRequest(request, response, path);
+ }
+
+ DownloadStream stream;
+
+ getSession().lock();
+ try {
List<URLReference> sources = getState().sources;
int sourceIndex = Integer.parseInt(matcher.group(1));
@@ -98,11 +106,13 @@ public abstract class AbstractMedia extends AbstractComponent {
URLReference reference = sources.get(sourceIndex);
ConnectorResource resource = (ConnectorResource) ResourceReference
.getResource(reference);
- resource.getStream().writeResponse(request, response);
- return true;
- } else {
- return super.handleConnectorRequest(request, response, path);
+ stream = resource.getStream();
+ } finally {
+ getSession().unlock();
}
+
+ stream.writeResponse(request, response);
+ return true;
}
private Logger getLogger() {
diff --git a/server/src/com/vaadin/ui/AbstractOrderedLayout.java b/server/src/com/vaadin/ui/AbstractOrderedLayout.java
index 8c2f86926d..c9eb756daa 100644
--- a/server/src/com/vaadin/ui/AbstractOrderedLayout.java
+++ b/server/src/com/vaadin/ui/AbstractOrderedLayout.java
@@ -53,6 +53,8 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
*/
protected LinkedList<Component> components = new LinkedList<Component>();
+ private Alignment defaultComponentAlignment = Alignment.TOP_LEFT;
+
/* Child component alignments */
/**
@@ -147,7 +149,9 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
}
private void componentAdded(Component c) {
- getState().childData.put(c, new ChildComponentData());
+ ChildComponentData ccd = new ChildComponentData();
+ ccd.alignmentBitmask = getDefaultComponentAlignment().getBitMask();
+ getState().childData.put(c, ccd);
}
/**
@@ -417,4 +421,27 @@ public abstract class AbstractOrderedLayout extends AbstractLayout implements
public void setMargin(MarginInfo marginInfo) {
getState().marginsBitmask = marginInfo.getBitMask();
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Layout.AlignmentHandler#getDefaultComponentAlignment()
+ */
+ @Override
+ public Alignment getDefaultComponentAlignment() {
+ return defaultComponentAlignment;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.Layout.AlignmentHandler#setDefaultComponentAlignment(com
+ * .vaadin.ui.Alignment)
+ */
+ @Override
+ public void setDefaultComponentAlignment(Alignment defaultAlignment) {
+ defaultComponentAlignment = defaultAlignment;
+ }
+
}
diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java
index fcfc55aadc..1bcf802f12 100644
--- a/server/src/com/vaadin/ui/Button.java
+++ b/server/src/com/vaadin/ui/Button.java
@@ -32,6 +32,7 @@ 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.server.Resource;
import com.vaadin.shared.MouseEventDetails;
import com.vaadin.shared.ui.button.ButtonServerRpc;
import com.vaadin.shared.ui.button.ButtonState;
@@ -581,6 +582,35 @@ public class Button extends AbstractComponent implements
}
/**
+ * Sets the component's icon and alt text.
+ *
+ * An alt text is shown when an image could not be loaded, and read by
+ * assisitve devices.
+ *
+ * @param icon
+ * the icon to be shown with the component's caption.
+ * @param iconAltText
+ * String to use as alt text
+ */
+ public void setIcon(Resource icon, String iconAltText) {
+ super.setIcon(icon);
+ getState().iconAltText = iconAltText == null ? "" : iconAltText;
+ }
+
+ /**
+ * Returns the icon's alt text.
+ *
+ * @return String with the alt text
+ */
+ public String getIconAlternateText() {
+ return getState().iconAltText;
+ }
+
+ public void setIconAlternateText(String iconAltText) {
+ getState().iconAltText = iconAltText;
+ }
+
+ /**
* Set whether the caption text is rendered as HTML or not. You might need
* to retheme button to allow higher content than the original text style.
*
diff --git a/server/src/com/vaadin/ui/Calendar.java b/server/src/com/vaadin/ui/Calendar.java
new file mode 100644
index 0000000000..38fa355dd8
--- /dev/null
+++ b/server/src/com/vaadin/ui/Calendar.java
@@ -0,0 +1,1845 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui;
+
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.EventListener;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TimeZone;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.event.Action;
+import com.vaadin.event.Action.Handler;
+import com.vaadin.event.dd.DropHandler;
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.TargetDetails;
+import com.vaadin.server.KeyMapper;
+import com.vaadin.shared.ui.calendar.CalendarEventId;
+import com.vaadin.shared.ui.calendar.CalendarServerRpc;
+import com.vaadin.shared.ui.calendar.CalendarState;
+import com.vaadin.shared.ui.calendar.DateConstants;
+import com.vaadin.ui.components.calendar.CalendarComponentEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.RangeSelectEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.RangeSelectHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClickHandler;
+import com.vaadin.ui.components.calendar.CalendarDateRange;
+import com.vaadin.ui.components.calendar.CalendarTargetDetails;
+import com.vaadin.ui.components.calendar.ContainerEventProvider;
+import com.vaadin.ui.components.calendar.event.BasicEventProvider;
+import com.vaadin.ui.components.calendar.event.CalendarEditableEventProvider;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeListener;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider;
+import com.vaadin.ui.components.calendar.handler.BasicBackwardHandler;
+import com.vaadin.ui.components.calendar.handler.BasicDateClickHandler;
+import com.vaadin.ui.components.calendar.handler.BasicEventMoveHandler;
+import com.vaadin.ui.components.calendar.handler.BasicEventResizeHandler;
+import com.vaadin.ui.components.calendar.handler.BasicForwardHandler;
+import com.vaadin.ui.components.calendar.handler.BasicWeekClickHandler;
+
+/**
+ * <p>
+ * Vaadin Calendar is for visualizing events in a calendar. Calendar events can
+ * be visualized in the variable length view depending on the start and end
+ * dates.
+ * </p>
+ *
+ * <li>You can set the viewable date range with the {@link #setStartDate(Date)}
+ * and {@link #setEndDate(Date)} methods. Calendar has a default date range of
+ * one week</li>
+ *
+ * <li>Calendar has two kind of views: monthly and weekly view</li>
+ *
+ * <li>If date range is seven days or shorter, the weekly view is used.</li>
+ *
+ * <li>Calendar queries its events by using a
+ * {@link com.vaadin.addon.calendar.event.CalendarEventProvider
+ * CalendarEventProvider}. By default, a
+ * {@link com.vaadin.addon.calendar.event.BasicEventProvider BasicEventProvider}
+ * is used.</li>
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class Calendar extends AbstractComponent implements
+ CalendarComponentEvents.NavigationNotifier,
+ CalendarComponentEvents.EventMoveNotifier,
+ CalendarComponentEvents.RangeSelectNotifier,
+ CalendarComponentEvents.EventResizeNotifier,
+ CalendarEventProvider.EventSetChangeListener, DropTarget,
+ CalendarEditableEventProvider, Action.Container {
+
+ /**
+ * Calendar can use either 12 hours clock or 24 hours clock.
+ */
+ public enum TimeFormat {
+
+ Format12H(), Format24H();
+ }
+
+ /** Defines currently active format for time. 12H/24H. */
+ protected TimeFormat currentTimeFormat;
+
+ /** Internal calendar data source. */
+ protected java.util.Calendar currentCalendar = java.util.Calendar
+ .getInstance();
+
+ /** Defines the component's active time zone. */
+ protected TimeZone timezone;
+
+ /** Defines the calendar's date range starting point. */
+ protected Date startDate = null;
+
+ /** Defines the calendar's date range ending point. */
+ protected Date endDate = null;
+
+ /** Event provider. */
+ private CalendarEventProvider calendarEventProvider;
+
+ /**
+ * Internal buffer for the events that are retrieved from the event
+ * provider.
+ */
+ protected List<CalendarEvent> events;
+
+ /** Date format that will be used in the UIDL for dates. */
+ protected DateFormat df_date = new SimpleDateFormat("yyyy-MM-dd");
+
+ /** Time format that will be used in the UIDL for time. */
+ protected DateFormat df_time = new SimpleDateFormat("HH:mm:ss");
+
+ /** Date format that will be used in the UIDL for both date and time. */
+ protected DateFormat df_date_time = new SimpleDateFormat(
+ DateConstants.CLIENT_DATE_FORMAT + "-"
+ + DateConstants.CLIENT_TIME_FORMAT);
+
+ /**
+ * Week view's scroll position. Client sends updates to this value so that
+ * scroll position wont reset all the time.
+ */
+ private int scrollTop = 0;
+
+ /** Caption format for the weekly view */
+ private String weeklyCaptionFormat = null;
+
+ /** Map from event ids to event handlers */
+ private final Map<String, EventListener> handlers;
+
+ /**
+ * Drop Handler for Vaadin DD. By default null.
+ */
+ private DropHandler dropHandler;
+
+ /**
+ * First day to show for a week
+ */
+ private int firstDay = 1;
+
+ /**
+ * Last day to show for a week
+ */
+ private int lastDay = 7;
+
+ /**
+ * First hour to show for a day
+ */
+ private int firstHour = 0;
+
+ /**
+ * Last hour to show for a day
+ */
+ private int lastHour = 23;
+
+ /**
+ * List of action handlers.
+ */
+ private LinkedList<Action.Handler> actionHandlers = null;
+
+ /**
+ * Action mapper.
+ */
+ private KeyMapper<Action> actionMapper = null;
+
+ /**
+ *
+ */
+ private CalendarServerRpcImpl rpc = new CalendarServerRpcImpl();
+
+ /**
+ * Returns the logger for the calendar
+ */
+ protected Logger getLogger() {
+ return Logger.getLogger(Calendar.class.getName());
+ }
+
+ /**
+ * Construct a Vaadin Calendar with a BasicEventProvider and no caption.
+ * Default date range is one week.
+ */
+ public Calendar() {
+ this(null, new BasicEventProvider());
+ }
+
+ /**
+ * Construct a Vaadin Calendar with a BasicEventProvider and the provided
+ * caption. Default date range is one week.
+ *
+ * @param caption
+ */
+ public Calendar(String caption) {
+ this(caption, new BasicEventProvider());
+ }
+
+ /**
+ * <p>
+ * Construct a Vaadin Calendar with event provider. Event provider is
+ * obligatory, because calendar component will query active events through
+ * it.
+ * </p>
+ *
+ * <p>
+ * By default, Vaadin Calendar will show dates from the start of the current
+ * week to the end of the current week. Use {@link #setStartDate(Date)} and
+ * {@link #setEndDate(Date)} to change this.
+ * </p>
+ *
+ * @param eventProvider
+ * Event provider, cannot be null.
+ */
+ public Calendar(CalendarEventProvider eventProvider) {
+ this(null, eventProvider);
+ }
+
+ /**
+ * <p>
+ * Construct a Vaadin Calendar with event provider and a caption. Event
+ * provider is obligatory, because calendar component will query active
+ * events through it.
+ * </p>
+ *
+ * <p>
+ * By default, Vaadin Calendar will show dates from the start of the current
+ * week to the end of the current week. Use {@link #setStartDate(Date)} and
+ * {@link #setEndDate(Date)} to change this.
+ * </p>
+ *
+ * @param eventProvider
+ * Event provider, cannot be null.
+ */
+ // this is the constructor every other constructor calls
+ public Calendar(String caption, CalendarEventProvider eventProvider) {
+ registerRpc(rpc);
+ setCaption(caption);
+ handlers = new HashMap<String, EventListener>();
+ setDefaultHandlers();
+ currentCalendar.setTime(new Date());
+ setEventProvider(eventProvider);
+ getState().firstDayOfWeek = firstDay;
+ getState().lastVisibleDayOfWeek = lastDay;
+ getState().firstHourOfDay = firstHour;
+ getState().lastHourOfDay = lastHour;
+ setTimeFormat(null);
+
+ }
+
+ @Override
+ public CalendarState getState() {
+ return (CalendarState) super.getState();
+ }
+
+ @Override
+ public void beforeClientResponse(boolean initial) {
+ super.beforeClientResponse(initial);
+
+ initCalendarWithLocale();
+
+ getState().format24H = TimeFormat.Format24H == getTimeFormat();
+ setupDaysAndActions();
+ setupCalendarEvents();
+ rpc.scroll(scrollTop);
+ }
+
+ /**
+ * Set all the wanted default handlers here. This is always called after
+ * constructing this object. All other events have default handlers except
+ * range and event click.
+ */
+ protected void setDefaultHandlers() {
+ setHandler(new BasicBackwardHandler());
+ setHandler(new BasicForwardHandler());
+ setHandler(new BasicWeekClickHandler());
+ setHandler(new BasicDateClickHandler());
+ setHandler(new BasicEventMoveHandler());
+ setHandler(new BasicEventResizeHandler());
+ }
+
+ /**
+ * Gets the calendar's start date.
+ *
+ * @return First visible date.
+ */
+ public Date getStartDate() {
+ if (startDate == null) {
+ currentCalendar.set(java.util.Calendar.DAY_OF_WEEK,
+ currentCalendar.getFirstDayOfWeek());
+ return currentCalendar.getTime();
+ }
+ return startDate;
+ }
+
+ /**
+ * Sets start date for the calendar. This and {@link #setEndDate(Date)}
+ * control the range of dates visible on the component. The default range is
+ * one week.
+ *
+ * @param date
+ * First visible date to show.
+ */
+ public void setStartDate(Date date) {
+ if (!date.equals(startDate)) {
+ startDate = date;
+ markAsDirty();
+ }
+ }
+
+ /**
+ * Gets the calendar's end date.
+ *
+ * @return Last visible date.
+ */
+ public Date getEndDate() {
+ if (endDate == null) {
+ currentCalendar.set(java.util.Calendar.DAY_OF_WEEK,
+ currentCalendar.getFirstDayOfWeek() + 6);
+ return currentCalendar.getTime();
+ }
+ return endDate;
+ }
+
+ /**
+ * Sets end date for the calendar. Starting from startDate, only six weeks
+ * will be shown if duration to endDate is longer than six weeks.
+ *
+ * This and {@link #setStartDate(Date)} control the range of dates visible
+ * on the component. The default range is one week.
+ *
+ * @param date
+ * Last visible date to show.
+ */
+ public void setEndDate(Date date) {
+ if (startDate != null && startDate.after(date)) {
+ startDate = (Date) date.clone();
+ markAsDirty();
+ } else if (!date.equals(endDate)) {
+ endDate = date;
+ markAsDirty();
+ }
+ }
+
+ /**
+ * Sets the locale to be used in the Calendar component.
+ *
+ * @see com.vaadin.ui.AbstractComponent#setLocale(java.util.Locale)
+ */
+ @Override
+ public void setLocale(Locale newLocale) {
+ super.setLocale(newLocale);
+ initCalendarWithLocale();
+ }
+
+ /**
+ * Initialize the java calendar instance with the current locale and
+ * timezone.
+ */
+ private void initCalendarWithLocale() {
+ if (timezone != null) {
+ currentCalendar = java.util.Calendar.getInstance(timezone,
+ getLocale());
+
+ } else {
+ currentCalendar = java.util.Calendar.getInstance(getLocale());
+ }
+ }
+
+ private void setupCalendarEvents() {
+ int durationInDays = (int) (((endDate.getTime()) - startDate.getTime()) / DateConstants.DAYINMILLIS);
+ durationInDays++;
+ if (durationInDays > 60) {
+ throw new RuntimeException("Daterange is too big (max 60) = "
+ + durationInDays);
+ }
+
+ Date firstDateToShow = expandStartDate(startDate, durationInDays > 7);
+ Date lastDateToShow = expandEndDate(endDate, durationInDays > 7);
+
+ currentCalendar.setTime(firstDateToShow);
+ events = getEventProvider().getEvents(firstDateToShow, lastDateToShow);
+
+ List<CalendarState.Event> calendarStateEvents = new ArrayList<CalendarState.Event>();
+ if (events != null) {
+ for (int i = 0; i < events.size(); i++) {
+ CalendarEvent e = events.get(i);
+ CalendarState.Event event = new CalendarState.Event();
+ event.index = i;
+ event.caption = e.getCaption() == null ? "" : e.getCaption();
+ event.dateFrom = df_date.format(e.getStart());
+ event.dateTo = df_date.format(e.getEnd());
+ event.timeFrom = df_time.format(e.getStart());
+ event.timeTo = df_time.format(e.getEnd());
+ event.description = e.getDescription() == null ? "" : e
+ .getDescription();
+ event.styleName = e.getStyleName() == null ? "" : e
+ .getStyleName();
+ event.allDay = e.isAllDay();
+ calendarStateEvents.add(event);
+ }
+ }
+ getState().events = calendarStateEvents;
+ }
+
+ private void setupDaysAndActions() {
+ // Make sure we have a up-to-date locale
+ initCalendarWithLocale();
+
+ CalendarState state = getState();
+
+ state.firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
+
+ // If only one is null, throw exception
+ // If both are null, set defaults
+ if (startDate == null ^ endDate == null) {
+ String message = "Schedule cannot be painted without a proper date range.\n";
+ if (startDate == null) {
+ throw new IllegalStateException(message
+ + "You must set a start date using setStartDate(Date).");
+
+ } else {
+ throw new IllegalStateException(message
+ + "You must set an end date using setEndDate(Date).");
+ }
+
+ } else if (startDate == null && endDate == null) {
+ // set defaults
+ startDate = getStartDate();
+ endDate = getEndDate();
+ }
+
+ int durationInDays = (int) (((endDate.getTime()) - startDate.getTime()) / DateConstants.DAYINMILLIS);
+ durationInDays++;
+ if (durationInDays > 60) {
+ throw new RuntimeException("Daterange is too big (max 60) = "
+ + durationInDays);
+ }
+
+ state.dayNames = getDayNamesShort();
+ state.monthNames = getMonthNamesShort();
+
+ // Use same timezone in all dates this component handles.
+ // Show "now"-marker in browser within given timezone.
+ Date now = new Date();
+ currentCalendar.setTime(now);
+ now = currentCalendar.getTime();
+
+ // Reset time zones for custom date formats
+ df_date.setTimeZone(currentCalendar.getTimeZone());
+ df_time.setTimeZone(currentCalendar.getTimeZone());
+
+ state.now = (df_date.format(now) + " " + df_time.format(now));
+
+ Date firstDateToShow = expandStartDate(startDate, durationInDays > 7);
+ Date lastDateToShow = expandEndDate(endDate, durationInDays > 7);
+
+ currentCalendar.setTime(firstDateToShow);
+
+ DateFormat weeklyCaptionFormatter = getWeeklyCaptionFormatter();
+ weeklyCaptionFormatter.setTimeZone(currentCalendar.getTimeZone());
+
+ Map<CalendarDateRange, Set<Action>> actionMap = new HashMap<CalendarDateRange, Set<Action>>();
+
+ List<CalendarState.Day> days = new ArrayList<CalendarState.Day>();
+
+ // Send all dates to client from server. This
+ // approach was taken because gwt doesn't
+ // support date localization properly.
+ while (currentCalendar.getTime().compareTo(lastDateToShow) < 1) {
+ final Date date = currentCalendar.getTime();
+ final CalendarState.Day day = new CalendarState.Day();
+ day.date = df_date.format(date);
+ day.localizedDateFormat = weeklyCaptionFormatter.format(date);
+ day.dayOfWeek = getDowByLocale(currentCalendar);
+ day.week = currentCalendar.get(java.util.Calendar.WEEK_OF_YEAR);
+
+ days.add(day);
+
+ // Get actions for a specific date
+ if (actionHandlers != null) {
+ for (Action.Handler actionHandler : actionHandlers) {
+
+ // Create calendar which omits time
+ GregorianCalendar cal = new GregorianCalendar(
+ getTimeZone(), getLocale());
+ cal.clear();
+ cal.set(currentCalendar.get(java.util.Calendar.YEAR),
+ currentCalendar.get(java.util.Calendar.MONTH),
+ currentCalendar.get(java.util.Calendar.DATE));
+
+ // Get day start and end times
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.DATE, 1);
+ Date end = cal.getTime();
+
+ boolean monthView = (durationInDays > 7);
+
+ /**
+ * If in day or week view add actions for each half-an-hour.
+ * If in month view add actions for each day
+ */
+ if (monthView) {
+ setActionsForDay(actionMap, start, end, actionHandler);
+ } else {
+ setActionsForEachHalfHour(actionMap, start, end,
+ actionHandler);
+ }
+
+ }
+ }
+
+ currentCalendar.add(java.util.Calendar.DATE, 1);
+ }
+ state.days = days;
+ state.actions = createActionsList(actionMap);
+ }
+
+ private void setActionsForEachHalfHour(
+ Map<CalendarDateRange, Set<Action>> actionMap, Date start,
+ Date end, Action.Handler actionHandler) {
+ GregorianCalendar cal = new GregorianCalendar(getTimeZone(),
+ getLocale());
+ cal.setTime(start);
+ while (cal.getTime().before(end)) {
+ Date s = cal.getTime();
+ cal.add(java.util.Calendar.MINUTE, 30);
+ Date e = cal.getTime();
+ CalendarDateRange range = new CalendarDateRange(s, e, getTimeZone());
+ Action[] actions = actionHandler.getActions(range, this);
+ if (actions != null) {
+ Set<Action> actionSet = new HashSet<Action>(
+ Arrays.asList(actions));
+ actionMap.put(range, actionSet);
+ }
+ }
+ }
+
+ private void setActionsForDay(
+ Map<CalendarDateRange, Set<Action>> actionMap, Date start,
+ Date end, Action.Handler actionHandler) {
+ CalendarDateRange range = new CalendarDateRange(start, end,
+ getTimeZone());
+ Action[] actions = actionHandler.getActions(range, this);
+ if (actions != null) {
+ Set<Action> actionSet = new HashSet<Action>(Arrays.asList(actions));
+ actionMap.put(range, actionSet);
+ }
+ }
+
+ private List<CalendarState.Action> createActionsList(
+ Map<CalendarDateRange, Set<Action>> actionMap) {
+ if (actionMap.isEmpty()) {
+ return null;
+ }
+
+ List<CalendarState.Action> calendarActions = new ArrayList<CalendarState.Action>();
+
+ SimpleDateFormat formatter = new SimpleDateFormat(
+ DateConstants.ACTION_DATE_FORMAT_PATTERN);
+ formatter.setTimeZone(getTimeZone());
+
+ for (Entry<CalendarDateRange, Set<Action>> entry : actionMap.entrySet()) {
+ CalendarDateRange range = entry.getKey();
+ Set<Action> actions = entry.getValue();
+ for (Action action : actions) {
+ String key = actionMapper.key(action);
+ CalendarState.Action calendarAction = new CalendarState.Action();
+ calendarAction.actionKey = key;
+ calendarAction.caption = action.getCaption();
+ setResource(key, action.getIcon());
+ calendarAction.iconKey = key;
+ calendarAction.startDate = formatter.format(range.getStart());
+ calendarAction.endDate = formatter.format(range.getEnd());
+ calendarActions.add(calendarAction);
+ }
+ }
+
+ return calendarActions;
+ }
+
+ /**
+ * Gets currently active time format. Value is either TimeFormat.Format12H
+ * or TimeFormat.Format24H.
+ *
+ * @return TimeFormat Format for the time.
+ */
+ public TimeFormat getTimeFormat() {
+ if (currentTimeFormat == null) {
+ SimpleDateFormat f = (SimpleDateFormat) SimpleDateFormat
+ .getTimeInstance(SimpleDateFormat.SHORT, getLocale());
+ String p = f.toPattern();
+ if (p.indexOf("HH") != -1 || p.indexOf("H") != -1) {
+ return TimeFormat.Format24H;
+ }
+ return TimeFormat.Format12H;
+ }
+ return currentTimeFormat;
+ }
+
+ /**
+ * Example: <code>setTimeFormat(TimeFormat.Format12H);</code></br> Set to
+ * null, if you want the format being defined by the locale.
+ *
+ * @param format
+ * Set 12h or 24h format. Default is defined by the locale.
+ */
+ public void setTimeFormat(TimeFormat format) {
+ currentTimeFormat = format;
+ markAsDirty();
+ }
+
+ /**
+ * Returns a time zone that is currently used by this component.
+ *
+ * @return Component's Time zone
+ */
+ public TimeZone getTimeZone() {
+ if (timezone == null) {
+ return currentCalendar.getTimeZone();
+ }
+ return timezone;
+ }
+
+ /**
+ * Set time zone that this component will use. Null value sets the default
+ * time zone.
+ *
+ * @param zone
+ * Time zone to use
+ */
+ public void setTimeZone(TimeZone zone) {
+ timezone = zone;
+ if (!currentCalendar.getTimeZone().equals(zone)) {
+ if (zone == null) {
+ zone = TimeZone.getDefault();
+ }
+ currentCalendar.setTimeZone(zone);
+ df_date_time.setTimeZone(zone);
+ markAsDirty();
+ }
+ }
+
+ /**
+ * Get the internally used Calendar instance. This is the currently used
+ * instance of {@link java.util.Calendar} but is bound to change during the
+ * lifetime of the component.
+ *
+ * @return the currently used java calendar
+ */
+ public java.util.Calendar getInternalCalendar() {
+ return currentCalendar;
+ }
+
+ /**
+ * <p>
+ * This method restricts the weekdays that are shown. This affects both the
+ * monthly and the weekly view. The general contract is that <b>firstDay <
+ * lastDay</b>.
+ * </p>
+ *
+ * <p>
+ * Note that this only affects the rendering process. Events are still
+ * requested by the dates set by {@link #setStartDate(Date)} and
+ * {@link #setEndDate(Date)}.
+ * </p>
+ *
+ * @param firstDay
+ * the first day of the week to show, between 1 and 7
+ */
+ public void setFirstVisibleDayOfWeek(int firstDay) {
+ if (this.firstDay != firstDay && firstDay >= 1 && firstDay <= 7
+ && getLastVisibleDayOfWeek() >= firstDay) {
+ this.firstDay = firstDay;
+ getState().firstVisibleDayOfWeek = firstDay;
+ }
+ }
+
+ /**
+ * Get the first visible day of the week. Returns the weekdays as integers
+ * represented by {@link java.util.Calendar#DAY_OF_WEEK}
+ *
+ * @return An integer representing the week day according to
+ * {@link java.util.Calendar#DAY_OF_WEEK}
+ */
+ public int getFirstVisibleDayOfWeek() {
+ return firstDay;
+ }
+
+ /**
+ * <p>
+ * This method restricts the weekdays that are shown. This affects both the
+ * monthly and the weekly view. The general contract is that <b>firstDay <
+ * lastDay</b>.
+ * </p>
+ *
+ * <p>
+ * Note that this only affects the rendering process. Events are still
+ * requested by the dates set by {@link #setStartDate(Date)} and
+ * {@link #setEndDate(Date)}.
+ * </p>
+ *
+ * @param lastDay
+ * the first day of the week to show, between 1 and 7
+ */
+ public void setLastVisibleDayOfWeek(int lastDay) {
+ if (this.lastDay != lastDay && lastDay >= 1 && lastDay <= 7
+ && getFirstVisibleDayOfWeek() <= lastDay) {
+ this.lastDay = lastDay;
+ getState().lastVisibleDayOfWeek = lastDay;
+ }
+ }
+
+ /**
+ * Get the last visible day of the week. Returns the weekdays as integers
+ * represented by {@link java.util.Calendar#DAY_OF_WEEK}
+ *
+ * @return An integer representing the week day according to
+ * {@link java.util.Calendar#DAY_OF_WEEK}
+ */
+ public int getLastVisibleDayOfWeek() {
+ return lastDay;
+ }
+
+ /**
+ * <p>
+ * This method restricts the hours that are shown per day. This affects the
+ * weekly view. The general contract is that <b>firstHour < lastHour</b>.
+ * </p>
+ *
+ * <p>
+ * Note that this only affects the rendering process. Events are still
+ * requested by the dates set by {@link #setStartDate(Date)} and
+ * {@link #setEndDate(Date)}.
+ * </p>
+ *
+ * @param firstHour
+ * the first hour of the day to show, between 0 and 23
+ */
+ public void setFirstVisibleHourOfDay(int firstHour) {
+ if (this.firstHour != firstHour && firstHour >= 0 && firstHour <= 23
+ && firstHour <= getLastVisibleHourOfDay()) {
+ this.firstHour = firstHour;
+ getState().firstHourOfDay = firstHour;
+ }
+ }
+
+ /**
+ * Returns the first visible hour in the week view. Returns the hour using a
+ * 24h time format
+ *
+ */
+ public int getFirstVisibleHourOfDay() {
+ return firstHour;
+ }
+
+ /**
+ * <p>
+ * This method restricts the hours that are shown per day. This affects the
+ * weekly view. The general contract is that <b>firstHour < lastHour</b>.
+ * </p>
+ *
+ * <p>
+ * Note that this only affects the rendering process. Events are still
+ * requested by the dates set by {@link #setStartDate(Date)} and
+ * {@link #setEndDate(Date)}.
+ * </p>
+ *
+ * @param lastHour
+ * the first hour of the day to show, between 0 and 23
+ */
+ public void setLastVisibleHourOfDay(int lastHour) {
+ if (this.lastHour != lastHour && lastHour >= 0 && lastHour <= 23
+ && lastHour >= getFirstVisibleHourOfDay()) {
+ this.lastHour = lastHour;
+ getState().lastHourOfDay = lastHour;
+ }
+ }
+
+ /**
+ * Returns the last visible hour in the week view. Returns the hour using a
+ * 24h time format
+ *
+ */
+ public int getLastVisibleHourOfDay() {
+ return lastHour;
+ }
+
+ /**
+ * Gets the date caption format for the weekly view.
+ *
+ * @return The pattern used in caption of dates in weekly view.
+ */
+ public String getWeeklyCaptionFormat() {
+ return weeklyCaptionFormat;
+ }
+
+ /**
+ * Sets custom date format for the weekly view. This is the caption of the
+ * date. Format could be like "mmm MM/dd".
+ *
+ * @param dateFormatPattern
+ * The date caption pattern.
+ */
+ public void setWeeklyCaptionFormat(String dateFormatPattern) {
+ if ((weeklyCaptionFormat == null && dateFormatPattern != null)
+ || (weeklyCaptionFormat != null && !weeklyCaptionFormat
+ .equals(dateFormatPattern))) {
+ weeklyCaptionFormat = dateFormatPattern;
+ markAsDirty();
+ }
+ }
+
+ private DateFormat getWeeklyCaptionFormatter() {
+ if (weeklyCaptionFormat != null) {
+ return new SimpleDateFormat(weeklyCaptionFormat, getLocale());
+ } else {
+ return SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT,
+ getLocale());
+ }
+ }
+
+ /**
+ * Get the day of week by the given calendar and its locale
+ *
+ * @param calendar
+ * The calendar to use
+ * @return
+ */
+ private static int getDowByLocale(java.util.Calendar calendar) {
+ int fow = calendar.get(java.util.Calendar.DAY_OF_WEEK);
+
+ // monday first
+ if (calendar.getFirstDayOfWeek() == java.util.Calendar.MONDAY) {
+ fow = (fow == java.util.Calendar.SUNDAY) ? 7 : fow - 1;
+ }
+
+ return fow;
+ }
+
+ /**
+ * Is the user allowed to trigger events which alters the events
+ *
+ * @return true if the client is allowed to send changes to server
+ * @see #isEventClickAllowed()
+ */
+ protected boolean isClientChangeAllowed() {
+ return !isReadOnly() && isEnabled();
+ }
+
+ /**
+ * Is the user allowed to trigger click events
+ *
+ * @return true if the client is allowed to click events
+ * @see #isClientChangeAllowed()
+ */
+ protected boolean isEventClickAllowed() {
+ return isEnabled();
+ }
+
+ /**
+ * Fires an event when the user selecing moving forward/backward in the
+ * calendar.
+ *
+ * @param forward
+ * True if the calendar moved forward else backward is assumed.
+ */
+ protected void fireNavigationEvent(boolean forward) {
+ if (forward) {
+ fireEvent(new ForwardEvent(this));
+ } else {
+ fireEvent(new BackwardEvent(this));
+ }
+ }
+
+ /**
+ * Fires an event move event to all server side move listerners
+ *
+ * @param index
+ * The index of the event in the events list
+ * @param newFromDatetime
+ * The changed from date time
+ */
+ protected void fireEventMove(int index, Date newFromDatetime) {
+ MoveEvent event = new MoveEvent(this, events.get(index),
+ newFromDatetime);
+
+ if (calendarEventProvider instanceof EventMoveHandler) {
+ // Notify event provider if it is an event move handler
+ ((EventMoveHandler) calendarEventProvider).eventMove(event);
+ }
+
+ // Notify event move handler attached by using the
+ // setHandler(EventMoveHandler) method
+ fireEvent(event);
+ }
+
+ /**
+ * Fires event when a week was clicked in the calendar.
+ *
+ * @param week
+ * The week that was clicked
+ * @param year
+ * The year of the week
+ */
+ protected void fireWeekClick(int week, int year) {
+ fireEvent(new WeekClick(this, week, year));
+ }
+
+ /**
+ * Fires event when a date was clicked in the calendar. Uses an existing
+ * event from the event cache.
+ *
+ * @param index
+ * The index of the event in the event cache.
+ */
+ protected void fireEventClick(Integer index) {
+ fireEvent(new EventClick(this, events.get(index)));
+ }
+
+ /**
+ * Fires event when a date was clicked in the calendar. Creates a new event
+ * for the date and passes it to the listener.
+ *
+ * @param date
+ * The date and time that was clicked
+ */
+ protected void fireDateClick(Date date) {
+ fireEvent(new DateClickEvent(this, date));
+ }
+
+ /**
+ * Fires an event range selected event. The event is fired when a user
+ * highlights an area in the calendar. The highlighted areas start and end
+ * dates are returned as arguments.
+ *
+ * @param from
+ * The start date and time of the highlighted area
+ * @param to
+ * The end date and time of the highlighted area
+ * @param monthlyMode
+ * Is the calendar in monthly mode
+ */
+ protected void fireRangeSelect(Date from, Date to, boolean monthlyMode) {
+ fireEvent(new RangeSelectEvent(this, from, to, monthlyMode));
+ }
+
+ /**
+ * Fires an event resize event. The event is fired when a user resizes the
+ * event in the calendar causing the time range of the event to increase or
+ * decrease. The new start and end times are returned as arguments to this
+ * method.
+ *
+ * @param index
+ * The index of the event in the event cache
+ * @param startTime
+ * The new start date and time of the event
+ * @param endTime
+ * The new end date and time of the event
+ */
+ protected void fireEventResize(int index, Date startTime, Date endTime) {
+ EventResize event = new EventResize(this, events.get(index), startTime,
+ endTime);
+
+ if (calendarEventProvider instanceof EventResizeHandler) {
+ // Notify event provider if it is an event resize handler
+ ((EventResizeHandler) calendarEventProvider).eventResize(event);
+ }
+
+ // Notify event resize handler attached by using the
+ // setHandler(EventMoveHandler) method
+ fireEvent(event);
+ }
+
+ /**
+ * Localized display names for week days starting from sunday. Returned
+ * array's length is always 7.
+ *
+ * @return Array of localized weekday names.
+ */
+ protected String[] getDayNamesShort() {
+ DateFormatSymbols s = new DateFormatSymbols(getLocale());
+ return Arrays.copyOfRange(s.getWeekdays(), 1, 8);
+ }
+
+ /**
+ * Localized display names for months starting from January. Returned
+ * array's length is always 12.
+ *
+ * @return Array of localized month names.
+ */
+ protected String[] getMonthNamesShort() {
+ DateFormatSymbols s = new DateFormatSymbols(getLocale());
+ return Arrays.copyOf(s.getShortMonths(), 12);
+ }
+
+ /**
+ * Gets a date that is first day in the week that target given date belongs
+ * to.
+ *
+ * @param date
+ * Target date
+ * @return Date that is first date in same week that given date is.
+ */
+ protected Date getFirstDateForWeek(Date date) {
+ int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
+ currentCalendar.setTime(date);
+ while (firstDayOfWeek != currentCalendar
+ .get(java.util.Calendar.DAY_OF_WEEK)) {
+ currentCalendar.add(java.util.Calendar.DATE, -1);
+ }
+ return currentCalendar.getTime();
+ }
+
+ /**
+ * Gets a date that is last day in the week that target given date belongs
+ * to.
+ *
+ * @param date
+ * Target date
+ * @return Date that is last date in same week that given date is.
+ */
+ protected Date getLastDateForWeek(Date date) {
+ currentCalendar.setTime(date);
+ currentCalendar.add(java.util.Calendar.DATE, 1);
+ int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
+ // Roll to weeks last day using firstdayofweek. Roll until FDofW is
+ // found and then roll back one day.
+ while (firstDayOfWeek != currentCalendar
+ .get(java.util.Calendar.DAY_OF_WEEK)) {
+ currentCalendar.add(java.util.Calendar.DATE, 1);
+ }
+ currentCalendar.add(java.util.Calendar.DATE, -1);
+ return currentCalendar.getTime();
+ }
+
+ /**
+ * Calculates the end time of the day using the given calendar and date
+ *
+ * @param date
+ * @param calendar
+ * the calendar instance to be used in the calculation. The given
+ * instance is unchanged in this operation.
+ * @return the given date, with time set to the end of the day
+ */
+ private static Date getEndOfDay(java.util.Calendar calendar, Date date) {
+ java.util.Calendar calendarClone = (java.util.Calendar) calendar
+ .clone();
+
+ calendarClone.setTime(date);
+ calendarClone.set(java.util.Calendar.MILLISECOND,
+ calendarClone.getActualMaximum(java.util.Calendar.MILLISECOND));
+ calendarClone.set(java.util.Calendar.SECOND,
+ calendarClone.getActualMaximum(java.util.Calendar.SECOND));
+ calendarClone.set(java.util.Calendar.MINUTE,
+ calendarClone.getActualMaximum(java.util.Calendar.MINUTE));
+ calendarClone.set(java.util.Calendar.HOUR,
+ calendarClone.getActualMaximum(java.util.Calendar.HOUR));
+ calendarClone.set(java.util.Calendar.HOUR_OF_DAY,
+ calendarClone.getActualMaximum(java.util.Calendar.HOUR_OF_DAY));
+
+ return calendarClone.getTime();
+ }
+
+ /**
+ * Calculates the end time of the day using the given calendar and date
+ *
+ * @param date
+ * @param calendar
+ * the calendar instance to be used in the calculation. The given
+ * instance is unchanged in this operation.
+ * @return the given date, with time set to the end of the day
+ */
+ private static Date getStartOfDay(java.util.Calendar calendar, Date date) {
+ java.util.Calendar calendarClone = (java.util.Calendar) calendar
+ .clone();
+
+ calendarClone.setTime(date);
+ calendarClone.set(java.util.Calendar.MILLISECOND, 0);
+ calendarClone.set(java.util.Calendar.SECOND, 0);
+ calendarClone.set(java.util.Calendar.MINUTE, 0);
+ calendarClone.set(java.util.Calendar.HOUR, 0);
+ calendarClone.set(java.util.Calendar.HOUR_OF_DAY, 0);
+
+ return calendarClone.getTime();
+ }
+
+ /**
+ * Finds the first day of the week and returns a day representing the start
+ * of that day
+ *
+ * @param start
+ * The actual date
+ * @param expandToFullWeek
+ * Should the returned date be moved to the start of the week
+ * @return If expandToFullWeek is set then it returns the first day of the
+ * week, else it returns a clone of the actual date with the time
+ * set to the start of the day
+ */
+ protected Date expandStartDate(Date start, boolean expandToFullWeek) {
+ // If the duration is more than week, use monthly view and get startweek
+ // and endweek. Example if views daterange is from tuesday to next weeks
+ // wednesday->expand to monday to nextweeks sunday. If firstdayofweek =
+ // monday
+ if (expandToFullWeek) {
+ start = getFirstDateForWeek(start);
+
+ } else {
+ start = (Date) start.clone();
+ }
+
+ // Always expand to the start of the first day to the end of the last
+ // day
+ start = getStartOfDay(currentCalendar, start);
+
+ return start;
+ }
+
+ /**
+ * Finds the last day of the week and returns a day representing the end of
+ * that day
+ *
+ * @param end
+ * The actual date
+ * @param expandToFullWeek
+ * Should the returned date be moved to the end of the week
+ * @return If expandToFullWeek is set then it returns the last day of the
+ * week, else it returns a clone of the actual date with the time
+ * set to the end of the day
+ */
+ protected Date expandEndDate(Date end, boolean expandToFullWeek) {
+ // If the duration is more than week, use monthly view and get startweek
+ // and endweek. Example if views daterange is from tuesday to next weeks
+ // wednesday->expand to monday to nextweeks sunday. If firstdayofweek =
+ // monday
+ if (expandToFullWeek) {
+ end = getLastDateForWeek(end);
+
+ } else {
+ end = (Date) end.clone();
+ }
+
+ // Always expand to the start of the first day to the end of the last
+ // day
+ end = getEndOfDay(currentCalendar, end);
+
+ return end;
+ }
+
+ /**
+ * Set the {@link com.vaadin.addon.calendar.event.CalendarEventProvider
+ * CalendarEventProvider} to be used with this calendar. The EventProvider
+ * is used to query for events to show, and must be non-null. By default a
+ * {@link com.vaadin.addon.calendar.event.BasicEventProvider
+ * BasicEventProvider} is used.
+ *
+ * @param calendarEventProvider
+ * the calendarEventProvider to set. Cannot be null.
+ */
+ public void setEventProvider(CalendarEventProvider calendarEventProvider) {
+ if (calendarEventProvider == null) {
+ throw new IllegalArgumentException(
+ "Calendar event provider cannot be null");
+ }
+
+ // remove old listener
+ if (getEventProvider() instanceof EventSetChangeNotifier) {
+ ((EventSetChangeNotifier) getEventProvider())
+ .removeEventSetChangeListener(this);
+ }
+
+ this.calendarEventProvider = calendarEventProvider;
+
+ // add new listener
+ if (calendarEventProvider instanceof EventSetChangeNotifier) {
+ ((EventSetChangeNotifier) calendarEventProvider)
+ .addEventSetChangeListener(this);
+ }
+ }
+
+ /**
+ * @return the {@link com.vaadin.addon.calendar.event.CalendarEventProvider
+ * CalendarEventProvider} currently used
+ */
+ public CalendarEventProvider getEventProvider() {
+ return calendarEventProvider;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarEvents.EventChangeListener#eventChange
+ * (com.vaadin.addon.calendar.ui.CalendarEvents.EventChange)
+ */
+ @Override
+ public void eventSetChange(EventSetChangeEvent changeEvent) {
+ // sanity check
+ if (calendarEventProvider == changeEvent.getProvider()) {
+ markAsDirty();
+ }
+ }
+
+ /**
+ * Set the handler for the given type information. Mirrors
+ * {@link #addListener(String, Class, Object, Method) addListener} from
+ * AbstractComponent
+ *
+ * @param eventId
+ * A unique id for the event. Usually one of
+ * {@link CalendarEventId}
+ * @param eventType
+ * The class of the event, most likely a subclass of
+ * {@link CalendarComponentEvent}
+ * @param listener
+ * A listener that listens to the given event
+ * @param listenerMethod
+ * The method on the lister to call when the event is triggered
+ */
+ protected void setHandler(String eventId, Class<?> eventType,
+ EventListener listener, Method listenerMethod) {
+ if (handlers.get(eventId) != null) {
+ removeListener(eventId, eventType, handlers.get(eventId));
+ handlers.remove(eventId);
+ }
+
+ if (listener != null) {
+ addListener(eventId, eventType, listener, listenerMethod);
+ handlers.put(eventId, listener);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardHandler)
+ */
+ @Override
+ public void setHandler(ForwardHandler listener) {
+ setHandler(ForwardEvent.EVENT_ID, ForwardEvent.class, listener,
+ ForwardHandler.forwardMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardHandler)
+ */
+ @Override
+ public void setHandler(BackwardHandler listener) {
+ setHandler(BackwardEvent.EVENT_ID, BackwardEvent.class, listener,
+ BackwardHandler.backwardMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickHandler)
+ */
+ @Override
+ public void setHandler(DateClickHandler listener) {
+ setHandler(DateClickEvent.EVENT_ID, DateClickEvent.class, listener,
+ DateClickHandler.dateClickMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventClickHandler)
+ */
+ @Override
+ public void setHandler(EventClickHandler listener) {
+ setHandler(EventClick.EVENT_ID, EventClick.class, listener,
+ EventClickHandler.eventClickMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClickHandler)
+ */
+ @Override
+ public void setHandler(WeekClickHandler listener) {
+ setHandler(WeekClick.EVENT_ID, WeekClick.class, listener,
+ WeekClickHandler.weekClickMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler
+ * )
+ */
+ @Override
+ public void setHandler(EventResizeHandler listener) {
+ setHandler(EventResize.EVENT_ID, EventResize.class, listener,
+ EventResizeHandler.eventResizeMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectHandler
+ * )
+ */
+ @Override
+ public void setHandler(RangeSelectHandler listener) {
+ setHandler(RangeSelectEvent.EVENT_ID, RangeSelectEvent.class, listener,
+ RangeSelectHandler.rangeSelectMethod);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler)
+ */
+ @Override
+ public void setHandler(EventMoveHandler listener) {
+ setHandler(MoveEvent.EVENT_ID, MoveEvent.class, listener,
+ EventMoveHandler.eventMoveMethod);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.CalendarEventNotifier
+ * #getHandler(java.lang.String)
+ */
+ @Override
+ public EventListener getHandler(String eventId) {
+ return handlers.get(eventId);
+ }
+
+ /**
+ * Get the currently active drop handler
+ */
+ @Override
+ public DropHandler getDropHandler() {
+ return dropHandler;
+ }
+
+ /**
+ * Set the drop handler for the calendar See {@link DropHandler} for
+ * implementation details.
+ *
+ * @param dropHandler
+ * The drop handler to set
+ */
+ public void setDropHandler(DropHandler dropHandler) {
+ this.dropHandler = dropHandler;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.event.dd.DropTarget#translateDropTargetDetails(java.util.Map)
+ */
+ @Override
+ public TargetDetails translateDropTargetDetails(
+ Map<String, Object> clientVariables) {
+ Map<String, Object> serverVariables = new HashMap<String, Object>(1);
+
+ if (clientVariables.containsKey("dropSlotIndex")) {
+ int slotIndex = (Integer) clientVariables.get("dropSlotIndex");
+ int dayIndex = (Integer) clientVariables.get("dropDayIndex");
+
+ currentCalendar.setTime(getStartOfDay(currentCalendar, startDate));
+ currentCalendar.add(java.util.Calendar.DATE, dayIndex);
+
+ // change this if slot length is modified
+ currentCalendar.add(java.util.Calendar.MINUTE, slotIndex * 30);
+
+ serverVariables.put("dropTime", currentCalendar.getTime());
+
+ } else {
+ int dayIndex = (Integer) clientVariables.get("dropDayIndex");
+ currentCalendar.setTime(expandStartDate(startDate, true));
+ currentCalendar.add(java.util.Calendar.DATE, dayIndex);
+ serverVariables.put("dropDay", currentCalendar.getTime());
+ }
+
+ CalendarTargetDetails td = new CalendarTargetDetails(serverVariables,
+ this);
+ td.setHasDropTime(clientVariables.containsKey("dropSlotIndex"));
+
+ return td;
+ }
+
+ /**
+ * Sets a container as a data source for the events in the calendar.
+ * Equivalent for doing
+ * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code>
+ *
+ * Use this method if you are adding a container which uses the default
+ * property ids like {@link BeanItemContainer} for instance. If you are
+ * using custom properties instead use
+ * {@link Calendar#setContainerDataSource(com.vaadin.data.Container.Indexed, Object, Object, Object, Object, Object)}
+ *
+ * Please note that the container must be sorted by date!
+ *
+ * @param container
+ * The container to use as a datasource
+ */
+ public void setContainerDataSource(Container.Indexed container) {
+ ContainerEventProvider provider = new ContainerEventProvider(container);
+ provider.addEventSetChangeListener(new CalendarEventProvider.EventSetChangeListener() {
+ @Override
+ public void eventSetChange(EventSetChangeEvent changeEvent) {
+ // Repaint if events change
+ markAsDirty();
+ }
+ });
+ provider.addEventChangeListener(new EventChangeListener() {
+ @Override
+ public void eventChange(EventChangeEvent changeEvent) {
+ // Repaint if event changes
+ markAsDirty();
+ }
+ });
+ setEventProvider(provider);
+ }
+
+ /**
+ * Sets a container as a data source for the events in the calendar.
+ * Equivalent for doing
+ * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code>
+ *
+ * Please note that the container must be sorted by date!
+ *
+ * @param container
+ * The container to use as a data source
+ * @param captionProperty
+ * The property that has the caption, null if no caption property
+ * is present
+ * @param descriptionProperty
+ * The property that has the description, null if no description
+ * property is present
+ * @param startDateProperty
+ * The property that has the starting date
+ * @param endDateProperty
+ * The property that has the ending date
+ * @param styleNameProperty
+ * The property that has the stylename, null if no stylname
+ * property is present
+ */
+ public void setContainerDataSource(Container.Indexed container,
+ Object captionProperty, Object descriptionProperty,
+ Object startDateProperty, Object endDateProperty,
+ Object styleNameProperty) {
+ ContainerEventProvider provider = new ContainerEventProvider(container);
+ provider.setCaptionProperty(captionProperty);
+ provider.setDescriptionProperty(descriptionProperty);
+ provider.setStartDateProperty(startDateProperty);
+ provider.setEndDateProperty(endDateProperty);
+ provider.setStyleNameProperty(styleNameProperty);
+ provider.addEventSetChangeListener(new CalendarEventProvider.EventSetChangeListener() {
+ @Override
+ public void eventSetChange(EventSetChangeEvent changeEvent) {
+ // Repaint if events change
+ markAsDirty();
+ }
+ });
+ provider.addEventChangeListener(new EventChangeListener() {
+ @Override
+ public void eventChange(EventChangeEvent changeEvent) {
+ // Repaint if event changes
+ markAsDirty();
+ }
+ });
+ setEventProvider(provider);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java.
+ * util.Date, java.util.Date)
+ */
+ @Override
+ public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
+ return getEventProvider().getEvents(startDate, endDate);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent
+ * (com.vaadin.addon.calendar.event.CalendarEvent)
+ */
+ @Override
+ public void addEvent(CalendarEvent event) {
+ if (getEventProvider() instanceof CalendarEditableEventProvider) {
+ CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider();
+ provider.addEvent(event);
+ markAsDirty();
+ } else {
+ throw new UnsupportedOperationException(
+ "Event provider does not support adding events");
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent
+ * (com.vaadin.addon.calendar.event.CalendarEvent)
+ */
+ @Override
+ public void removeEvent(CalendarEvent event) {
+ if (getEventProvider() instanceof CalendarEditableEventProvider) {
+ CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider();
+ provider.removeEvent(event);
+ markAsDirty();
+ } else {
+ throw new UnsupportedOperationException(
+ "Event provider does not support removing events");
+ }
+ }
+
+ /**
+ * Adds an action handler to the calender that handles event produced by the
+ * context menu.
+ *
+ * <p>
+ * The {@link Handler#getActions(Object, Object)} parameters depend on what
+ * view the Calendar is in:
+ * <ul>
+ * <li>If the Calendar is in <i>Day or Week View</i> then the target
+ * parameter will be a {@link CalendarDateRange} with a range of
+ * half-an-hour. The {@link Handler#getActions(Object, Object)} method will
+ * be called once per half-hour slot.</li>
+ * <li>If the Calendar is in <i>Month View</i> then the target parameter
+ * will be a {@link CalendarDateRange} with a range of one day. The
+ * {@link Handler#getActions(Object, Object)} will be called once for each
+ * day.
+ * </ul>
+ * The Dates passed into the {@link CalendarDateRange} are in the same
+ * timezone as the calendar is.
+ * </p>
+ *
+ * <p>
+ * The {@link Handler#handleAction(Action, Object, Object)} parameters
+ * depend on what the context menu is called upon:
+ * <ul>
+ * <li>If the context menu is called upon an event then the target parameter
+ * is the event, i.e. instanceof {@link CalendarEvent}</li>
+ * <li>If the context menu is called upon an empty slot then the target is a
+ * {@link Date} representing that slot
+ * </ul>
+ * </p>
+ */
+ @Override
+ public void addActionHandler(Handler actionHandler) {
+ if (actionHandler != null) {
+ if (actionHandlers == null) {
+ actionHandlers = new LinkedList<Action.Handler>();
+ actionMapper = new KeyMapper<Action>();
+ }
+ if (!actionHandlers.contains(actionHandler)) {
+ actionHandlers.add(actionHandler);
+ markAsDirty();
+ }
+ }
+ }
+
+ /**
+ * Is the calendar in a mode where all days of the month is shown
+ *
+ * @return Returns true if calendar is in monthly mode and false if it is in
+ * weekly mode
+ */
+ public boolean isMonthlyMode() {
+ CalendarState state = (CalendarState) getState(false);
+ if (state.days != null) {
+ return state.days.size() > 7;
+ } else {
+ // Default mode
+ return true;
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.event.Action.Container#removeActionHandler(com.vaadin.event
+ * .Action.Handler)
+ */
+ @Override
+ public void removeActionHandler(Handler actionHandler) {
+ if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
+ actionHandlers.remove(actionHandler);
+ if (actionHandlers.isEmpty()) {
+ actionHandlers = null;
+ actionMapper = null;
+ }
+ markAsDirty();
+ }
+ }
+
+ private class CalendarServerRpcImpl implements CalendarServerRpc {
+
+ @Override
+ public void eventMove(int eventIndex, String newDate) {
+ if (!isClientChangeAllowed()) {
+ return;
+ }
+ if (newDate != null) {
+ try {
+ Date d = df_date_time.parse(newDate);
+ if (eventIndex >= 0 && eventIndex < events.size()
+ && events.get(eventIndex) != null) {
+ fireEventMove(eventIndex, d);
+ }
+ } catch (ParseException e) {
+ getLogger().log(Level.WARNING, e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public void rangeSelect(String range) {
+ if (!isClientChangeAllowed()) {
+ return;
+ }
+
+ if (range != null && range.length() > 14 && range.contains("TO")) {
+ String[] dates = range.split("TO");
+ try {
+ Date d1 = df_date.parse(dates[0]);
+ Date d2 = df_date.parse(dates[1]);
+
+ fireRangeSelect(d1, d2, true);
+
+ } catch (ParseException e) {
+ // NOP
+ }
+ } else if (range != null && range.length() > 12
+ && range.contains(":")) {
+ String[] dates = range.split(":");
+ if (dates.length == 3) {
+ try {
+ Date d = df_date.parse(dates[0]);
+ currentCalendar.setTime(d);
+ int startMinutes = Integer.parseInt(dates[1]);
+ int endMinutes = Integer.parseInt(dates[2]);
+ currentCalendar.add(java.util.Calendar.MINUTE,
+ startMinutes);
+ Date start = currentCalendar.getTime();
+ currentCalendar.add(java.util.Calendar.MINUTE,
+ endMinutes - startMinutes);
+ Date end = currentCalendar.getTime();
+ fireRangeSelect(start, end, false);
+ } catch (ParseException e) {
+ // NOP
+ } catch (NumberFormatException e) {
+ // NOP
+ }
+ }
+ }
+ }
+
+ @Override
+ public void forward() {
+ fireEvent(new ForwardEvent(Calendar.this));
+ }
+
+ @Override
+ public void backward() {
+ fireEvent(new BackwardEvent(Calendar.this));
+ }
+
+ @Override
+ public void dateClick(String date) {
+ if (!isClientChangeAllowed()) {
+ return;
+ }
+ if (date != null && date.length() > 6) {
+ try {
+ Date d = df_date.parse(date);
+ fireDateClick(d);
+ } catch (ParseException e) {
+ }
+ }
+ }
+
+ @Override
+ public void weekClick(String event) {
+ if (!isClientChangeAllowed()) {
+ return;
+ }
+ if (event.length() > 0 && event.contains("w")) {
+ String[] splitted = event.split("w");
+ if (splitted.length == 2) {
+ try {
+ int yr = 1900 + Integer.parseInt(splitted[0]);
+ int week = Integer.parseInt(splitted[1]);
+ fireWeekClick(week, yr);
+ } catch (NumberFormatException e) {
+ // NOP
+ }
+ }
+ }
+ }
+
+ @Override
+ public void eventClick(int eventIndex) {
+ if (!isEventClickAllowed()) {
+ return;
+ }
+ if (eventIndex >= 0 && eventIndex < events.size()
+ && events.get(eventIndex) != null) {
+ fireEventClick(eventIndex);
+ }
+ }
+
+ @Override
+ public void eventResize(int eventIndex, String newStartDate,
+ String newEndDate) {
+ if (!isClientChangeAllowed()) {
+ return;
+ }
+ if (newStartDate != null && !"".equals(newStartDate)
+ && newEndDate != null && !"".equals(newEndDate)) {
+ try {
+ Date newStartTime = df_date_time.parse(newStartDate);
+ Date newEndTime = df_date_time.parse(newEndDate);
+
+ fireEventResize(eventIndex, newStartTime, newEndTime);
+ } catch (ParseException e) {
+ // NOOP
+ }
+ }
+ }
+
+ @Override
+ public void scroll(int scrollPosition) {
+ scrollTop = scrollPosition;
+ markAsDirty();
+ }
+
+ @Override
+ public void actionOnEmptyCell(String actionKey, String startDate,
+ String endDate) {
+ Action action = actionMapper.get(actionKey);
+ SimpleDateFormat formatter = new SimpleDateFormat(
+ DateConstants.ACTION_DATE_FORMAT_PATTERN);
+ formatter.setTimeZone(getTimeZone());
+ try {
+ Date start = formatter.parse(startDate);
+ for (Action.Handler ah : actionHandlers) {
+ ah.handleAction(action, this, start);
+ }
+
+ } catch (ParseException e) {
+ getLogger().log(Level.WARNING,
+ "Could not parse action date string");
+ }
+
+ }
+
+ @Override
+ public void actionOnEvent(String actionKey, String startDate,
+ String endDate, int eventIndex) {
+ Action action = actionMapper.get(actionKey);
+ SimpleDateFormat formatter = new SimpleDateFormat(
+ DateConstants.ACTION_DATE_FORMAT_PATTERN);
+ formatter.setTimeZone(getTimeZone());
+ for (Action.Handler ah : actionHandlers) {
+ ah.handleAction(action, this, events.get(eventIndex));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index a229003224..85cdcdf65c 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -17,6 +17,7 @@ package com.vaadin.ui;
import java.io.IOException;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -31,9 +32,9 @@ import org.json.JSONException;
import org.json.JSONObject;
import com.vaadin.server.AbstractClientConnector;
-import com.vaadin.server.AbstractCommunicationManager;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.GlobalResourceHandler;
+import com.vaadin.server.LegacyCommunicationManager;
import com.vaadin.server.StreamVariable;
/**
@@ -295,7 +296,7 @@ public class ConnectorTracker implements Serializable {
uninitializedConnectors.remove(connector);
diffStates.remove(connector);
iterator.remove();
- } else if (!AbstractCommunicationManager
+ } else if (!LegacyCommunicationManager
.isConnectorVisibleToClient(connector)
&& !uninitializedConnectors.contains(connector)) {
uninitializedConnectors.add(connector);
@@ -463,6 +464,31 @@ public class ConnectorTracker implements Serializable {
return dirtyConnectors;
}
+ /**
+ * Checks if there a dirty connectors.
+ *
+ * @return true if there are dirty connectors, false otherwise
+ */
+ public boolean hasDirtyConnectors() {
+ return !getDirtyConnectors().isEmpty();
+ }
+
+ /**
+ * Returns a collection of those {@link #getDirtyConnectors() dirty
+ * connectors} that are actually visible to the client.
+ *
+ * @return A list of dirty and visible connectors.
+ */
+ public ArrayList<ClientConnector> getDirtyVisibleConnectors() {
+ ArrayList<ClientConnector> dirtyConnectors = new ArrayList<ClientConnector>();
+ for (ClientConnector c : getDirtyConnectors()) {
+ if (LegacyCommunicationManager.isConnectorVisibleToClient(c)) {
+ dirtyConnectors.add(c);
+ }
+ }
+ return dirtyConnectors;
+ }
+
public JSONObject getDiffState(ClientConnector connector) {
assert getConnector(connector.getConnectorId()) == connector;
return diffStates.get(connector);
diff --git a/server/src/com/vaadin/ui/DateField.java b/server/src/com/vaadin/ui/DateField.java
index 1a8955801b..5017fac993 100644
--- a/server/src/com/vaadin/ui/DateField.java
+++ b/server/src/com/vaadin/ui/DateField.java
@@ -19,10 +19,8 @@ package com.vaadin.ui;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
-import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
-import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
@@ -31,6 +29,7 @@ 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.data.validator.DateRangeValidator;
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
@@ -40,6 +39,7 @@ import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.shared.ui.datefield.DateFieldConstants;
import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.shared.ui.datefield.TextualDateFieldState;
/**
* <p>
@@ -148,6 +148,10 @@ public class DateField extends AbstractField<Date> implements
private TimeZone timeZone = null;
private static Map<Resolution, String> variableNameForResolution = new HashMap<Resolution, String>();
+
+ private String dateOutOfRangeMessage = "Date is out of allowed range";
+
+ private DateRangeValidator currentRangeValidator;
{
variableNameForResolution.put(Resolution.SECOND, "sec");
variableNameForResolution.put(Resolution.MINUTE, "min");
@@ -279,6 +283,174 @@ public class DateField extends AbstractField<Date> implements
return super.shouldHideErrors() && uiHasValidDateString;
}
+ @Override
+ protected TextualDateFieldState getState() {
+ return (TextualDateFieldState) super.getState();
+ }
+
+ @Override
+ protected TextualDateFieldState getState(boolean markAsDirty) {
+ return (TextualDateFieldState) super.getState(markAsDirty);
+ }
+
+ /**
+ * Sets the start range for this component. If the value is set before this
+ * date (taking the resolution into account), the component will not
+ * validate. If <code>startDate</code> is set to <code>null</code>, any
+ * value before <code>endDate</code> will be accepted by the range
+ *
+ * @param startDate
+ * - the allowed range's start date
+ */
+ public void setRangeStart(Date startDate) {
+ if (startDate != null && getState().rangeEnd != null
+ && startDate.after(getState().rangeEnd)) {
+ throw new IllegalStateException(
+ "startDate cannot be later than endDate");
+ }
+ getState().rangeStart = startDate;
+ // rangeStart = startDate;
+ // This has to be done to correct for the resolution
+ // updateRangeState();
+ updateRangeValidator();
+ }
+
+ /**
+ * Sets the current error message if the range validation fails.
+ *
+ * @param dateOutOfRangeMessage
+ * - Localizable message which is shown when value (the date) is
+ * set outside allowed range
+ */
+ public void setDateOutOfRangeMessage(String dateOutOfRangeMessage) {
+ this.dateOutOfRangeMessage = dateOutOfRangeMessage;
+ updateRangeValidator();
+ }
+
+ /**
+ * Gets the end range for a certain resolution. The range is inclusive, so
+ * if rangeEnd is set to zero milliseconds past year n and resolution is set
+ * to YEAR, any date in year n will be accepted. Resolutions lower than DAY
+ * will be interpreted on a DAY level. That is, everything below DATE is
+ * cleared
+ *
+ * @param forResolution
+ * - the range conforms to the resolution
+ * @return
+ */
+ private Date getRangeEnd(Resolution forResolution) {
+ // We need to set the correct resolution for the dates,
+ // otherwise the range validator will complain
+
+ Date rangeEnd = getState(false).rangeEnd;
+ if (rangeEnd == null) {
+ return null;
+ }
+
+ Calendar endCal = Calendar.getInstance();
+ endCal.setTime(rangeEnd);
+
+ if (forResolution == Resolution.YEAR) {
+ // Adding one year (minresolution) and clearing the rest.
+ endCal.set(endCal.get(Calendar.YEAR) + 1, 0, 1, 0, 0, 0);
+ } else if (forResolution == Resolution.MONTH) {
+ // Adding one month (minresolution) and clearing the rest.
+ endCal.set(endCal.get(Calendar.YEAR),
+ endCal.get(Calendar.MONTH) + 1, 1, 0, 0, 0);
+ } else {
+ endCal.set(endCal.get(Calendar.YEAR), endCal.get(Calendar.MONTH),
+ endCal.get(Calendar.DATE) + 1, 0, 0, 0);
+ }
+ // removing one millisecond will now get the endDate to return to
+ // current resolution's set time span (year or month)
+ endCal.set(Calendar.MILLISECOND, -1);
+ return endCal.getTime();
+ }
+
+ /**
+ * Gets the start range for a certain resolution. The range is inclusive, so
+ * if <code>rangeStart</code> is set to one millisecond before year n and
+ * resolution is set to YEAR, any date in year n - 1 will be accepted.
+ * Lowest supported resolution is DAY.
+ *
+ * @param forResolution
+ * - the range conforms to the resolution
+ * @return
+ */
+ private Date getRangeStart(Resolution forResolution) {
+ if (getState(false).rangeStart == null) {
+ return null;
+ }
+ Calendar startCal = Calendar.getInstance();
+ startCal.setTime(getState(false).rangeStart);
+
+ if (forResolution == Resolution.YEAR) {
+ startCal.set(startCal.get(Calendar.YEAR), 0, 1, 0, 0, 0);
+ } else if (forResolution == Resolution.MONTH) {
+ startCal.set(startCal.get(Calendar.YEAR),
+ startCal.get(Calendar.MONTH), 1, 0, 0, 0);
+ } else {
+ startCal.set(startCal.get(Calendar.YEAR),
+ startCal.get(Calendar.MONTH), startCal.get(Calendar.DATE),
+ 0, 0, 0);
+ }
+
+ startCal.set(Calendar.MILLISECOND, 0);
+ return startCal.getTime();
+ }
+
+ private void updateRangeValidator() {
+ if (currentRangeValidator != null) {
+ removeValidator(currentRangeValidator);
+ }
+
+ currentRangeValidator = new DateRangeValidator(dateOutOfRangeMessage,
+ getRangeStart(resolution), getRangeEnd(resolution), null);
+
+ addValidator(currentRangeValidator);
+
+ }
+
+ /**
+ * Sets the end range for this component. If the value is set after this
+ * date (taking the resolution into account), the component will not
+ * validate. If <code>endDate</code> is set to <code>null</code>, any value
+ * after <code>startDate</code> will be accepted by the range.
+ *
+ * @param endDate
+ * - the allowed range's end date (inclusive, based on the
+ * current resolution)
+ */
+ public void setRangeEnd(Date endDate) {
+ if (endDate != null && getState().rangeStart != null
+ && getState().rangeStart.after(endDate)) {
+ throw new IllegalStateException(
+ "endDate cannot be earlier than startDate");
+ }
+ // rangeEnd = endDate;
+ getState().rangeEnd = endDate;
+ updateRangeValidator();
+ }
+
+ /**
+ * Returns the precise rangeStart used.
+ *
+ * @param startDate
+ *
+ */
+ public Date getRangeStart() {
+ return getState(false).rangeStart;
+ }
+
+ /**
+ * Returns the precise rangeEnd used.
+ *
+ * @param startDate
+ */
+ public Date getRangeEnd() {
+ return getState(false).rangeEnd;
+ }
+
/*
* Invoked when a variable of the component changes. Don't add a JavaDoc
* comment here, we use the default documentation from implemented
@@ -574,6 +746,7 @@ public class DateField extends AbstractField<Date> implements
*/
public void setResolution(Resolution resolution) {
this.resolution = resolution;
+ updateRangeValidator();
markAsDirty();
}
diff --git a/server/src/com/vaadin/ui/GridLayout.java b/server/src/com/vaadin/ui/GridLayout.java
index e60d9c676a..53a25c1c83 100644
--- a/server/src/com/vaadin/ui/GridLayout.java
+++ b/server/src/com/vaadin/ui/GridLayout.java
@@ -92,6 +92,7 @@ public class GridLayout extends AbstractLayout implements
private Map<Integer, Float> columnExpandRatio = new HashMap<Integer, Float>();
private Map<Integer, Float> rowExpandRatio = new HashMap<Integer, Float>();
+ private Alignment defaultComponentAlignment = Alignment.TOP_LEFT;
/**
* Constructor for a grid of given size (number of columns and rows).
@@ -573,6 +574,7 @@ public class GridLayout extends AbstractLayout implements
int row2) {
this.component = component;
childData = new ChildComponentData();
+ childData.alignment = getDefaultComponentAlignment().getBitMask();
childData.column1 = column1;
childData.row1 = row1;
childData.column2 = column2;
@@ -1226,4 +1228,26 @@ public class GridLayout extends AbstractLayout implements
return new MarginInfo(getState().marginsBitmask);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Layout.AlignmentHandler#getDefaultComponentAlignment()
+ */
+ @Override
+ public Alignment getDefaultComponentAlignment() {
+ return defaultComponentAlignment;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.ui.Layout.AlignmentHandler#setDefaultComponentAlignment(com
+ * .vaadin.ui.Alignment)
+ */
+ @Override
+ public void setDefaultComponentAlignment(Alignment defaultAlignment) {
+ defaultComponentAlignment = defaultAlignment;
+ }
+
}
diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java
index f49a1403cf..d037652a09 100644
--- a/server/src/com/vaadin/ui/Label.java
+++ b/server/src/com/vaadin/ui/Label.java
@@ -21,10 +21,13 @@ import java.util.Locale;
import java.util.logging.Logger;
import com.vaadin.data.Property;
+import com.vaadin.data.util.AbstractProperty;
+import com.vaadin.data.util.LegacyPropertyHelper;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.ConverterUtil;
import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.shared.ui.label.LabelState;
+import com.vaadin.shared.util.SharedUtil;
/**
* Label component for showing non-editable short texts.
@@ -203,23 +206,6 @@ public class Label extends AbstractComponent implements Property<String>,
}
/**
- * Returns the value displayed by this label.
- *
- * @see java.lang.Object#toString()
- * @deprecated As of 7.0, use {@link #getValue()} to get the value of the
- * label or {@link #getPropertyDataSource()} .getValue() to get
- * the value of the data source.
- */
- @Deprecated
- @Override
- public String toString() {
- logger.warning("You are using Label.toString() to get the value for a "
- + getClass().getSimpleName()
- + ". This will not be supported starting from Vaadin 7.1 (your debugger might call toString() and cause this message to appear).");
- return getValue();
- }
-
- /**
* Gets the type of the Property.
*
* @see com.vaadin.data.Property#getType()
@@ -419,7 +405,7 @@ public class Label extends AbstractComponent implements Property<String>,
private void updateValueFromDataSource() {
// Update the internal value from the data source
String newConvertedValue = getDataSourceValue();
- if (!AbstractField.equals(newConvertedValue, getState().text)) {
+ if (!SharedUtil.equals(newConvertedValue, getState().text)) {
getState().text = newConvertedValue;
fireValueChange();
}
@@ -541,4 +527,35 @@ public class Label extends AbstractComponent implements Property<String>,
markAsDirty();
}
+ /**
+ * Returns a string representation of this object. The returned string
+ * representation depends on if the legacy Property toString mode is enabled
+ * or disabled.
+ * <p>
+ * If legacy Property toString mode is enabled, returns the value displayed
+ * by this label.
+ * </p>
+ * <p>
+ * If legacy Property toString mode is disabled, the string representation
+ * has no special meaning
+ * </p>
+ *
+ * @see AbstractProperty#isLegacyToStringEnabled()
+ *
+ * @return The value displayed by this label or a string representation of
+ * this Label object.
+ *
+ * @deprecated As of 7.0, use {@link #getValue()} to get the value of the
+ * label or {@link #getPropertyDataSource()}.getValue() to get
+ * the value of the data source.
+ */
+ @Deprecated
+ @Override
+ public String toString() {
+ if (!LegacyPropertyHelper.isLegacyToStringEnabled()) {
+ return super.toString();
+ } else {
+ return LegacyPropertyHelper.legacyPropertyToString(this);
+ }
+ }
}
diff --git a/server/src/com/vaadin/ui/Layout.java b/server/src/com/vaadin/ui/Layout.java
index cd6ffc42d2..dc16b186f2 100644
--- a/server/src/com/vaadin/ui/Layout.java
+++ b/server/src/com/vaadin/ui/Layout.java
@@ -61,6 +61,23 @@ public interface Layout extends ComponentContainer, Serializable {
*/
public Alignment getComponentAlignment(Component childComponent);
+ /**
+ * Sets the alignment used for new components added to this layout. The
+ * default is {@link Alignment#TOP_LEFT}.
+ *
+ * @param defaultComponentAlignment
+ * The new default alignment
+ */
+ public void setDefaultComponentAlignment(
+ Alignment defaultComponentAlignment);
+
+ /**
+ * Returns the alignment used for new components added to this layout
+ *
+ * @return The default alignment
+ */
+ public Alignment getDefaultComponentAlignment();
+
}
/**
diff --git a/server/src/com/vaadin/ui/LoadingIndicatorConfiguration.java b/server/src/com/vaadin/ui/LoadingIndicatorConfiguration.java
new file mode 100644
index 0000000000..57ccdc1b64
--- /dev/null
+++ b/server/src/com/vaadin/ui/LoadingIndicatorConfiguration.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui;
+
+import java.io.Serializable;
+
+import com.vaadin.shared.ui.ui.UIState.LoadingIndicatorConfigurationState;
+
+/**
+ * Provides method for configuring the loading indicator.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public interface LoadingIndicatorConfiguration extends Serializable {
+ /**
+ * Sets the delay before the loading indicator is shown. The default is
+ * 300ms.
+ *
+ * @param firstDelay
+ * The first delay (in ms)
+ */
+ public void setFirstDelay(int firstDelay);
+
+ /**
+ * Returns the delay before the loading indicator is shown.
+ *
+ * @return The first delay (in ms)
+ */
+ public int getFirstDelay();
+
+ /**
+ * Sets the delay before the loading indicator goes into the "second" state.
+ * The delay is calculated from the time when the loading indicator was
+ * triggered. The default is 1500ms.
+ *
+ * @param secondDelay
+ * The delay before going into the "second" state (in ms)
+ */
+ public void setSecondDelay(int secondDelay);
+
+ /**
+ * Returns the delay before the loading indicator goes into the "second"
+ * state. The delay is calculated from the time when the loading indicator
+ * was triggered.
+ *
+ * @return The delay before going into the "second" state (in ms)
+ */
+ public int getSecondDelay();
+
+ /**
+ * Sets the delay before the loading indicator goes into the "third" state.
+ * The delay is calculated from the time when the loading indicator was
+ * triggered. The default is 5000ms.
+ *
+ * @param thirdDelay
+ * The delay before going into the "third" state (in ms)
+ */
+ public void setThirdDelay(int thirdDelay);
+
+ /**
+ * Returns the delay before the loading indicator goes into the "third"
+ * state. The delay is calculated from the time when the loading indicator
+ * was triggered.
+ *
+ * @return The delay before going into the "third" state (in ms)
+ */
+ public int getThirdDelay();
+}
+
+class LoadingIndicatorConfigurationImpl implements
+ LoadingIndicatorConfiguration {
+ private UI ui;
+
+ public LoadingIndicatorConfigurationImpl(UI ui) {
+ this.ui = ui;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.LoadingIndicator#setFirstDelay(int)
+ */
+ @Override
+ public void setFirstDelay(int firstDelay) {
+ getState().firstDelay = firstDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.LoadingIndicator#getFirstDelay()
+ */
+ @Override
+ public int getFirstDelay() {
+ return getState(false).firstDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.LoadingIndicator#setSecondDelay(int)
+ */
+ @Override
+ public void setSecondDelay(int secondDelay) {
+ getState().secondDelay = secondDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.LoadingIndicator#getSecondDelay()
+ */
+ @Override
+ public int getSecondDelay() {
+ return getState(false).secondDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.LoadingIndicator#setThirdDelay(int)
+ */
+ @Override
+ public void setThirdDelay(int thirdDelay) {
+ getState().thirdDelay = thirdDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.LoadingIndicator#getThirdDelay()
+ */
+ @Override
+ public int getThirdDelay() {
+ return getState(false).thirdDelay;
+ }
+
+ private LoadingIndicatorConfigurationState getState() {
+ return ui.getState().loadingIndicatorConfiguration;
+ }
+
+ private LoadingIndicatorConfigurationState getState(boolean markAsDirty) {
+ return ui.getState(markAsDirty).loadingIndicatorConfiguration;
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/LoginForm.java b/server/src/com/vaadin/ui/LoginForm.java
index 11ae1b379b..d06882927e 100644
--- a/server/src/com/vaadin/ui/LoginForm.java
+++ b/server/src/com/vaadin/ui/LoginForm.java
@@ -61,24 +61,30 @@ public class LoginForm extends CustomComponent {
private Embedded iframe = new Embedded();
@Override
- public boolean handleConnectorRequest(VaadinRequest request,
- VaadinResponse response, String path) throws IOException {
- String method = VaadinServletService.getCurrentServletRequest()
- .getMethod();
+ public boolean handleConnectorRequest(final VaadinRequest request,
+ final VaadinResponse response, String path) throws IOException {
if (!path.equals("login")) {
return super.handleConnectorRequest(request, response, path);
}
- String responseString = null;
- if (method.equalsIgnoreCase("post")) {
- responseString = handleLogin(request);
- } else {
- responseString = getLoginHTML();
- }
+ final StringBuilder responseBuilder = new StringBuilder();
+
+ getUI().access(new Runnable() {
+ @Override
+ public void run() {
+ String method = VaadinServletService.getCurrentServletRequest()
+ .getMethod();
+ if (method.equalsIgnoreCase("post")) {
+ responseBuilder.append(handleLogin(request));
+ } else {
+ responseBuilder.append(getLoginHTML());
+ }
+ }
+ });
- if (responseString != null) {
+ if (responseBuilder.length() > 0) {
response.setContentType("text/html; charset=utf-8");
response.setCacheTime(-1);
- response.getWriter().write(responseString);
+ response.getWriter().write(responseBuilder.toString());
return true;
} else {
return false;
diff --git a/server/src/com/vaadin/ui/PopupDateField.java b/server/src/com/vaadin/ui/PopupDateField.java
index ae33493c89..f0bb0d74fe 100644
--- a/server/src/com/vaadin/ui/PopupDateField.java
+++ b/server/src/com/vaadin/ui/PopupDateField.java
@@ -118,4 +118,24 @@ public class PopupDateField extends DateField {
getState().textFieldEnabled = state;
}
+ /**
+ * Set a description that explains the usage of the Widget for users of
+ * assistive devices.
+ *
+ * @param description
+ * String with the description
+ */
+ public void setAssistiveText(String description) {
+ getState().descriptionForAssistiveDevices = description;
+ }
+
+ /**
+ * Get the description that explains the usage of the Widget for users of
+ * assistive devices.
+ *
+ * @return String with the description
+ */
+ public String getAssistiveText() {
+ return getState().descriptionForAssistiveDevices;
+ }
}
diff --git a/server/src/com/vaadin/ui/TooltipConfiguration.java b/server/src/com/vaadin/ui/TooltipConfiguration.java
new file mode 100644
index 0000000000..f9120aa18d
--- /dev/null
+++ b/server/src/com/vaadin/ui/TooltipConfiguration.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui;
+
+import java.io.Serializable;
+
+import com.vaadin.shared.ui.ui.UIState.TooltipConfigurationState;
+
+/**
+ * Provides method for configuring the tooltip.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public interface TooltipConfiguration extends Serializable {
+ /**
+ * Returns the time (in ms) the tooltip should be displayed after an event
+ * that will cause it to be closed (e.g. mouse click outside the component,
+ * key down).
+ *
+ * @return The close timeout
+ */
+ public int getCloseTimeout();
+
+ /**
+ * Sets the time (in ms) the tooltip should be displayed after an event that
+ * will cause it to be closed (e.g. mouse click outside the component, key
+ * down).
+ *
+ * @param closeTimeout
+ * The close timeout
+ */
+ public void setCloseTimeout(int closeTimeout);
+
+ /**
+ * Returns the time (in ms) during which {@link #getQuickOpenDelay()} should
+ * be used instead of {@link #getOpenDelay()}. The quick open delay is used
+ * when the tooltip has very recently been shown, is currently hidden but
+ * about to be shown again.
+ *
+ * @return The quick open timeout
+ */
+ public int getQuickOpenTimeout();
+
+ /**
+ * Sets the time (in ms) that determines when {@link #getQuickOpenDelay()}
+ * should be used instead of {@link #getOpenDelay()}. The quick open delay
+ * is used when the tooltip has very recently been shown, is currently
+ * hidden but about to be shown again.
+ *
+ * @param quickOpenTimeout
+ * The quick open timeout
+ */
+ public void setQuickOpenTimeout(int quickOpenTimeout);
+
+ /**
+ * Returns the time (in ms) that should elapse before a tooltip will be
+ * shown, in the situation when a tooltip has very recently been shown
+ * (within {@link #getQuickOpenDelay()} ms).
+ *
+ * @return The quick open delay
+ */
+ public int getQuickOpenDelay();
+
+ /**
+ * Sets the time (in ms) that should elapse before a tooltip will be shown,
+ * in the situation when a tooltip has very recently been shown (within
+ * {@link #getQuickOpenDelay()} ms).
+ *
+ * @param quickOpenDelay
+ * The quick open delay
+ */
+ public void setQuickOpenDelay(int quickOpenDelay);
+
+ /**
+ * Returns the time (in ms) that should elapse after an event triggering
+ * tooltip showing has occurred (e.g. mouse over) before the tooltip is
+ * shown. If a tooltip has recently been shown, then
+ * {@link #getQuickOpenDelay()} is used instead of this.
+ *
+ * @return The open delay
+ */
+ public int getOpenDelay();
+
+ /**
+ * Sets the time (in ms) that should elapse after an event triggering
+ * tooltip showing has occurred (e.g. mouse over) before the tooltip is
+ * shown. If a tooltip has recently been shown, then
+ * {@link #getQuickOpenDelay()} is used instead of this.
+ *
+ * @param openDelay
+ * The open delay
+ */
+ public void setOpenDelay(int openDelay);
+
+ /**
+ * Returns the maximum width of the tooltip popup.
+ *
+ * @return The maximum width the tooltip popup
+ */
+ public int getMaxWidth();
+
+ /**
+ * Sets the maximum width of the tooltip popup.
+ *
+ * @param maxWidth
+ * The maximum width the tooltip popup
+ */
+ public void setMaxWidth(int maxWidth);
+}
+
+class TooltipConfigurationImpl implements TooltipConfiguration {
+ private UI ui;
+
+ public TooltipConfigurationImpl(UI ui) {
+ this.ui = ui;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.UI.Tooltip#getCloseTimeout()
+ */
+ @Override
+ public int getCloseTimeout() {
+ return getState(false).closeTimeout;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#setCloseTimeout(int)
+ */
+ @Override
+ public void setCloseTimeout(int closeTimeout) {
+ getState().closeTimeout = closeTimeout;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#getQuickOpenTimeout()
+ */
+ @Override
+ public int getQuickOpenTimeout() {
+ return getState(false).quickOpenTimeout;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#setQuickOpenTimeout(int)
+ */
+ @Override
+ public void setQuickOpenTimeout(int quickOpenTimeout) {
+ getState().quickOpenTimeout = quickOpenTimeout;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#getQuickOpenDelay()
+ */
+ @Override
+ public int getQuickOpenDelay() {
+ return getState(false).quickOpenDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#setQuickOpenDelay(int)
+ */
+ @Override
+ public void setQuickOpenDelay(int quickOpenDelay) {
+ getState().quickOpenDelay = quickOpenDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#getOpenDelay()
+ */
+ @Override
+ public int getOpenDelay() {
+ return getState(false).openDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#setOpenDelay(int)
+ */
+ @Override
+ public void setOpenDelay(int openDelay) {
+ getState().openDelay = openDelay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#getMaxWidth()
+ */
+ @Override
+ public int getMaxWidth() {
+ return getState(false).maxWidth;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Tooltip#setMaxWidth(int)
+ */
+ @Override
+ public void setMaxWidth(int maxWidth) {
+ getState().maxWidth = maxWidth;
+ }
+
+ private TooltipConfigurationState getState() {
+ return ui.getState().tooltipConfiguration;
+ }
+
+ private TooltipConfigurationState getState(boolean markAsDirty) {
+ return ui.getState(markAsDirty).tooltipConfiguration;
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/Tree.java b/server/src/com/vaadin/ui/Tree.java
index a6dbea51ba..15175b5a8b 100644
--- a/server/src/com/vaadin/ui/Tree.java
+++ b/server/src/com/vaadin/ui/Tree.java
@@ -72,6 +72,13 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
/* Private members */
+ private static final String NULL_ALT_EXCEPTION_MESSAGE = "Parameter 'altText' needs to be non null";
+
+ /**
+ * Item icons alt texts.
+ */
+ private final HashMap<Object, String> itemIconAlts = new HashMap<Object, String>();
+
/**
* Set of expanded nodes.
*/
@@ -163,6 +170,70 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
super(caption, dataSource);
}
+ @Override
+ public void setItemIcon(Object itemId, Resource icon) {
+ setItemIcon(itemId, icon, "");
+ }
+
+ /**
+ * Sets the icon for an item.
+ *
+ * @param itemId
+ * the id of the item to be assigned an icon.
+ * @param icon
+ * the icon to use or null.
+ *
+ * @param altText
+ * the alternative text for the icon
+ */
+ public void setItemIcon(Object itemId, Resource icon, String altText) {
+ if (itemId != null) {
+ super.setItemIcon(itemId, icon);
+
+ if (icon == null) {
+ itemIconAlts.remove(itemId);
+ } else if (altText == null) {
+ throw new IllegalArgumentException(NULL_ALT_EXCEPTION_MESSAGE);
+ } else {
+ itemIconAlts.put(itemId, altText);
+ }
+ markAsDirty();
+ }
+ }
+
+ /**
+ * Set the alternate text for an item.
+ *
+ * Used when the item has an icon.
+ *
+ * @param itemId
+ * the id of the item to be assigned an icon.
+ * @param altText
+ * the alternative text for the icon
+ */
+ public void setItemIconAlternateText(Object itemId, String altText) {
+ if (itemId != null) {
+ if (altText == null) {
+ throw new IllegalArgumentException(NULL_ALT_EXCEPTION_MESSAGE);
+ } else {
+ itemIconAlts.put(itemId, altText);
+ }
+ }
+ }
+
+ /**
+ * Return the alternate text of an icon in a tree item.
+ *
+ * @param itemId
+ * Object with the ID of the item
+ * @return String with the alternate text of the icon, or null when no icon
+ * was set
+ */
+ public String getItemIconAlternateText(Object itemId) {
+ String storedAlt = itemIconAlts.get(itemId);
+ return storedAlt == null ? "" : storedAlt;
+ }
+
/* Expanding and collapsing */
/**
@@ -638,6 +709,8 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
if (icon != null) {
target.addAttribute(TreeConstants.ATTRIBUTE_NODE_ICON,
getItemIcon(itemId));
+ target.addAttribute(TreeConstants.ATTRIBUTE_NODE_ICON_ALT,
+ getItemIconAlternateText(itemId));
}
final String key = itemIdMapper.key(itemId);
target.addAttribute("key", key);
@@ -861,6 +934,37 @@ public class Tree extends AbstractSelect implements Container.Hierarchical,
}
+ @Override
+ public void containerItemSetChange(
+ com.vaadin.data.Container.ItemSetChangeEvent event) {
+ super.containerItemSetChange(event);
+ if (getContainerDataSource() instanceof Filterable) {
+ boolean hasFilters = !((Filterable) getContainerDataSource())
+ .getContainerFilters().isEmpty();
+ if (!hasFilters) {
+ /*
+ * If Container is not filtered then the itemsetchange is caused
+ * by either adding or removing items to the container. To
+ * prevent a memory leak we should cleanup the expanded list
+ * from items which was removed.
+ *
+ * However, there will still be a leak if the container is
+ * filtered to show only a subset of the items in the tree and
+ * later unfiltered items are removed from the container. In
+ * that case references to the unfiltered item ids will remain
+ * in the expanded list until the Tree instance is removed and
+ * the list is destroyed, or the container data source is
+ * replaced/updated. To force the removal of the removed items
+ * the application developer needs to a) remove the container
+ * filters temporarly or b) re-apply the container datasource
+ * using setContainerDataSource(getContainerDataSource())
+ */
+ cleanupExpandedItems();
+ }
+ }
+
+ }
+
/* Expand event and listener */
/**
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index 796d1f08ea..e077b003b8 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -37,9 +37,12 @@ import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServlet;
import com.vaadin.server.VaadinSession;
+import com.vaadin.server.communication.PushConnection;
import com.vaadin.shared.EventId;
import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.ui.ScrollClientRpc;
+import com.vaadin.shared.ui.ui.UIClientRpc;
import com.vaadin.shared.ui.ui.UIConstants;
import com.vaadin.shared.ui.ui.UIServerRpc;
import com.vaadin.shared.ui.ui.UIState;
@@ -114,7 +117,10 @@ public abstract class UI extends AbstractSingleComponentContainer implements
/** Identifies the click event */
private ConnectorTracker connectorTracker = new ConnectorTracker(this);
- private Page page = new Page(this);
+ private Page page = new Page(this, getState(false).pageState);
+
+ private LoadingIndicatorConfiguration loadingIndicatorConfiguration = new LoadingIndicatorConfigurationImpl(
+ this);
/**
* Scroll Y position.
@@ -144,6 +150,14 @@ public abstract class UI extends AbstractSingleComponentContainer implements
UI.this.scrollTop = scrollTop;
UI.this.scrollLeft = scrollLeft;
}
+
+ @Override
+ public void poll() {
+ /*
+ * No-op. This is only called to cause a server visit to check for
+ * changes.
+ */
+ }
};
/**
@@ -155,6 +169,9 @@ public abstract class UI extends AbstractSingleComponentContainer implements
private boolean closing = false;
+ private TooltipConfiguration tooltipConfiguration = new TooltipConfigurationImpl(
+ this);
+
/**
* Creates a new empty UI without a caption. The content of the UI must be
* set by calling {@link #setContent(Component)} before using the UI.
@@ -347,6 +364,12 @@ public abstract class UI extends AbstractSingleComponentContainer implements
} else {
if (session == null) {
detach();
+ if (pushConnection != null && pushConnection.isConnected()) {
+ // Close the push connection when UI is detached. Otherwise
+ // the push connection and possibly VaadinSession will live
+ // on.
+ pushConnection.disconnect();
+ }
}
this.session = session;
}
@@ -466,6 +489,10 @@ public abstract class UI extends AbstractSingleComponentContainer implements
private Navigator navigator;
+ private PushConnection pushConnection = null;
+
+ private boolean hasPendingPush = false;
+
/**
* This method is used by Component.Focusable objects to request focus to
* themselves. Focus renders must be handled at window level (instead of
@@ -659,10 +686,16 @@ public abstract class UI extends AbstractSingleComponentContainer implements
/**
* 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.
+ * layout sizes are recalculated and resize events are sent to the server.
+ * Speeds up resize operations in slow UIs with the penalty of slightly
+ * decreased usability.
* <p>
* Default value: <code>false</code>
+ * </p>
+ * <p>
+ * When there are active window resize listeners, lazy resize mode should be
+ * used to avoid a large number of events during resize.
+ * </p>
*
* @param resizeLazy
* true to use a delay before recalculating sizes, false to
@@ -986,6 +1019,15 @@ public abstract class UI extends AbstractSingleComponentContainer implements
*/
public void close() {
closing = true;
+
+ boolean sessionExpired = (session == null || session.isClosing());
+ getRpcProxy(UIClientRpc.class).uiClosed(sessionExpired);
+ if (getPushConnection() != null && getPushConnection().isConnected()) {
+ // Push the Rpc to the client. The connection will be closed when
+ // the UI is detached and cleaned up.
+ getPushConnection().push();
+ }
+
}
/**
@@ -1054,4 +1096,265 @@ public abstract class UI extends AbstractSingleComponentContainer implements
public int getTabIndex() {
return getState(false).tabIndex;
}
+
+ /**
+ * Provides exclusive access to this UI from outside a request handling
+ * thread.
+ * <p>
+ * The given runnable is executed while holding the session lock to ensure
+ * exclusive access to this UI and its session. The UI and related thread
+ * locals are set properly before executing the runnable.
+ * </p>
+ * <p>
+ * RPC handlers for components inside this UI do not need this method as the
+ * session is automatically locked by the framework during request handling.
+ * </p>
+ * <p>
+ * Note that calling this method while another session is locked by the
+ * current thread will cause an exception. This is to prevent deadlock
+ * situations when two threads have locked one session each and are both
+ * waiting for the lock for the other session.
+ * </p>
+ *
+ * @param runnable
+ * the runnable which accesses the UI
+ * @throws UIDetachedException
+ * if the UI is not attached to a session (and locking can
+ * therefore not be done)
+ * @throws IllegalStateException
+ * if the current thread holds the lock for another session
+ *
+ * @see #getCurrent()
+ * @see VaadinSession#access(Runnable)
+ * @see VaadinSession#lock()
+ */
+ public void access(Runnable runnable) throws UIDetachedException {
+ Map<Class<?>, CurrentInstance> old = null;
+
+ VaadinSession session = getSession();
+
+ if (session == null) {
+ throw new UIDetachedException();
+ }
+
+ VaadinService.verifyNoOtherSessionLocked(session);
+
+ session.lock();
+ try {
+ if (getSession() == null) {
+ // UI was detached after fetching the session but before we
+ // acquired the lock.
+ throw new UIDetachedException();
+ }
+ old = CurrentInstance.setThreadLocals(this);
+ runnable.run();
+ } finally {
+ session.unlock();
+ if (old != null) {
+ CurrentInstance.restoreThreadLocals(old);
+ }
+ }
+
+ }
+
+ /**
+ * @deprecated As of 7.1.0.beta1, use {@link #access(Runnable)} instead.
+ * This method will be removed before the final 7.1.0 release.
+ */
+ @Deprecated
+ public void runSafely(Runnable runnable) throws UIDetachedException {
+ access(runnable);
+ }
+
+ /**
+ * Retrieves the object used for configuring tooltips.
+ *
+ * @return The instance used for tooltip configuration
+ */
+ public TooltipConfiguration getTooltipConfiguration() {
+ return tooltipConfiguration;
+ }
+
+ /**
+ * Retrieves the object used for configuring the loading indicator.
+ *
+ * @return The instance used for configuring the loading indicator
+ */
+ public LoadingIndicatorConfiguration getLoadingIndicatorConfiguration() {
+ return loadingIndicatorConfiguration;
+ }
+
+ /**
+ * Pushes the pending changes and client RPC invocations of this UI to the
+ * client-side.
+ * <p>
+ * As with all UI methods, it is not safe to call push() without holding the
+ * {@link VaadinSession#lock() session lock}.
+ *
+ * @throws IllegalStateException
+ * if push is disabled.
+ * @throws UIDetachedException
+ * if this UI is not attached to a session.
+ *
+ * @see #getPushMode()
+ *
+ * @since 7.1
+ */
+ public void push() {
+ VaadinSession session = getSession();
+ if (session != null) {
+ assert session.hasLock();
+ if (!getConnectorTracker().hasDirtyConnectors()) {
+ // Do not push if there is nothing to push
+ return;
+ }
+
+ if (!getPushMode().isEnabled()) {
+ throw new IllegalStateException("Push not enabled");
+ }
+
+ if (pushConnection == null) {
+ hasPendingPush = true;
+ } else {
+ pushConnection.push();
+ }
+ } else {
+ throw new UIDetachedException("Trying to push a detached UI");
+ }
+ }
+
+ /**
+ * Returns the internal push connection object used by this UI. This method
+ * should only be called by the framework.
+ */
+ public PushConnection getPushConnection() {
+ return pushConnection;
+ }
+
+ /**
+ * Sets the internal push connection object used by this UI. This method
+ * should only be called by the framework.
+ */
+ public void setPushConnection(PushConnection pushConnection) {
+ // If pushMode is disabled then there should never be a pushConnection
+ assert (getPushMode().isEnabled() || pushConnection == null);
+
+ if (pushConnection == this.pushConnection) {
+ return;
+ }
+
+ if (this.pushConnection != null) {
+ this.pushConnection.disconnect();
+ }
+
+ this.pushConnection = pushConnection;
+ if (pushConnection != null && hasPendingPush) {
+ hasPendingPush = false;
+ pushConnection.push();
+ }
+ }
+
+ /**
+ * Sets the interval with which the UI should poll the server to see if
+ * there are any changes. Polling is disabled by default.
+ * <p>
+ * Note that it is possible to enable push and polling at the same time but
+ * it should not be done to avoid excessive server traffic.
+ * </p>
+ * <p>
+ * Add-on developers should note that this method is only meant for the
+ * application developer. An add-on should not set the poll interval
+ * directly, rather instruct the user to set it.
+ * </p>
+ *
+ * @param intervalInMillis
+ * The interval (in ms) with which the UI should poll the server
+ * or -1 to disable polling
+ */
+ public void setPollInterval(int intervalInMillis) {
+ getState().pollInterval = intervalInMillis;
+ }
+
+ /**
+ * Returns the interval with which the UI polls the server.
+ *
+ * @return The interval (in ms) with which the UI polls the server or -1 if
+ * polling is disabled
+ */
+ public int getPollInterval() {
+ return getState(false).pollInterval;
+ }
+
+ /**
+ * Returns the mode of bidirectional ("push") communication that is used in
+ * this UI.
+ *
+ * @return The push mode.
+ */
+ public PushMode getPushMode() {
+ return getState(false).pushMode;
+ }
+
+ /**
+ * Sets the mode of bidirectional ("push") communication that should be used
+ * in this UI.
+ * <p>
+ * Add-on developers should note that this method is only meant for the
+ * application developer. An add-on should not set the push mode directly,
+ * rather instruct the user to set it.
+ * </p>
+ *
+ * @param pushMode
+ * The push mode to use.
+ *
+ * @throws IllegalArgumentException
+ * if the argument is null.
+ * @throws IllegalStateException
+ * if push support is not available.
+ */
+ public void setPushMode(PushMode pushMode) {
+ if (pushMode == null) {
+ throw new IllegalArgumentException("Push mode cannot be null");
+ }
+
+ if (pushMode.isEnabled()) {
+ VaadinSession session = getSession();
+ if (session != null && !session.getService().ensurePushAvailable()) {
+ throw new IllegalStateException(
+ "Push is not available. See previous log messages for more information.");
+ }
+ }
+
+ /*
+ * Client-side will open a new connection or disconnect the old
+ * connection, so there's nothing more to do on the server at this
+ * point.
+ */
+ getState().pushMode = pushMode;
+ }
+
+ /**
+ * Get the label that is added to the container element, where tooltip,
+ * notification and dialogs are added to.
+ *
+ * @return the label of the container
+ */
+ public String getOverlayContainerLabel() {
+ return getState().overlayContainerLabel;
+ }
+
+ /**
+ * Sets the label that is added to the container element, where tooltip,
+ * notifications and dialogs are added to.
+ * <p>
+ * This is helpful for users of assistive devices, as this element is
+ * reachable for them.
+ * </p>
+ *
+ * @param overlayContainerLabel
+ * label to use for the container
+ */
+ public void setOverlayContainerLabel(String overlayContainerLabel) {
+ getState().overlayContainerLabel = overlayContainerLabel;
+ }
}
diff --git a/server/src/com/vaadin/ui/UIDetachedException.java b/server/src/com/vaadin/ui/UIDetachedException.java
new file mode 100644
index 0000000000..07207b0bf3
--- /dev/null
+++ b/server/src/com/vaadin/ui/UIDetachedException.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui;
+
+/**
+ * Exception thrown if the UI has been detached when it should not be.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public class UIDetachedException extends RuntimeException {
+
+ public UIDetachedException() {
+ super();
+ }
+
+ public UIDetachedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public UIDetachedException(String message) {
+ super(message);
+ }
+
+ public UIDetachedException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/Window.java b/server/src/com/vaadin/ui/Window.java
index d8b33e6b25..9f64c9118e 100644
--- a/server/src/com/vaadin/ui/Window.java
+++ b/server/src/com/vaadin/ui/Window.java
@@ -35,8 +35,10 @@ import com.vaadin.server.ClientConnector;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.shared.MouseEventDetails;
+import com.vaadin.shared.ui.window.WindowMode;
import com.vaadin.shared.ui.window.WindowServerRpc;
import com.vaadin.shared.ui.window.WindowState;
+import com.vaadin.util.ReflectTools;
/**
* A component that represents a floating popup window that can be added to a
@@ -71,6 +73,11 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
public void click(MouseEventDetails mouseDetails) {
fireEvent(new ClickEvent(Window.this, mouseDetails));
}
+
+ @Override
+ public void windowModeChanged(WindowMode newState) {
+ setWindowMode(newState);
+ }
};
/**
@@ -234,10 +241,10 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
/**
* Gets the distance of Window left border in pixels from left border of the
- * containing (main window).
+ * containing (main window) when the window is in {@link WindowMode#NORMAL}.
*
* @return the Distance of Window left border in pixels from left border of
- * the containing (main window). or -1 if unspecified.
+ * the containing (main window).or -1 if unspecified
* @since 4.0.0
*/
public int getPositionX() {
@@ -246,7 +253,8 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
/**
* Sets the distance of Window left border in pixels from left border of the
- * containing (main window).
+ * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
+ * mode.
*
* @param positionX
* the Distance of Window left border in pixels from left border
@@ -260,10 +268,11 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
/**
* Gets the distance of Window top border in pixels from top border of the
- * containing (main window).
+ * containing (main window) when the window is in {@link WindowMode#NORMAL}
+ * state, or when next set to that state.
*
* @return Distance of Window top border in pixels from top border of the
- * containing (main window). or -1 if unspecified .
+ * containing (main window). or -1 if unspecified
*
* @since 4.0.0
*/
@@ -273,7 +282,8 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
/**
* Sets the distance of Window top border in pixels from top border of the
- * containing (main window).
+ * containing (main window). Has effect only if in {@link WindowMode#NORMAL}
+ * mode.
*
* @param positionY
* the Distance of Window top border in pixels from top border of
@@ -402,6 +412,101 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
}
/**
+ * Event which is fired when the mode of the Window changes.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ *
+ */
+ public static class WindowModeChangeEvent extends Component.Event {
+
+ private final WindowMode windowMode;
+
+ /**
+ *
+ * @param source
+ */
+ public WindowModeChangeEvent(Component source, WindowMode windowMode) {
+ super(source);
+ this.windowMode = windowMode;
+ }
+
+ /**
+ * Gets the Window.
+ *
+ * @return the window
+ */
+ public Window getWindow() {
+ return (Window) getSource();
+ }
+
+ /**
+ * Gets the new window mode.
+ *
+ * @return the new mode
+ */
+ public WindowMode getWindowMode() {
+ return windowMode;
+ }
+ }
+
+ /**
+ * An interface used for listening to Window maximize / restore events. Add
+ * the WindowModeChangeListener to a window and
+ * {@link WindowModeChangeListener#windowModeChanged(WindowModeChangeEvent)}
+ * will be called whenever the window is maximized (
+ * {@link WindowMode#MAXIMIZED}) or restored ({@link WindowMode#NORMAL} ).
+ */
+ public interface WindowModeChangeListener extends Serializable {
+
+ public static final Method windowModeChangeMethod = ReflectTools
+ .findMethod(WindowModeChangeListener.class,
+ "windowModeChanged", WindowModeChangeEvent.class);
+
+ /**
+ * Called when the user maximizes / restores a window. Use
+ * {@link WindowModeChangeEvent#getWindow()} to get a reference to the
+ * {@link Window} that was maximized / restored. Use
+ * {@link WindowModeChangeEvent#getWindowMode()} to get a reference to
+ * the new state.
+ *
+ * @param event
+ */
+ public void windowModeChanged(WindowModeChangeEvent event);
+ }
+
+ /**
+ * Adds a WindowModeChangeListener to the window.
+ *
+ * The WindowModeChangeEvent is fired when the user changed the display
+ * state by clicking the maximize/restore button or by double clicking on
+ * the window header. The event is also fired if the state is changed using
+ * {@link #setWindowMode(WindowMode)}.
+ *
+ * @param listener
+ * the WindowModeChangeListener to add.
+ */
+ public void addWindowModeChangeListener(WindowModeChangeListener listener) {
+ addListener(WindowModeChangeEvent.class, listener,
+ WindowModeChangeListener.windowModeChangeMethod);
+ }
+
+ /**
+ * Removes the WindowModeChangeListener from the window.
+ *
+ * @param listener
+ * the WindowModeChangeListener to remove.
+ */
+ public void removeWindowModeChangeListener(WindowModeChangeListener listener) {
+ removeListener(WindowModeChangeEvent.class, listener,
+ WindowModeChangeListener.windowModeChangeMethod);
+ }
+
+ protected void fireWindowWindowModeChange() {
+ fireEvent(new Window.WindowModeChangeEvent(this, getState().windowMode));
+ }
+
+ /**
* Method for the resize event.
*/
private static final Method WINDOW_RESIZE_METHOD;
@@ -670,6 +775,30 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
getState().draggable = draggable;
}
+ /**
+ * Gets the current mode of the window.
+ *
+ * @see WindowMode
+ * @return the mode of the window.
+ */
+ public WindowMode getWindowMode() {
+ return getState(false).windowMode;
+ }
+
+ /**
+ * Sets the mode for the window
+ *
+ * @see WindowMode
+ * @param windowMode
+ * The new mode
+ */
+ public void setWindowMode(WindowMode windowMode) {
+ if (windowMode != getWindowMode()) {
+ getState().windowMode = windowMode;
+ fireWindowWindowModeChange();
+ }
+ }
+
/*
* Actions
*/
@@ -873,4 +1002,9 @@ public class Window extends Panel implements FocusNotifier, BlurNotifier,
protected WindowState getState() {
return (WindowState) super.getState();
}
+
+ @Override
+ protected WindowState getState(boolean markAsDirty) {
+ return (WindowState) super.getState(markAsDirty);
+ }
}
diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java
new file mode 100644
index 0000000000..1f012157b5
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvent.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar;
+
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.Component;
+
+/**
+ * All Calendar events extends this class.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+@SuppressWarnings("serial")
+public class CalendarComponentEvent extends Component.Event {
+
+ /**
+ * Set the source of the event
+ *
+ * @param source
+ * The source calendar
+ *
+ */
+ public CalendarComponentEvent(Calendar source) {
+ super(source);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.Component.Event#getComponent()
+ */
+ @Override
+ public Calendar getComponent() {
+ return (Calendar) super.getComponent();
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java
new file mode 100644
index 0000000000..1904d69898
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/CalendarComponentEvents.java
@@ -0,0 +1,603 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.util.Date;
+import java.util.EventListener;
+
+import com.vaadin.shared.ui.calendar.CalendarEventId;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.util.ReflectTools;
+
+/**
+ * Interface for all Vaadin Calendar events.
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+public interface CalendarComponentEvents extends Serializable {
+
+ /**
+ * Notifier interface for notifying listener of calendar events
+ */
+ public interface CalendarEventNotifier extends Serializable {
+ /**
+ * Get the assigned event handler for the given eventId.
+ *
+ * @param eventId
+ * @return the assigned eventHandler, or null if no handler is assigned
+ */
+ public EventListener getHandler(String eventId);
+ }
+
+ /**
+ * Notifier interface for event drag & drops.
+ */
+ public interface EventMoveNotifier extends CalendarEventNotifier {
+
+ /**
+ * Set the EventMoveHandler.
+ *
+ * @param listener
+ * EventMoveHandler to be added
+ */
+ public void setHandler(EventMoveHandler listener);
+
+ }
+
+ /**
+ * MoveEvent is sent when existing event is dragged to a new position.
+ */
+ @SuppressWarnings("serial")
+ public class MoveEvent extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.EVENTMOVE;
+
+ /** Index for the moved Schedule.Event. */
+ private CalendarEvent calendarEvent;
+
+ /** New starting date for the moved Calendar.Event. */
+ private Date newStart;
+
+ /**
+ * MoveEvent needs the target event and new start date.
+ *
+ * @param source
+ * Calendar component.
+ * @param calendarEvent
+ * Target event.
+ * @param newStart
+ * Target event's new start date.
+ */
+ public MoveEvent(Calendar source, CalendarEvent calendarEvent,
+ Date newStart) {
+ super(source);
+
+ this.calendarEvent = calendarEvent;
+ this.newStart = newStart;
+ }
+
+ /**
+ * Get target event.
+ *
+ * @return Target event.
+ */
+ public CalendarEvent getCalendarEvent() {
+ return calendarEvent;
+ }
+
+ /**
+ * Get new start date.
+ *
+ * @return New start date.
+ */
+ public Date getNewStart() {
+ return newStart;
+ }
+ }
+
+ /**
+ * Handler interface for when events are being dragged on the calendar
+ *
+ */
+ public interface EventMoveHandler extends EventListener, Serializable {
+
+ /** Trigger method for the MoveEvent. */
+ public static final Method eventMoveMethod = ReflectTools.findMethod(
+ EventMoveHandler.class, "eventMove", MoveEvent.class);
+
+ /**
+ * This method will be called when event has been moved to a new
+ * position.
+ *
+ * @param event
+ * MoveEvent containing specific information of the new
+ * position and target event.
+ */
+ public void eventMove(MoveEvent event);
+ }
+
+ /**
+ * Handler interface for day or time cell drag-marking with mouse.
+ */
+ public interface RangeSelectNotifier extends Serializable,
+ CalendarEventNotifier {
+
+ /**
+ * Set the RangeSelectHandler that listens for drag-marking.
+ *
+ * @param listener
+ * RangeSelectHandler to be added.
+ */
+ public void setHandler(RangeSelectHandler listener);
+ }
+
+ /**
+ * RangeSelectEvent is sent when day or time cells are drag-marked with
+ * mouse.
+ */
+ @SuppressWarnings("serial")
+ public class RangeSelectEvent extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.RANGESELECT;
+
+ /** Calendar event's start date. */
+ private Date start;
+
+ /** Calendar event's end date. */
+ private Date end;
+
+ /**
+ * Defines the event's view mode.
+ */
+ private boolean monthlyMode;
+
+ /**
+ * RangeSelectEvent needs a start and end date.
+ *
+ * @param source
+ * Calendar component.
+ * @param start
+ * Start date.
+ * @param end
+ * End date.
+ * @param monthlyMode
+ * Calendar view mode.
+ */
+ public RangeSelectEvent(Calendar source, Date start, Date end,
+ boolean monthlyMode) {
+ super(source);
+ this.start = start;
+ this.end = end;
+ this.monthlyMode = monthlyMode;
+ }
+
+ /**
+ * Get start date.
+ *
+ * @return Start date.
+ */
+ public Date getStart() {
+ return start;
+ }
+
+ /**
+ * Get end date.
+ *
+ * @return End date.
+ */
+ public Date getEnd() {
+ return end;
+ }
+
+ /**
+ * Gets the event's view mode. Calendar can be be either in monthly or
+ * weekly mode, depending on the active date range.
+ *
+ * @deprecated User {@link Calendar#isMonthlyMode()} instead
+ *
+ * @return Returns true when monthly view is active.
+ */
+ @Deprecated
+ public boolean isMonthlyMode() {
+ return monthlyMode;
+ }
+ }
+
+ /** RangeSelectHandler handles RangeSelectEvent. */
+ public interface RangeSelectHandler extends EventListener, Serializable {
+
+ /** Trigger method for the RangeSelectEvent. */
+ public static final Method rangeSelectMethod = ReflectTools
+ .findMethod(RangeSelectHandler.class, "rangeSelect",
+ RangeSelectEvent.class);
+
+ /**
+ * This method will be called when day or time cells are drag-marked
+ * with mouse.
+ *
+ * @param event
+ * RangeSelectEvent that contains range start and end date.
+ */
+ public void rangeSelect(RangeSelectEvent event);
+ }
+
+ /** Notifier interface for navigation listening. */
+ public interface NavigationNotifier extends Serializable {
+ /**
+ * Add a forward navigation listener.
+ *
+ * @param handler
+ * ForwardHandler to be added.
+ */
+ public void setHandler(ForwardHandler handler);
+
+ /**
+ * Add a backward navigation listener.
+ *
+ * @param handler
+ * BackwardHandler to be added.
+ */
+ public void setHandler(BackwardHandler handler);
+
+ /**
+ * Add a date click listener.
+ *
+ * @param handler
+ * DateClickHandler to be added.
+ */
+ public void setHandler(DateClickHandler handler);
+
+ /**
+ * Add a event click listener.
+ *
+ * @param handler
+ * EventClickHandler to be added.
+ */
+ public void setHandler(EventClickHandler handler);
+
+ /**
+ * Add a week click listener.
+ *
+ * @param handler
+ * WeekClickHandler to be added.
+ */
+ public void setHandler(WeekClickHandler handler);
+ }
+
+ /**
+ * ForwardEvent is sent when forward navigation button is clicked.
+ */
+ @SuppressWarnings("serial")
+ public class ForwardEvent extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.FORWARD;
+
+ /**
+ * ForwardEvent needs only the source component.
+ *
+ * @param source
+ * Calendar component.
+ */
+ public ForwardEvent(Calendar source) {
+ super(source);
+ }
+ }
+
+ /** ForwardHandler handles ForwardEvent. */
+ public interface ForwardHandler extends EventListener, Serializable {
+
+ /** Trigger method for the ForwardEvent. */
+ public static final Method forwardMethod = ReflectTools.findMethod(
+ ForwardHandler.class, "forward", ForwardEvent.class);
+
+ /**
+ * This method will be called when date range is moved forward.
+ *
+ * @param event
+ * ForwardEvent
+ */
+ public void forward(ForwardEvent event);
+ }
+
+ /**
+ * BackwardEvent is sent when backward navigation button is clicked.
+ */
+ @SuppressWarnings("serial")
+ public class BackwardEvent extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.BACKWARD;
+
+ /**
+ * BackwardEvent needs only the source source component.
+ *
+ * @param source
+ * Calendar component.
+ */
+ public BackwardEvent(Calendar source) {
+ super(source);
+ }
+ }
+
+ /** BackwardHandler handles BackwardEvent. */
+ public interface BackwardHandler extends EventListener, Serializable {
+
+ /** Trigger method for the BackwardEvent. */
+ public static final Method backwardMethod = ReflectTools.findMethod(
+ BackwardHandler.class, "backward", BackwardEvent.class);
+
+ /**
+ * This method will be called when date range is moved backwards.
+ *
+ * @param event
+ * BackwardEvent
+ */
+ public void backward(BackwardEvent event);
+ }
+
+ /**
+ * DateClickEvent is sent when a date is clicked.
+ */
+ @SuppressWarnings("serial")
+ public class DateClickEvent extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.DATECLICK;
+
+ /** Date that was clicked. */
+ private Date date;
+
+ /** DateClickEvent needs the target date that was clicked. */
+ public DateClickEvent(Calendar source, Date date) {
+ super(source);
+ this.date = date;
+ }
+
+ /**
+ * Get clicked date.
+ *
+ * @return Clicked date.
+ */
+ public Date getDate() {
+ return date;
+ }
+ }
+
+ /** DateClickHandler handles DateClickEvent. */
+ public interface DateClickHandler extends EventListener, Serializable {
+
+ /** Trigger method for the DateClickEvent. */
+ public static final Method dateClickMethod = ReflectTools.findMethod(
+ DateClickHandler.class, "dateClick", DateClickEvent.class);
+
+ /**
+ * This method will be called when a date is clicked.
+ *
+ * @param event
+ * DateClickEvent containing the target date.
+ */
+ public void dateClick(DateClickEvent event);
+ }
+
+ /**
+ * EventClick is sent when an event is clicked.
+ */
+ @SuppressWarnings("serial")
+ public class EventClick extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.EVENTCLICK;
+
+ /** Clicked source event. */
+ private CalendarEvent calendarEvent;
+
+ /** Target source event is needed for the EventClick. */
+ public EventClick(Calendar source, CalendarEvent calendarEvent) {
+ super(source);
+ this.calendarEvent = calendarEvent;
+ }
+
+ /**
+ * Get the clicked event.
+ *
+ * @return Clicked event.
+ */
+ public CalendarEvent getCalendarEvent() {
+ return calendarEvent;
+ }
+ }
+
+ /** EventClickHandler handles EventClick. */
+ public interface EventClickHandler extends EventListener, Serializable {
+
+ /** Trigger method for the EventClick. */
+ public static final Method eventClickMethod = ReflectTools.findMethod(
+ EventClickHandler.class, "eventClick", EventClick.class);
+
+ /**
+ * This method will be called when an event is clicked.
+ *
+ * @param event
+ * EventClick containing the target event.
+ */
+ public void eventClick(EventClick event);
+ }
+
+ /**
+ * WeekClick is sent when week is clicked.
+ */
+ @SuppressWarnings("serial")
+ public class WeekClick extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.WEEKCLICK;
+
+ /** Target week. */
+ private int week;
+
+ /** Target year. */
+ private int year;
+
+ /**
+ * WeekClick needs a target year and week.
+ *
+ * @param source
+ * Target source.
+ * @param week
+ * Target week.
+ * @param year
+ * Target year.
+ */
+ public WeekClick(Calendar source, int week, int year) {
+ super(source);
+ this.week = week;
+ this.year = year;
+ }
+
+ /**
+ * Get week as a integer. See {@link java.util.Calendar} for the allowed
+ * values.
+ *
+ * @return Week as a integer.
+ */
+ public int getWeek() {
+ return week;
+ }
+
+ /**
+ * Get year as a integer. See {@link java.util.Calendar} for the allowed
+ * values.
+ *
+ * @return Year as a integer
+ */
+ public int getYear() {
+ return year;
+ }
+ }
+
+ /** WeekClickHandler handles WeekClicks. */
+ public interface WeekClickHandler extends EventListener, Serializable {
+
+ /** Trigger method for the WeekClick. */
+ public static final Method weekClickMethod = ReflectTools.findMethod(
+ WeekClickHandler.class, "weekClick", WeekClick.class);
+
+ /**
+ * This method will be called when a week is clicked.
+ *
+ * @param event
+ * WeekClick containing the target week and year.
+ */
+ public void weekClick(WeekClick event);
+ }
+
+ /**
+ * EventResize is sent when an event is resized
+ */
+ @SuppressWarnings("serial")
+ public class EventResize extends CalendarComponentEvent {
+
+ public static final String EVENT_ID = CalendarEventId.EVENTRESIZE;
+
+ private CalendarEvent calendarEvent;
+
+ private Date startTime;
+
+ private Date endTime;
+
+ public EventResize(Calendar source, CalendarEvent calendarEvent,
+ Date startTime, Date endTime) {
+ super(source);
+ this.calendarEvent = calendarEvent;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ }
+
+ /**
+ * Get target event.
+ *
+ * @return Target event.
+ */
+ public CalendarEvent getCalendarEvent() {
+ return calendarEvent;
+ }
+
+ /**
+ * @deprecated Use {@link #getNewStart()} instead
+ *
+ * @return the new start time
+ */
+ @Deprecated
+ public Date getNewStartTime() {
+ return startTime;
+ }
+
+ /**
+ * Returns the updated start date/time of the event
+ *
+ * @return The new date for the event
+ */
+ public Date getNewStart() {
+ return startTime;
+ }
+
+ /**
+ * @deprecated Use {@link #getNewEnd()} instead
+ *
+ * @return the new end time
+ */
+ @Deprecated
+ public Date getNewEndTime() {
+ return endTime;
+ }
+
+ /**
+ * Returns the updates end date/time of the event
+ *
+ * @return The new date for the event
+ */
+ public Date getNewEnd() {
+ return endTime;
+ }
+ }
+
+ /**
+ * Notifier interface for event resizing.
+ */
+ public interface EventResizeNotifier extends Serializable {
+
+ /**
+ * Set a EventResizeHandler.
+ *
+ * @param handler
+ * EventResizeHandler to be set
+ */
+ public void setHandler(EventResizeHandler handler);
+ }
+
+ /**
+ * Handler for EventResize event.
+ */
+ public interface EventResizeHandler extends EventListener, Serializable {
+
+ /** Trigger method for the EventResize. */
+ public static final Method eventResizeMethod = ReflectTools.findMethod(
+ EventResizeHandler.class, "eventResize", EventResize.class);
+
+ void eventResize(EventResize event);
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java b/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java
new file mode 100644
index 0000000000..01b766a6db
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/CalendarDateRange.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * Class for representing a date range.
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ *
+ */
+@SuppressWarnings("serial")
+public class CalendarDateRange implements Serializable {
+
+ private Date start;
+
+ private Date end;
+
+ private final transient TimeZone tz;
+
+ /**
+ * Constructor
+ *
+ * @param start
+ * The start date and time of the date range
+ * @param end
+ * The end date and time of the date range
+ */
+ public CalendarDateRange(Date start, Date end, TimeZone tz) {
+ super();
+ this.start = start;
+ this.end = end;
+ this.tz = tz;
+ }
+
+ /**
+ * Get the start date of the date range
+ *
+ * @return the start Date of the range
+ */
+ public Date getStart() {
+ return start;
+ }
+
+ /**
+ * Get the end date of the date range
+ *
+ * @return the end Date of the range
+ */
+ public Date getEnd() {
+ return end;
+ }
+
+ /**
+ * Is a date in the date range
+ *
+ * @param date
+ * The date to check
+ * @return true if the date range contains a date start and end of range
+ * inclusive; false otherwise
+ */
+ public boolean inRange(Date date) {
+ if (date == null) {
+ return false;
+ }
+
+ return date.compareTo(start) >= 0 && date.compareTo(end) <= 0;
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java b/server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java
new file mode 100644
index 0000000000..1a3ef67377
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/CalendarTargetDetails.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar;
+
+import java.util.Date;
+import java.util.Map;
+
+import com.vaadin.event.dd.DropTarget;
+import com.vaadin.event.dd.TargetDetailsImpl;
+import com.vaadin.ui.Calendar;
+
+/**
+ * Drop details for {@link com.vaadin.ui.addon.calendar.ui.Calendar Calendar}.
+ * When something is dropped on the Calendar, this class contains the specific
+ * details of the drop point. Specifically, this class gives access to the date
+ * where the drop happened. If the Calendar was in weekly mode, the date also
+ * includes the start time of the slot.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class CalendarTargetDetails extends TargetDetailsImpl {
+
+ private boolean hasDropTime;
+
+ public CalendarTargetDetails(Map<String, Object> rawDropData,
+ DropTarget dropTarget) {
+ super(rawDropData, dropTarget);
+ }
+
+ /**
+ * @return true if {@link #getDropTime()} will return a date object with the
+ * time set to the start of the time slot where the drop happened
+ */
+ public boolean hasDropTime() {
+ return hasDropTime;
+ }
+
+ /**
+ * Does the dropped item have a time associated with it
+ *
+ * @param hasDropTime
+ */
+ public void setHasDropTime(boolean hasDropTime) {
+ this.hasDropTime = hasDropTime;
+ }
+
+ /**
+ * @return the date where the drop happened
+ */
+ public Date getDropTime() {
+ if (hasDropTime) {
+ return (Date) getData("dropTime");
+ } else {
+ return (Date) getData("dropDay");
+ }
+ }
+
+ /**
+ * @return the {@link com.vaadin.ui.addon.calendar.ui.Calendar Calendar}
+ * instance which was the target of the drop
+ */
+ public Calendar getTargetCalendar() {
+ return (Calendar) getTarget();
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java
new file mode 100644
index 0000000000..37ea255d27
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/ContainerEventProvider.java
@@ -0,0 +1,577 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.LinkedList;
+import java.util.List;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Container.Indexed;
+import com.vaadin.data.Container.ItemSetChangeEvent;
+import com.vaadin.data.Container.ItemSetChangeNotifier;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeNotifier;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEditableEventProvider;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeListener;
+import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeNotifier;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider.EventSetChangeNotifier;
+
+/**
+ * A event provider which uses a {@link Container} as a datasource. Container
+ * used as data source.
+ *
+ * NOTE: The data source must be sorted by date!
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class ContainerEventProvider implements CalendarEditableEventProvider,
+ EventSetChangeNotifier, EventChangeNotifier, EventMoveHandler,
+ EventResizeHandler, Container.ItemSetChangeListener,
+ Property.ValueChangeListener {
+
+ // Default property ids
+ public static final String CAPTION_PROPERTY = "caption";
+ public static final String DESCRIPTION_PROPERTY = "description";
+ public static final String STARTDATE_PROPERTY = "start";
+ public static final String ENDDATE_PROPERTY = "end";
+ public static final String STYLENAME_PROPERTY = "styleName";
+
+ /**
+ * Internal class to keep the container index which item this event
+ * represents
+ *
+ */
+ private class ContainerCalendarEvent extends BasicEvent {
+ private final int index;
+
+ public ContainerCalendarEvent(int containerIndex) {
+ super();
+ index = containerIndex;
+ }
+
+ public int getContainerIndex() {
+ return index;
+ }
+ }
+
+ /**
+ * Listeners attached to the container
+ */
+ private final List<EventSetChangeListener> eventSetChangeListeners = new LinkedList<CalendarEventProvider.EventSetChangeListener>();
+ private final List<EventChangeListener> eventChangeListeners = new LinkedList<CalendarEvent.EventChangeListener>();
+
+ /**
+ * The event cache contains the events previously created by
+ * {@link #getEvents(Date, Date)}
+ */
+ private final List<CalendarEvent> eventCache = new LinkedList<CalendarEvent>();
+
+ /**
+ * The container used as datasource
+ */
+ private Indexed container;
+
+ /**
+ * Container properties. Defaults based on using the {@link BasicEvent}
+ * helper class.
+ */
+ private Object captionProperty = CAPTION_PROPERTY;
+ private Object descriptionProperty = DESCRIPTION_PROPERTY;
+ private Object startDateProperty = STARTDATE_PROPERTY;
+ private Object endDateProperty = ENDDATE_PROPERTY;
+ private Object styleNameProperty = STYLENAME_PROPERTY;
+
+ /**
+ * Constructor
+ *
+ * @param container
+ * Container to use as a data source.
+ */
+ public ContainerEventProvider(Container.Indexed container) {
+ this.container = container;
+ listenToContainerEvents();
+ }
+
+ /**
+ * Set the container data source
+ *
+ * @param container
+ * The container to use as datasource
+ *
+ */
+ public void setContainerDataSource(Container.Indexed container) {
+ // Detach the previous container
+ detachContainerDataSource();
+
+ this.container = container;
+ listenToContainerEvents();
+ }
+
+ /**
+ * Returns the container used as data source
+ *
+ */
+ public Container.Indexed getContainerDataSource() {
+ return container;
+ }
+
+ /**
+ * Attaches listeners to the container so container events can be processed
+ */
+ private void listenToContainerEvents() {
+ if (container instanceof ItemSetChangeNotifier) {
+ ((ItemSetChangeNotifier) container).addItemSetChangeListener(this);
+ }
+ if (container instanceof ValueChangeNotifier) {
+ ((ValueChangeNotifier) container).addValueChangeListener(this);
+ }
+ }
+
+ /**
+ * Removes listeners from the container so no events are processed
+ */
+ private void ignoreContainerEvents() {
+ if (container instanceof ItemSetChangeNotifier) {
+ ((ItemSetChangeNotifier) container)
+ .removeItemSetChangeListener(this);
+ }
+ if (container instanceof ValueChangeNotifier) {
+ ((ValueChangeNotifier) container).removeValueChangeListener(this);
+ }
+ }
+
+ /**
+ * Converts an event in the container to an {@link CalendarEvent}
+ *
+ * @param index
+ * The index of the item in the container to get the event for
+ * @return
+ */
+ private CalendarEvent getEvent(int index) {
+
+ // Check the event cache first
+ for (CalendarEvent e : eventCache) {
+ if (e instanceof ContainerCalendarEvent
+ && ((ContainerCalendarEvent) e).getContainerIndex() == index) {
+ return e;
+ } else if (container.getIdByIndex(index) == e) {
+ return e;
+ }
+ }
+
+ final Object id = container.getIdByIndex(index);
+ Item item = container.getItem(id);
+ CalendarEvent event;
+ if (id instanceof CalendarEvent) {
+ /*
+ * If we are using the BeanItemContainer or another container which
+ * stores the objects as ids then just return the instances
+ */
+ event = (CalendarEvent) id;
+
+ } else {
+ /*
+ * Else we use the properties to create the event
+ */
+ BasicEvent basicEvent = new ContainerCalendarEvent(index);
+
+ // Set values from property values
+ if (captionProperty != null
+ && item.getItemPropertyIds().contains(captionProperty)) {
+ basicEvent.setCaption(String.valueOf(item.getItemProperty(
+ captionProperty).getValue()));
+ }
+ if (descriptionProperty != null
+ && item.getItemPropertyIds().contains(descriptionProperty)) {
+ basicEvent.setDescription(String.valueOf(item.getItemProperty(
+ descriptionProperty).getValue()));
+ }
+ if (startDateProperty != null
+ && item.getItemPropertyIds().contains(startDateProperty)) {
+ basicEvent.setStart((Date) item.getItemProperty(
+ startDateProperty).getValue());
+ }
+ if (endDateProperty != null
+ && item.getItemPropertyIds().contains(endDateProperty)) {
+ basicEvent.setEnd((Date) item.getItemProperty(endDateProperty)
+ .getValue());
+ }
+ if (styleNameProperty != null
+ && item.getItemPropertyIds().contains(styleNameProperty)) {
+ basicEvent.setDescription(String.valueOf(item.getItemProperty(
+ descriptionProperty).getValue()));
+ }
+ event = basicEvent;
+ }
+ return event;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java.
+ * util.Date, java.util.Date)
+ */
+ @Override
+ public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
+ eventCache.clear();
+
+ int[] rangeIndexes = getFirstAndLastEventIndex(startDate, endDate);
+ for (int i = rangeIndexes[0]; i <= rangeIndexes[1]
+ && i < container.size(); i++) {
+ eventCache.add(getEvent(i));
+ }
+ return Collections.unmodifiableList(eventCache);
+ }
+
+ /**
+ * Get the first event for a date
+ *
+ * @param date
+ * The date to search for, NUll returns first event in container
+ * @return Returns an array where the first item is the start index and the
+ * second item is the end item
+ */
+ private int[] getFirstAndLastEventIndex(Date start, Date end) {
+ int startIndex = 0;
+ int size = container.size();
+ int endIndex = size - 1;
+
+ if (start != null) {
+ /*
+ * Iterating from the start of the container, if range is in the end
+ * of the container then this will be slow TODO This could be
+ * improved by using some sort of divide and conquer algorithm
+ */
+ while (startIndex < size) {
+ Object id = container.getIdByIndex(startIndex);
+ Item item = container.getItem(id);
+ Date d = (Date) item.getItemProperty(startDateProperty)
+ .getValue();
+ if (d.compareTo(start) >= 0) {
+ break;
+ }
+ startIndex++;
+ }
+ }
+
+ if (end != null) {
+ /*
+ * Iterate from the start index until range ends
+ */
+ endIndex = startIndex;
+ while (endIndex < size - 1) {
+ Object id = container.getIdByIndex(endIndex);
+ Item item = container.getItem(id);
+ Date d = (Date) item.getItemProperty(endDateProperty)
+ .getValue();
+ if (d == null) {
+ // No end date present, use start date
+ d = (Date) item.getItemProperty(startDateProperty)
+ .getValue();
+ }
+ if (d.compareTo(end) >= 0) {
+ endIndex--;
+ break;
+ }
+ endIndex++;
+ }
+ }
+
+ return new int[] { startIndex, endIndex };
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventProvider.EventSetChangeNotifier
+ * #addListener(com.vaadin.addon.calendar.event.CalendarEventProvider.
+ * EventSetChangeListener)
+ */
+ @Override
+ public void addEventSetChangeListener(EventSetChangeListener listener) {
+ if (!eventSetChangeListeners.contains(listener)) {
+ eventSetChangeListeners.add(listener);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventProvider.EventSetChangeNotifier
+ * #removeListener(com.vaadin.addon.calendar.event.CalendarEventProvider.
+ * EventSetChangeListener)
+ */
+ @Override
+ public void removeEventSetChangeListener(EventSetChangeListener listener) {
+ eventSetChangeListeners.remove(listener);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEvent.EventChangeNotifier#addListener
+ * (com.vaadin.addon.calendar.event.CalendarEvent.EventChangeListener)
+ */
+ @Override
+ public void addEventChangeListener(EventChangeListener listener) {
+ if (eventChangeListeners.contains(listener)) {
+ eventChangeListeners.add(listener);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent.EventChangeNotifier#
+ * removeListener
+ * (com.vaadin.addon.calendar.event.CalendarEvent.EventChangeListener)
+ */
+ @Override
+ public void removeEventChangeListener(EventChangeListener listener) {
+ eventChangeListeners.remove(listener);
+ }
+
+ /**
+ * Get the property which provides the caption of the event
+ */
+ public Object getCaptionProperty() {
+ return captionProperty;
+ }
+
+ /**
+ * Set the property which provides the caption of the event
+ */
+ public void setCaptionProperty(Object captionProperty) {
+ this.captionProperty = captionProperty;
+ }
+
+ /**
+ * Get the property which provides the description of the event
+ */
+ public Object getDescriptionProperty() {
+ return descriptionProperty;
+ }
+
+ /**
+ * Set the property which provides the description of the event
+ */
+ public void setDescriptionProperty(Object descriptionProperty) {
+ this.descriptionProperty = descriptionProperty;
+ }
+
+ /**
+ * Get the property which provides the starting date and time of the event
+ */
+ public Object getStartDateProperty() {
+ return startDateProperty;
+ }
+
+ /**
+ * Set the property which provides the starting date and time of the event
+ */
+ public void setStartDateProperty(Object startDateProperty) {
+ this.startDateProperty = startDateProperty;
+ }
+
+ /**
+ * Get the property which provides the ending date and time of the event
+ */
+ public Object getEndDateProperty() {
+ return endDateProperty;
+ }
+
+ /**
+ * Set the property which provides the ending date and time of the event
+ */
+ public void setEndDateProperty(Object endDateProperty) {
+ this.endDateProperty = endDateProperty;
+ }
+
+ /**
+ * Get the property which provides the style name for the event
+ */
+ public Object getStyleNameProperty() {
+ return styleNameProperty;
+ }
+
+ /**
+ * Set the property which provides the style name for the event
+ */
+ public void setStyleNameProperty(Object styleNameProperty) {
+ this.styleNameProperty = styleNameProperty;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.Container.ItemSetChangeListener#containerItemSetChange
+ * (com.vaadin.data.Container.ItemSetChangeEvent)
+ */
+ @Override
+ public void containerItemSetChange(ItemSetChangeEvent event) {
+ if (event.getContainer() == container) {
+ // Trigger an eventset change event when the itemset changes
+ for (EventSetChangeListener listener : eventSetChangeListeners) {
+ listener.eventSetChange(new EventSetChangeEvent(this));
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data
+ * .Property.ValueChangeEvent)
+ */
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ /*
+ * TODO Need to figure out how to get the item which triggered the the
+ * valuechange event and then trigger a EventChange event to the
+ * listeners
+ */
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler
+ * #eventMove
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.MoveEvent)
+ */
+ @Override
+ public void eventMove(MoveEvent event) {
+ CalendarEvent ce = event.getCalendarEvent();
+ if (eventCache.contains(ce)) {
+ int index;
+ if (ce instanceof ContainerCalendarEvent) {
+ index = ((ContainerCalendarEvent) ce).getContainerIndex();
+ } else {
+ index = container.indexOfId(ce);
+ }
+
+ long eventLength = ce.getEnd().getTime() - ce.getStart().getTime();
+ Date newEnd = new Date(event.getNewStart().getTime() + eventLength);
+
+ ignoreContainerEvents();
+ Item item = container.getItem(container.getIdByIndex(index));
+ item.getItemProperty(startDateProperty).setValue(
+ event.getNewStart());
+ item.getItemProperty(endDateProperty).setValue(newEnd);
+ listenToContainerEvents();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler
+ * #eventResize
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResize)
+ */
+ @Override
+ public void eventResize(EventResize event) {
+ CalendarEvent ce = event.getCalendarEvent();
+ if (eventCache.contains(ce)) {
+ int index;
+ if (ce instanceof ContainerCalendarEvent) {
+ index = ((ContainerCalendarEvent) ce).getContainerIndex();
+ } else {
+ index = container.indexOfId(ce);
+ }
+ ignoreContainerEvents();
+ Item item = container.getItem(container.getIdByIndex(index));
+ item.getItemProperty(startDateProperty).setValue(
+ event.getNewStart());
+ item.getItemProperty(endDateProperty).setValue(event.getNewEnd());
+ listenToContainerEvents();
+ }
+ }
+
+ /**
+ * If you are reusing the container which previously have been attached to
+ * this ContainerEventProvider call this method to remove this event
+ * providers container listeners before attaching it to an other
+ * ContainerEventProvider
+ */
+ public void detachContainerDataSource() {
+ ignoreContainerEvents();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent
+ * (com.vaadin.addon.calendar.event.CalendarEvent)
+ */
+ @Override
+ public void addEvent(CalendarEvent event) {
+ Item item;
+ try {
+ item = container.addItem(event);
+ } catch (UnsupportedOperationException uop) {
+ // Thrown if container does not support adding items with custom
+ // ids. JPAContainer for example.
+ item = container.getItem(container.addItem());
+ }
+ if (item != null) {
+ item.getItemProperty(getCaptionProperty()).setValue(
+ event.getCaption());
+ item.getItemProperty(getStartDateProperty()).setValue(
+ event.getStart());
+ item.getItemProperty(getEndDateProperty()).setValue(event.getEnd());
+ item.getItemProperty(getStyleNameProperty()).setValue(
+ event.getStyleName());
+ item.getItemProperty(getDescriptionProperty()).setValue(
+ event.getDescription());
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent
+ * (com.vaadin.addon.calendar.event.CalendarEvent)
+ */
+ @Override
+ public void removeEvent(CalendarEvent event) {
+ container.removeItem(event);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java b/server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java
new file mode 100644
index 0000000000..3f14145f0c
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/event/BasicEvent.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.event;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeNotifier;
+
+/**
+ * Simple implementation of
+ * {@link com.vaadin.addon.calendar.event.CalendarEvent CalendarEvent}. Has
+ * setters for all required fields and fires events when this event is changed.
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicEvent implements EditableCalendarEvent, EventChangeNotifier {
+
+ private String caption;
+ private String description;
+ private Date end;
+ private Date start;
+ private String styleName;
+ private transient List<EventChangeListener> listeners = new ArrayList<EventChangeListener>();
+
+ private boolean isAllDay;
+
+ /**
+ * Default constructor
+ */
+ public BasicEvent() {
+
+ }
+
+ /**
+ * Constructor for creating an event with the same start and end date
+ *
+ * @param caption
+ * The caption for the event
+ * @param description
+ * The description for the event
+ * @param date
+ * The date the event occurred
+ */
+ public BasicEvent(String caption, String description, Date date) {
+ this.caption = caption;
+ this.description = description;
+ start = date;
+ end = date;
+ }
+
+ /**
+ * Constructor for creating an event with a start date and an end date.
+ * Start date should be before the end date
+ *
+ * @param caption
+ * The caption for the event
+ * @param description
+ * The description for the event
+ * @param startDate
+ * The start date of the event
+ * @param endDate
+ * The end date of the event
+ */
+ public BasicEvent(String caption, String description, Date startDate,
+ Date endDate) {
+ this.caption = caption;
+ this.description = description;
+ start = startDate;
+ end = endDate;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getCaption()
+ */
+ @Override
+ public String getCaption() {
+ return caption;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getDescription()
+ */
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getEnd()
+ */
+ @Override
+ public Date getEnd() {
+ return end;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getStart()
+ */
+ @Override
+ public Date getStart() {
+ return start;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#getStyleName()
+ */
+ @Override
+ public String getStyleName() {
+ return styleName;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.addon.calendar.event.CalendarEvent#isAllDay()
+ */
+ @Override
+ public boolean isAllDay() {
+ return isAllDay;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventEditor#setCaption(java.lang
+ * .String)
+ */
+ @Override
+ public void setCaption(String caption) {
+ this.caption = caption;
+ fireEventChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventEditor#setDescription(java
+ * .lang.String)
+ */
+ @Override
+ public void setDescription(String description) {
+ this.description = description;
+ fireEventChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventEditor#setEnd(java.util.
+ * Date)
+ */
+ @Override
+ public void setEnd(Date end) {
+ this.end = end;
+ fireEventChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventEditor#setStart(java.util
+ * .Date)
+ */
+ @Override
+ public void setStart(Date start) {
+ this.start = start;
+ fireEventChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventEditor#setStyleName(java
+ * .lang.String)
+ */
+ @Override
+ public void setStyleName(String styleName) {
+ this.styleName = styleName;
+ fireEventChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventEditor#setAllDay(boolean)
+ */
+ @Override
+ public void setAllDay(boolean isAllDay) {
+ this.isAllDay = isAllDay;
+ fireEventChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeListener
+ * )
+ */
+ @Override
+ public void addEventChangeListener(EventChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeNotifier
+ * #removeListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeListener
+ * )
+ */
+ @Override
+ public void removeEventChangeListener(EventChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Fires an event change event to the listeners. Should be triggered when
+ * some property of the event changes.
+ */
+ protected void fireEventChange() {
+ EventChangeEvent event = new EventChangeEvent(this);
+
+ for (EventChangeListener listener : listeners) {
+ listener.eventChange(event);
+ }
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java b/server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java
new file mode 100644
index 0000000000..b2b74a5e52
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/event/BasicEventProvider.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.event;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.vaadin.ui.components.calendar.event.CalendarEvent.EventChangeEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider.EventSetChangeNotifier;
+
+/**
+ * <p>
+ * Simple implementation of
+ * {@link com.vaadin.addon.calendar.event.CalendarEventProvider
+ * CalendarEventProvider}. Use {@link #addEvent(CalendarEvent)} and
+ * {@link #removeEvent(CalendarEvent)} to add / remove events.
+ * </p>
+ *
+ * <p>
+ * {@link com.vaadin.addon.calendar.event.CalendarEventProvider.EventSetChangeNotifier
+ * EventSetChangeNotifier} and
+ * {@link com.vaadin.addon.calendar.event.CalendarEvent.EventChangeListener
+ * EventChangeListener} are also implemented, so the Calendar is notified when
+ * an event is added, changed or removed.
+ * </p>
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicEventProvider implements CalendarEditableEventProvider,
+ EventSetChangeNotifier, CalendarEvent.EventChangeListener {
+
+ protected List<CalendarEvent> eventList = new ArrayList<CalendarEvent>();
+
+ private List<EventSetChangeListener> listeners = new ArrayList<EventSetChangeListener>();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java.
+ * util.Date, java.util.Date)
+ */
+ @Override
+ public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
+ ArrayList<CalendarEvent> activeEvents = new ArrayList<CalendarEvent>();
+
+ for (CalendarEvent ev : eventList) {
+ long from = startDate.getTime();
+ long to = endDate.getTime();
+
+ if (ev.getStart() != null && ev.getEnd() != null) {
+ long f = ev.getStart().getTime();
+ long t = ev.getEnd().getTime();
+ // Select only events that overlaps with startDate and
+ // endDate.
+ if ((f <= to && f >= from) || (t >= from && t <= to)
+ || (f <= from && t >= to)) {
+ activeEvents.add(ev);
+ }
+ }
+ }
+
+ return activeEvents;
+ }
+
+ /**
+ * Does this event provider container this event
+ *
+ * @param event
+ * The event to check for
+ * @return If this provider has the event then true is returned, else false
+ */
+ public boolean containsEvent(BasicEvent event) {
+ return eventList.contains(event);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeNotifier
+ * #addListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeListener
+ * )
+ */
+ @Override
+ public void addEventSetChangeListener(EventSetChangeListener listener) {
+ listeners.add(listener);
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeNotifier
+ * #removeListener
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChangeListener
+ * )
+ */
+ @Override
+ public void removeEventSetChangeListener(EventSetChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Fires a eventsetchange event. The event is fired when either an event is
+ * added or removed to the event provider
+ */
+ protected void fireEventSetChange() {
+ EventSetChangeEvent event = new EventSetChangeEvent(this);
+
+ for (EventSetChangeListener listener : listeners) {
+ listener.eventSetChange(event);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventChangeListener
+ * #eventChange
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventSetChange)
+ */
+ @Override
+ public void eventChange(EventChangeEvent changeEvent) {
+ // naive implementation
+ fireEventSetChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent
+ * (com.vaadin.addon.calendar.event.CalendarEvent)
+ */
+ @Override
+ public void addEvent(CalendarEvent event) {
+ eventList.add(event);
+ if (event instanceof BasicEvent) {
+ ((BasicEvent) event).addEventChangeListener(this);
+ }
+ fireEventSetChange();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent
+ * (com.vaadin.addon.calendar.event.CalendarEvent)
+ */
+ @Override
+ public void removeEvent(CalendarEvent event) {
+ eventList.remove(event);
+ if (event instanceof BasicEvent) {
+ ((BasicEvent) event).removeEventChangeListener(this);
+ }
+ fireEventSetChange();
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java b/server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java
new file mode 100644
index 0000000000..13e84df666
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/event/CalendarEditableEventProvider.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.ui.components.calendar.event;
+
+/**
+ * An event provider which allows adding and removing events
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+public interface CalendarEditableEventProvider extends CalendarEventProvider {
+
+ /**
+ * Adds an event to the event provider
+ *
+ * @param event
+ * The event to add
+ */
+ void addEvent(CalendarEvent event);
+
+ /**
+ * Removes an event from the event provider
+ *
+ * @param event
+ * The event
+ */
+ void removeEvent(CalendarEvent event);
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java b/server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java
new file mode 100644
index 0000000000..531ee72c7f
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/event/CalendarEvent.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.event;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>
+ * Event in the calendar. Customize your own event by implementing this
+ * interface.
+ * </p>
+ *
+ * <li>Start and end fields are mandatory.</li>
+ *
+ * <li>In "allDay" events longer than one day, starting and ending clock times
+ * are omitted in UI and only dates are shown.</li>
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ *
+ */
+public interface CalendarEvent extends Serializable {
+
+ /**
+ * Gets start date of event.
+ *
+ * @return Start date.
+ */
+ public Date getStart();
+
+ /**
+ * Get end date of event.
+ *
+ * @return End date;
+ */
+ public Date getEnd();
+
+ /**
+ * Gets caption of event.
+ *
+ * @return Caption text
+ */
+ public String getCaption();
+
+ /**
+ * Gets description of event. Shown as a tooltip over the event.
+ *
+ * @return Description text.
+ */
+ public String getDescription();
+
+ /**
+ * <p>
+ * Gets style name of event. In the client, style name will be set to the
+ * event's element class name and can be styled by CSS
+ * </p>
+ * Styling example:</br> <code>Java code: </br>
+ * event.setStyleName("color1");
+ * </br></br>
+ * CSS:</br>
+ * .v-calendar-event-color1 {</br>
+ * &nbsp;&nbsp;&nbsp;background-color: #9effae;</br>}</code>
+ *
+ * @return Style name.
+ */
+ public String getStyleName();
+
+ /**
+ * An all-day event typically does not occur at a specific time but targets
+ * a whole day or days. The rendering of all-day events differs from normal
+ * events.
+ *
+ * @return true if this event is an all-day event, false otherwise
+ */
+ public boolean isAllDay();
+
+ /**
+ * Event to signal that an event has changed.
+ */
+ @SuppressWarnings("serial")
+ public class EventChangeEvent implements Serializable {
+
+ private CalendarEvent source;
+
+ public EventChangeEvent(CalendarEvent source) {
+ this.source = source;
+ }
+
+ /**
+ * @return the {@link com.vaadin.addon.calendar.event.CalendarEvent
+ * CalendarEvent} that has changed
+ */
+ public CalendarEvent getCalendarEvent() {
+ return source;
+ }
+ }
+
+ /**
+ * Listener for EventSetChange events.
+ */
+ public interface EventChangeListener extends Serializable {
+
+ /**
+ * Called when an Event has changed.
+ */
+ public void eventChange(EventChangeEvent eventChangeEvent);
+ }
+
+ /**
+ * Notifier interface for EventChange events.
+ */
+ public interface EventChangeNotifier extends Serializable {
+
+ /**
+ * Add a listener to listen for EventChangeEvents. These events are
+ * fired when a events properties are changed.
+ *
+ * @param listener
+ * The listener to add
+ */
+ void addEventChangeListener(EventChangeListener listener);
+
+ /**
+ * Remove a listener from the event provider.
+ *
+ * @param listener
+ * The listener to remove
+ */
+ void removeEventChangeListener(EventChangeListener listener);
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java b/server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java
new file mode 100644
index 0000000000..fefb2ca9b6
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/event/CalendarEventProvider.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.event;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Interface for querying events. The Vaadin Calendar always has a
+ * CalendarEventProvider set.
+ *
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+public interface CalendarEventProvider extends Serializable {
+ /**
+ * <p>
+ * Gets all available events in the target date range between startDate and
+ * endDate. The Vaadin Calendar queries the events from the range that is
+ * shown, which is not guaranteed to be the same as the date range that is
+ * set.
+ * </p>
+ *
+ * <p>
+ * For example, if you set the date range to be monday 22.2.2010 - wednesday
+ * 24.2.2000, the used Event Provider will be queried for events between
+ * monday 22.2.2010 00:00 and sunday 28.2.2010 23:59. Generally you can
+ * expect the date range to be expanded to whole days and whole weeks.
+ * </p>
+ *
+ * @param startDate
+ * Start date
+ * @param endDate
+ * End date
+ * @return List of events
+ */
+ public List<CalendarEvent> getEvents(Date startDate, Date endDate);
+
+ /**
+ * Event to signal that the set of events has changed and the calendar
+ * should refresh its view from the
+ * {@link com.vaadin.addon.calendar.event.CalendarEventProvider
+ * CalendarEventProvider} .
+ *
+ */
+ @SuppressWarnings("serial")
+ public class EventSetChangeEvent implements Serializable {
+
+ private CalendarEventProvider source;
+
+ public EventSetChangeEvent(CalendarEventProvider source) {
+ this.source = source;
+ }
+
+ /**
+ * @return the
+ * {@link com.vaadin.addon.calendar.event.CalendarEventProvider
+ * CalendarEventProvider} that has changed
+ */
+ public CalendarEventProvider getProvider() {
+ return source;
+ }
+ }
+
+ /**
+ * Listener for EventSetChange events.
+ */
+ public interface EventSetChangeListener extends Serializable {
+
+ /**
+ * Called when the set of Events has changed.
+ */
+ public void eventSetChange(EventSetChangeEvent changeEvent);
+ }
+
+ /**
+ * Notifier interface for EventSetChange events.
+ */
+ public interface EventSetChangeNotifier extends Serializable {
+
+ /**
+ * Add a listener for listening to when new events are adding or removed
+ * from the event provider.
+ *
+ * @param listener
+ * The listener to add
+ */
+ void addEventSetChangeListener(EventSetChangeListener listener);
+
+ /**
+ * Remove a listener which listens to {@link EventSetChangeEvent}-events
+ *
+ * @param listener
+ * The listener to remove
+ */
+ void removeEventSetChangeListener(EventSetChangeListener listener);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java b/server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java
new file mode 100644
index 0000000000..e8a27ad50f
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/event/EditableCalendarEvent.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.event;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * Extension to the basic {@link com.vaadin.addon.calendar.event.CalendarEvent
+ * CalendarEvent}. This interface provides setters (and thus editing
+ * capabilities) for all {@link com.vaadin.addon.calendar.event.CalendarEvent
+ * CalendarEvent} fields. For descriptions on the fields, refer to the extended
+ * interface.
+ * </p>
+ *
+ * <p>
+ * This interface is used by some of the basic Calendar event handlers in the
+ * <code>com.vaadin.addon.calendar.ui.handler</code> package to determine
+ * whether an event can be edited.
+ * </p>
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public interface EditableCalendarEvent extends CalendarEvent {
+
+ /**
+ * Set the visible text in the calendar for the event.
+ *
+ * @param caption
+ * The text to show in the calendar
+ */
+ void setCaption(String caption);
+
+ /**
+ * Set the description of the event. This is shown in the calendar when
+ * hoovering over the event.
+ *
+ * @param description
+ * The text which describes the event
+ */
+ void setDescription(String description);
+
+ /**
+ * Set the end date of the event. Must be after the start date.
+ *
+ * @param end
+ * The end date to set
+ */
+ void setEnd(Date end);
+
+ /**
+ * Set the start date for the event. Must be before the end date
+ *
+ * @param start
+ * The start date of the event
+ */
+ void setStart(Date start);
+
+ /**
+ * Set the style name for the event used for styling the event cells
+ *
+ * @param styleName
+ * The stylename to use
+ *
+ */
+ void setStyleName(String styleName);
+
+ /**
+ * Does the event span the whole day. If so then set this to true
+ *
+ * @param isAllDay
+ * True if the event spans the whole day. In this case the start
+ * and end times are ignored.
+ */
+ void setAllDay(boolean isAllDay);
+
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java
new file mode 100644
index 0000000000..65e9c94dec
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicBackwardHandler.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.handler;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import com.vaadin.shared.ui.calendar.DateConstants;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardHandler;
+
+/**
+ * Implements basic functionality needed to enable backwards navigation.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicBackwardHandler implements BackwardHandler {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardHandler#
+ * backward
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardEvent)
+ */
+ @Override
+ public void backward(BackwardEvent event) {
+ Date start = event.getComponent().getStartDate();
+ Date end = event.getComponent().getEndDate();
+
+ // calculate amount to move back
+ int durationInDays = (int) (((end.getTime()) - start.getTime()) / DateConstants.DAYINMILLIS);
+ durationInDays++;
+ durationInDays = -durationInDays;
+
+ // set new start and end times
+ Calendar javaCalendar = event.getComponent().getInternalCalendar();
+ javaCalendar.setTime(start);
+ javaCalendar.add(java.util.Calendar.DATE, durationInDays);
+ Date newStart = javaCalendar.getTime();
+
+ javaCalendar.setTime(end);
+ javaCalendar.add(java.util.Calendar.DATE, durationInDays);
+ Date newEnd = javaCalendar.getTime();
+
+ setDates(event, newStart, newEnd);
+ }
+
+ /**
+ * Set the start and end dates for the event
+ *
+ * @param event
+ * The event that the start and end dates should be set
+ * @param start
+ * The start date
+ * @param end
+ * The end date
+ */
+ protected void setDates(BackwardEvent event, Date start, Date end) {
+ event.getComponent().setStartDate(start);
+ event.getComponent().setEndDate(end);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java
new file mode 100644
index 0000000000..ac2470e008
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicDateClickHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.handler;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickHandler;
+
+/**
+ * Implements basic functionality needed to switch to day view when a single day
+ * is clicked.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicDateClickHandler implements DateClickHandler {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickHandler
+ * #dateClick
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickEvent)
+ */
+ @Override
+ public void dateClick(DateClickEvent event) {
+ Date clickedDate = event.getDate();
+
+ Calendar javaCalendar = event.getComponent().getInternalCalendar();
+ javaCalendar.setTime(clickedDate);
+
+ // as times are expanded, this is all that is needed to show one day
+ Date start = javaCalendar.getTime();
+ Date end = javaCalendar.getTime();
+
+ setDates(event, start, end);
+ }
+
+ /**
+ * Set the start and end dates for the event
+ *
+ * @param event
+ * The event that the start and end dates should be set
+ * @param start
+ * The start date
+ * @param end
+ * The end date
+ */
+ protected void setDates(DateClickEvent event, Date start, Date end) {
+ event.getComponent().setStartDate(start);
+ event.getComponent().setEndDate(end);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java
new file mode 100644
index 0000000000..ae4c5fcc12
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventMoveHandler.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.handler;
+
+import java.util.Date;
+
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventMoveHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.event.EditableCalendarEvent;
+
+/**
+ * Implements basic functionality needed to enable moving events.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicEventMoveHandler implements EventMoveHandler {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler
+ * #eventMove
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.MoveEvent)
+ */
+ @Override
+ public void eventMove(MoveEvent event) {
+ CalendarEvent calendarEvent = event.getCalendarEvent();
+
+ if (calendarEvent instanceof EditableCalendarEvent) {
+
+ EditableCalendarEvent editableEvent = (EditableCalendarEvent) calendarEvent;
+
+ Date newFromTime = event.getNewStart();
+
+ // Update event dates
+ long length = editableEvent.getEnd().getTime()
+ - editableEvent.getStart().getTime();
+ setDates(editableEvent, newFromTime, new Date(newFromTime.getTime()
+ + length));
+ }
+ }
+
+ /**
+ * Set the start and end dates for the event
+ *
+ * @param event
+ * The event that the start and end dates should be set
+ * @param start
+ * The start date
+ * @param end
+ * The end date
+ */
+ protected void setDates(EditableCalendarEvent event, Date start, Date end) {
+ event.setStart(start);
+ event.setEnd(end);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java
new file mode 100644
index 0000000000..ee7fc27360
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicEventResizeHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.handler;
+
+import java.util.Date;
+
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResizeHandler;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.event.EditableCalendarEvent;
+
+/**
+ * Implements basic functionality needed to enable event resizing.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicEventResizeHandler implements EventResizeHandler {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler
+ * #eventResize
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResize)
+ */
+ @Override
+ public void eventResize(EventResize event) {
+ CalendarEvent calendarEvent = event.getCalendarEvent();
+
+ if (calendarEvent instanceof EditableCalendarEvent) {
+ Date newStartTime = event.getNewStart();
+ Date newEndTime = event.getNewEnd();
+
+ EditableCalendarEvent editableEvent = (EditableCalendarEvent) calendarEvent;
+
+ setDates(editableEvent, newStartTime, newEndTime);
+ }
+ }
+
+ /**
+ * Set the start and end dates for the event
+ *
+ * @param event
+ * The event that the start and end dates should be set
+ * @param start
+ * The start date
+ * @param end
+ * The end date
+ */
+ protected void setDates(EditableCalendarEvent event, Date start, Date end) {
+ event.setStart(start);
+ event.setEnd(end);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java
new file mode 100644
index 0000000000..e36c9e5756
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicForwardHandler.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.handler;
+
+import java.util.Calendar;
+import java.util.Date;
+
+import com.vaadin.shared.ui.calendar.DateConstants;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardHandler;
+
+/**
+ * Implements basic functionality needed to enable forward navigation.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicForwardHandler implements ForwardHandler {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardHandler#forward
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardEvent)
+ */
+ @Override
+ public void forward(ForwardEvent event) {
+ Date start = event.getComponent().getStartDate();
+ Date end = event.getComponent().getEndDate();
+
+ // calculate amount to move forward
+ int durationInDays = (int) (((end.getTime()) - start.getTime()) / DateConstants.DAYINMILLIS);
+ durationInDays++;
+
+ // set new start and end times
+ Calendar javaCalendar = Calendar.getInstance();
+ javaCalendar.setTime(start);
+ javaCalendar.add(java.util.Calendar.DATE, durationInDays);
+ Date newStart = javaCalendar.getTime();
+
+ javaCalendar.setTime(end);
+ javaCalendar.add(java.util.Calendar.DATE, durationInDays);
+ Date newEnd = javaCalendar.getTime();
+
+ setDates(event, newStart, newEnd);
+ }
+
+ /**
+ * Set the start and end dates for the event
+ *
+ * @param event
+ * The event that the start and end dates should be set
+ * @param start
+ * The start date
+ * @param end
+ * The end date
+ */
+ protected void setDates(ForwardEvent event, Date start, Date end) {
+ event.getComponent().setStartDate(start);
+ event.getComponent().setEndDate(end);
+ }
+}
diff --git a/server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java b/server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java
new file mode 100644
index 0000000000..846fd7dd53
--- /dev/null
+++ b/server/src/com/vaadin/ui/components/calendar/handler/BasicWeekClickHandler.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.ui.components.calendar.handler;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClickHandler;
+
+/**
+ * Implements basic functionality needed to change to week view when a week
+ * number is clicked.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+@SuppressWarnings("serial")
+public class BasicWeekClickHandler implements WeekClickHandler {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClickHandler
+ * #weekClick
+ * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClick)
+ */
+ @Override
+ public void weekClick(WeekClick event) {
+ int week = event.getWeek();
+ int year = event.getYear();
+
+ // set correct year and month
+ Calendar javaCalendar = event.getComponent().getInternalCalendar();
+ javaCalendar.set(GregorianCalendar.YEAR, year);
+ javaCalendar.set(GregorianCalendar.WEEK_OF_YEAR, week);
+
+ // starting at the beginning of the week
+ javaCalendar.set(GregorianCalendar.DAY_OF_WEEK,
+ javaCalendar.getFirstDayOfWeek());
+ Date start = javaCalendar.getTime();
+
+ // ending at the end of the week
+ javaCalendar.add(GregorianCalendar.DATE, 6);
+ Date end = javaCalendar.getTime();
+
+ setDates(event, start, end);
+
+ // times are automatically expanded, no need to worry about them
+ }
+
+ /**
+ * Set the start and end dates for the event
+ *
+ * @param event
+ * The event that the start and end dates should be set
+ * @param start
+ * The start date
+ * @param end
+ * The end date
+ */
+ protected void setDates(WeekClick event, Date start, Date end) {
+ event.getComponent().setStartDate(start);
+ event.getComponent().setEndDate(end);
+ }
+
+}
diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java
index 9e9855afdd..9123245033 100644
--- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java
+++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerGrid.java
@@ -187,6 +187,7 @@ public class ColorPickerGrid extends AbstractComponent implements ColorSelector
* @param listener
* The color change listener
*/
+ @Override
public void addColorChangeListener(ColorChangeListener listener) {
addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD);
}
@@ -202,6 +203,7 @@ public class ColorPickerGrid extends AbstractComponent implements ColorSelector
* @param listener
* The listener
*/
+ @Override
public void removeColorChangeListener(ColorChangeListener listener) {
removeListener(ColorChangeEvent.class, listener);
}
diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java
index e6edbcf40e..2902585f56 100644
--- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java
+++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerHistory.java
@@ -194,6 +194,7 @@ public class ColorPickerHistory extends CustomComponent implements
* @param listener
* The listener
*/
+ @Override
public void addColorChangeListener(ColorChangeListener listener) {
addListener(ColorChangeEvent.class, listener, COLOR_CHANGE_METHOD);
}
@@ -204,6 +205,7 @@ public class ColorPickerHistory extends CustomComponent implements
* @param listener
* The listener
*/
+ @Override
public void removeColorChangeListener(ColorChangeListener listener) {
removeListener(ColorChangeEvent.class, listener);
}
diff --git a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java
index c06ae9f6ff..fee52d1a24 100644
--- a/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java
+++ b/server/src/com/vaadin/ui/components/colorpicker/ColorPickerPopup.java
@@ -283,6 +283,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
}
redSlider.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
double red = (Double) event.getProperty().getValue();
if (!updatingColors) {
@@ -303,6 +304,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
}
greenSlider.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
double green = (Double) event.getProperty().getValue();
if (!updatingColors) {
@@ -322,6 +324,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
}
blueSlider.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
double blue = (Double) event.getProperty().getValue();
if (!updatingColors) {
@@ -380,6 +383,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
hueSlider.setWidth("220px");
hueSlider.setImmediate(true);
hueSlider.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
if (!updatingColors) {
float hue = (Float.parseFloat(event.getProperty()
@@ -417,6 +421,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
saturationSlider.setWidth("220px");
saturationSlider.setImmediate(true);
saturationSlider.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
if (!updatingColors) {
float hue = (Float.parseFloat(hueSlider.getValue()
@@ -444,6 +449,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
valueSlider.setWidth("220px");
valueSlider.setImmediate(true);
valueSlider.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
if (!updatingColors) {
float hue = (Float.parseFloat(hueSlider.getValue()
@@ -754,6 +760,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
/** HSV color converter */
Coordinates2Color HSVConverter = new Coordinates2Color() {
+ @Override
public int[] calculate(Color color) {
float[] hsv = color.getHSV();
@@ -769,6 +776,7 @@ public class ColorPickerPopup extends Window implements ClickListener,
return new int[] { x, y };
}
+ @Override
public Color calculate(int x, int y) {
float saturation = 1f - (y / 220.0f);
float value = (x / 220.0f);
diff --git a/server/src/com/vaadin/util/CurrentInstance.java b/server/src/com/vaadin/util/CurrentInstance.java
index 595c162e7e..60489d596e 100644
--- a/server/src/com/vaadin/util/CurrentInstance.java
+++ b/server/src/com/vaadin/util/CurrentInstance.java
@@ -21,8 +21,28 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
+import com.vaadin.server.VaadinPortlet;
+import com.vaadin.server.VaadinPortletService;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinResponse;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinServlet;
+import com.vaadin.server.VaadinServletService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.ui.UI;
+
/**
* Keeps track of various thread local instances used by the framework.
+ * <p>
+ * Currently the framework uses the following instances:
+ * </p>
+ * <p>
+ * Inheritable: {@link UI}, {@link VaadinPortlet}, {@link VaadinService},
+ * {@link VaadinServlet}, {@link VaadinSession}.
+ * </p>
+ * <p>
+ * Non-inheritable: {@link VaadinRequest}, {@link VaadinResponse}.
+ * </p>
*
* @author Vaadin Ltd
* @version @VERSION@
@@ -32,6 +52,18 @@ public class CurrentInstance implements Serializable {
private final Object instance;
private final boolean inheritable;
+ private static boolean portletAvailable = false;
+ {
+ try {
+ /*
+ * VaadinPortlet depends on portlet API which is available only if
+ * running in a portal.
+ */
+ portletAvailable = (VaadinPortlet.class.getName() != null);
+ } catch (Throwable t) {
+ }
+ }
+
private static InheritableThreadLocal<Map<Class<?>, CurrentInstance>> instances = new InheritableThreadLocal<Map<Class<?>, CurrentInstance>>() {
@Override
protected Map<Class<?>, CurrentInstance> childValue(
@@ -135,7 +167,11 @@ public class CurrentInstance implements Serializable {
new CurrentInstance(instance, inheritable));
if (previousInstance != null) {
assert previousInstance.inheritable == inheritable : "Inheritable status mismatch for "
- + type;
+ + type
+ + " (previous was "
+ + previousInstance.inheritable
+ + ", new is "
+ + inheritable + ")";
}
}
}
@@ -146,4 +182,72 @@ public class CurrentInstance implements Serializable {
public static void clearAll() {
instances.remove();
}
+
+ /**
+ * Restores the given thread locals to the given values. Note that this
+ * should only be used internally to restore Vaadin classes.
+ *
+ * @param old
+ * A Class -> Object map to set as thread locals
+ */
+ public static void restoreThreadLocals(Map<Class<?>, CurrentInstance> old) {
+ for (Class c : old.keySet()) {
+ CurrentInstance ci = old.get(c);
+ set(c, ci.instance, ci.inheritable);
+ }
+ }
+
+ /**
+ * Sets thread locals for the UI and all related classes
+ *
+ * @param ui
+ * The UI
+ * @return A map containing the old values of the thread locals this method
+ * updated.
+ */
+ public static Map<Class<?>, CurrentInstance> setThreadLocals(UI ui) {
+ Map<Class<?>, CurrentInstance> old = new HashMap<Class<?>, CurrentInstance>();
+ old.put(UI.class, new CurrentInstance(UI.getCurrent(), true));
+ UI.setCurrent(ui);
+ old.putAll(setThreadLocals(ui.getSession()));
+ return old;
+ }
+
+ /**
+ * Sets thread locals for the {@link VaadinSession} and all related classes
+ *
+ * @param session
+ * The VaadinSession
+ * @return A map containing the old values of the thread locals this method
+ * updated.
+ */
+ public static Map<Class<?>, CurrentInstance> setThreadLocals(
+ VaadinSession session) {
+ Map<Class<?>, CurrentInstance> old = new HashMap<Class<?>, CurrentInstance>();
+ old.put(VaadinSession.class,
+ new CurrentInstance(VaadinSession.getCurrent(), true));
+ old.put(VaadinService.class,
+ new CurrentInstance(VaadinService.getCurrent(), true));
+ VaadinService service = null;
+ if (session != null) {
+ service = session.getService();
+ }
+
+ VaadinSession.setCurrent(session);
+ VaadinService.setCurrent(service);
+
+ if (service instanceof VaadinServletService) {
+ old.put(VaadinServlet.class,
+ new CurrentInstance(VaadinServlet.getCurrent(), true));
+ VaadinServlet.setCurrent(((VaadinServletService) service)
+ .getServlet());
+ } else if (portletAvailable && service instanceof VaadinPortletService) {
+ old.put(VaadinPortlet.class,
+ new CurrentInstance(VaadinPortlet.getCurrent(), true));
+ VaadinPortlet.setCurrent(((VaadinPortletService) service)
+ .getPortlet());
+ }
+
+ return old;
+ }
}
diff --git a/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java b/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java
new file mode 100644
index 0000000000..b319c13e4e
--- /dev/null
+++ b/server/tests/src/com/vaadin/data/DefaultFieldGroupFieldFactoryTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data;
+
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.data.fieldgroup.DefaultFieldGroupFieldFactory;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.PopupDateField;
+import com.vaadin.ui.TextField;
+
+public class DefaultFieldGroupFieldFactoryTest {
+
+ private DefaultFieldGroupFieldFactory fieldFactory;
+
+ @Before
+ public void setupFieldFactory() {
+ fieldFactory = new DefaultFieldGroupFieldFactory();
+ }
+
+ @Test
+ public void testDateGenerationForPopupDateField() {
+ Field f = fieldFactory.createField(Date.class, DateField.class);
+ Assert.assertNotNull(f);
+ Assert.assertEquals(PopupDateField.class, f.getClass());
+ }
+
+ @Test
+ public void testDateGenerationForInlineDateField() {
+ Field f = fieldFactory.createField(Date.class, InlineDateField.class);
+ Assert.assertNotNull(f);
+ Assert.assertEquals(InlineDateField.class, f.getClass());
+ }
+
+ @Test
+ public void testDateGenerationForTextField() {
+ Field f = fieldFactory.createField(Date.class, TextField.class);
+ Assert.assertNotNull(f);
+ Assert.assertEquals(TextField.class, f.getClass());
+ }
+
+ @Test
+ public void testDateGenerationForField() {
+ Field f = fieldFactory.createField(Date.class, Field.class);
+ Assert.assertNotNull(f);
+ Assert.assertEquals(PopupDateField.class, f.getClass());
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java
new file mode 100644
index 0000000000..e11b6e50f8
--- /dev/null
+++ b/server/tests/src/com/vaadin/data/fieldgroup/FieldGroupDate.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.data.fieldgroup;
+
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.ui.Field;
+import com.vaadin.ui.PopupDateField;
+
+public class FieldGroupDate {
+
+ private FieldGroup fieldGroup;
+
+ public class TestBean {
+ private Date javaDate;
+ private java.sql.Date sqlDate;
+
+ public TestBean(Date javaDate, java.sql.Date sqlDate) {
+ super();
+ this.javaDate = javaDate;
+ this.sqlDate = sqlDate;
+ }
+
+ public java.sql.Date getSqlDate() {
+ return sqlDate;
+ }
+
+ public void setSqlDate(java.sql.Date sqlDate) {
+ this.sqlDate = sqlDate;
+ }
+
+ public Date getJavaDate() {
+ return javaDate;
+ }
+
+ public void setJavaDate(Date date) {
+ javaDate = date;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ @Before
+ public void setup() {
+ fieldGroup = new FieldGroup();
+ fieldGroup.setItemDataSource(new BeanItem<TestBean>(new TestBean(
+ new Date(2010, 5, 7), new java.sql.Date(2011, 6, 8))));
+ }
+
+ @Test
+ public void testBuildAndBindDate() {
+ Field f = fieldGroup.buildAndBind("javaDate");
+ Assert.assertNotNull(f);
+ Assert.assertEquals(PopupDateField.class, f.getClass());
+ }
+
+ @Test
+ public void testBuildAndBindSqlDate() {
+ Field f = fieldGroup.buildAndBind("sqlDate");
+ Assert.assertNotNull(f);
+ Assert.assertEquals(PopupDateField.class, f.getClass());
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/data/util/AbstractContainerTest.java b/server/tests/src/com/vaadin/data/util/AbstractContainerTest.java
index f04acf8c46..81c90ba07b 100644
--- a/server/tests/src/com/vaadin/data/util/AbstractContainerTest.java
+++ b/server/tests/src/com/vaadin/data/util/AbstractContainerTest.java
@@ -314,8 +314,12 @@ public abstract class AbstractContainerTest extends TestCase {
initializeContainer(container);
// Filter by "contains ab"
- container.addContainerFilter(new SimpleStringFilter(
- FULLY_QUALIFIED_NAME, "ab", false, false));
+ SimpleStringFilter filter1 = new SimpleStringFilter(
+ FULLY_QUALIFIED_NAME, "ab", false, false);
+ container.addContainerFilter(filter1);
+
+ assertTrue(container.getContainerFilters().size() == 1);
+ assertEquals(filter1, container.getContainerFilters().iterator().next());
validateContainer(container, "com.vaadin.data.BufferedValidatable",
"com.vaadin.ui.TabSheet",
@@ -324,15 +328,21 @@ public abstract class AbstractContainerTest extends TestCase {
// Filter by "contains da" (reversed as ad here)
container.removeAllContainerFilters();
- container.addContainerFilter(new SimpleStringFilter(
- REVERSE_FULLY_QUALIFIED_NAME, "ad", false, false));
+
+ assertTrue(container.getContainerFilters().isEmpty());
+
+ SimpleStringFilter filter2 = new SimpleStringFilter(
+ REVERSE_FULLY_QUALIFIED_NAME, "ad", false, false);
+ container.addContainerFilter(filter2);
+
+ assertTrue(container.getContainerFilters().size() == 1);
+ assertEquals(filter2, container.getContainerFilters().iterator().next());
validateContainer(container, "com.vaadin.data.Buffered",
"com.vaadin.server.ComponentSizeValidator",
"com.vaadin.data.util.IndexedContainer",
"com.vaadin.terminal.gwt.client.ui.VUriFragmentUtility",
isFilteredOutItemNull(), 37);
-
}
/**
diff --git a/server/tests/src/com/vaadin/data/util/ReflectToolsGetSuperField.java b/server/tests/src/com/vaadin/data/util/ReflectToolsGetSuperField.java
index efba6085ac..dc828689a8 100644
--- a/server/tests/src/com/vaadin/data/util/ReflectToolsGetSuperField.java
+++ b/server/tests/src/com/vaadin/data/util/ReflectToolsGetSuperField.java
@@ -19,15 +19,16 @@ public class ReflectToolsGetSuperField {
class MySubClass extends MyClass {
// no fields here
}
-
+
PropertysetItem item = new PropertysetItem();
- item.addItemProperty("testProperty", new ObjectProperty<String>("Value of testProperty"));
-
+ item.addItemProperty("testProperty", new ObjectProperty<String>(
+ "Value of testProperty"));
+
MySubClass form = new MySubClass();
-
+
FieldGroup binder = new FieldGroup(item);
binder.bindMemberFields(form);
-
+
assertTrue("Value of testProperty".equals(form.test.getValue()));
}
diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLTestsConstants.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLTestsConstants.java
index 786903f1d0..1e96d59ed5 100755
--- a/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLTestsConstants.java
+++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/SQLTestsConstants.java
@@ -45,6 +45,10 @@ public class SQLTestsConstants {
public static String peopleFirst;
public static String peopleSecond;
public static String peopleThird;
+ /* Schema test creation statement(s) */
+ public static String createSchema;
+ public static String createProductTable;
+ public static String dropSchema;
/* Versioned -test table createion statement(s) */
public static String[] versionStatements;
/* SQL Generator used during the testing */
@@ -66,6 +70,10 @@ public class SQLTestsConstants {
versionStatements = new String[] {
"create table versioned (id integer generated always as identity, text varchar(255), version tinyint default 0)",
"alter table versioned add primary key (id)" };
+ // TODO these should ideally exist for all databases
+ createSchema = "create schema oaas authorization DBA";
+ createProductTable = "create table oaas.product (\"ID\" integer generated always as identity primary key, \"NAME\" VARCHAR(32))";
+ dropSchema = "drop schema if exists oaas cascade";
break;
case MYSQL:
offset = 1;
@@ -104,6 +112,9 @@ public class SQLTestsConstants {
"CREATE TRIGGER \"mytable_modify_dt_tr\" BEFORE UPDATE"
+ " ON VERSIONED FOR EACH ROW"
+ " EXECUTE PROCEDURE \"public\".\"zz_row_version\"();" };
+ createSchema = "create schema oaas";
+ createProductTable = "create table oaas.product (\"ID\" serial primary key, \"NAME\" VARCHAR(32))";
+ dropSchema = "drop schema oaas cascade";
break;
case MSSQL:
offset = 1;
diff --git a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java
index 54db34dfd2..c275cd4363 100644
--- a/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java
+++ b/server/tests/src/com/vaadin/data/util/sqlcontainer/query/TableQueryTest.java
@@ -661,4 +661,77 @@ public class TableQueryTest {
container.commit();
}
+ @Test
+ public void construction_explicitSchema_shouldSucceed() throws SQLException {
+ if (SQLTestsConstants.createSchema == null
+ || SQLTestsConstants.createProductTable == null
+ || SQLTestsConstants.dropSchema == null) {
+ // only perform the test on the databases for which the setup and
+ // cleanup statements are available
+ return;
+ }
+
+ // create schema "oaas" and table "product" in it
+ Connection conn = connectionPool.reserveConnection();
+ Statement statement = conn.createStatement();
+ try {
+ statement.execute(SQLTestsConstants.dropSchema);
+ } catch (SQLException e) {
+ // May fail if schema doesn't exist, which is OK.
+ conn.rollback();
+ }
+ statement.execute(SQLTestsConstants.createSchema);
+ statement.execute(SQLTestsConstants.createProductTable);
+ conn.commit();
+
+ try {
+ // metadata scanning at query creation time should not fail
+ TableQuery tq1 = new TableQuery(null, "oaas", "product",
+ connectionPool, SQLTestsConstants.sqlGen);
+ Assert.assertNotNull(tq1);
+ } finally {
+ // cleanup - might not be an in-memory DB
+ statement.execute(SQLTestsConstants.dropSchema);
+ }
+ }
+
+ @Test
+ public void construction_explicitCatalogAndSchema_shouldSucceed()
+ throws SQLException {
+ // not all databases support explicit catalogs, test with PostgreSQL
+ // using database name as catalog
+ if (SQLTestsConstants.db != SQLTestsConstants.DB.POSTGRESQL
+ || SQLTestsConstants.createSchema == null
+ || SQLTestsConstants.createProductTable == null
+ || SQLTestsConstants.dropSchema == null) {
+ // only perform the test on the databases for which the setup and
+ // cleanup statements are available
+ return;
+ }
+
+ // create schema "oaas" and table "product" in it
+ Connection conn = connectionPool.reserveConnection();
+ Statement statement = conn.createStatement();
+ try {
+ statement.execute(SQLTestsConstants.dropSchema);
+ } catch (SQLException e) {
+ // May fail if schema doesn't exist, which is OK.
+ conn.rollback();
+ }
+ statement.execute(SQLTestsConstants.createSchema);
+ statement.execute(SQLTestsConstants.createProductTable);
+ conn.commit();
+
+ try {
+ // metadata scanning at query creation time should not fail
+ // note that for most DBMS, catalog is just an optional database
+ // name
+ TableQuery tq1 = new TableQuery("sqlcontainer", "oaas", "product",
+ connectionPool, SQLTestsConstants.sqlGen);
+ Assert.assertNotNull(tq1);
+ } finally {
+ // cleanup - might not be an in-memory DB
+ statement.execute(SQLTestsConstants.dropSchema);
+ }
+ }
} \ No newline at end of file
diff --git a/server/tests/src/com/vaadin/server/TestAbstractApplicationServletStaticFilesLocation.java b/server/tests/src/com/vaadin/server/TestAbstractApplicationServletStaticFilesLocation.java
index c7330001d3..2a83f5d5b2 100644
--- a/server/tests/src/com/vaadin/server/TestAbstractApplicationServletStaticFilesLocation.java
+++ b/server/tests/src/com/vaadin/server/TestAbstractApplicationServletStaticFilesLocation.java
@@ -28,9 +28,11 @@ public class TestAbstractApplicationServletStaticFilesLocation extends TestCase
// Workaround to avoid calling init and creating servlet config
Field f = VaadinServlet.class.getDeclaredField("servletService");
f.setAccessible(true);
- f.set(servlet, new VaadinServletService(servlet,
+ VaadinServletService service = new VaadinServletService(servlet,
new DefaultDeploymentConfiguration(servlet.getClass(),
- new Properties())));
+ new Properties()));
+ service.init();
+ f.set(servlet, service);
}
diff --git a/server/tests/src/com/vaadin/server/VaadinSessionTest.java b/server/tests/src/com/vaadin/server/VaadinSessionTest.java
new file mode 100644
index 0000000000..61a1581a6f
--- /dev/null
+++ b/server/tests/src/com/vaadin/server/VaadinSessionTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.server;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionBindingEvent;
+
+import junit.framework.Assert;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.server.ClientConnector.DetachEvent;
+import com.vaadin.server.ClientConnector.DetachListener;
+import com.vaadin.tests.util.MockDeploymentConfiguration;
+import com.vaadin.ui.UI;
+import com.vaadin.util.CurrentInstance;
+
+public class VaadinSessionTest {
+
+ private VaadinSession session;
+ private VaadinServlet mockServlet;
+ private VaadinServletService mockService;
+ private HttpSession mockHttpSession;
+ private WrappedSession mockWrappedSession;
+ private VaadinServletRequest vaadinRequest;
+ private UI ui;
+
+ @Before
+ public void setup() throws Exception {
+ mockServlet = new VaadinServlet() {
+ @Override
+ public String getServletName() {
+ return "mockServlet";
+ };
+ };
+
+ mockService = new VaadinServletService(mockServlet,
+ new MockDeploymentConfiguration());
+ mockService.init();
+
+ mockHttpSession = EasyMock.createMock(HttpSession.class);
+ mockWrappedSession = new WrappedHttpSession(mockHttpSession) {
+ final ReentrantLock lock = new ReentrantLock();
+
+ @Override
+ public Object getAttribute(String name) {
+ if ("mockServlet.lock".equals(name)) {
+ return lock;
+ }
+ return super.getAttribute(name);
+ }
+ };
+
+ session = new VaadinSession(mockService);
+ session.storeInSession(mockService, mockWrappedSession);
+
+ ui = new UI() {
+ Page page = new Page(this, getState(false).pageState) {
+ @Override
+ public void init(VaadinRequest request) {
+ }
+ };
+
+ @Override
+ protected void init(VaadinRequest request) {
+ }
+
+ @Override
+ public Page getPage() {
+ return page;
+ }
+ };
+ vaadinRequest = new VaadinServletRequest(
+ EasyMock.createMock(HttpServletRequest.class), mockService) {
+ @Override
+ public String getParameter(String name) {
+ if ("theme".equals(name)) {
+ return null;
+ }
+
+ return super.getParameter(name);
+ }
+ };
+
+ ui.doInit(vaadinRequest, session.getNextUIid());
+
+ ui.setSession(session);
+ session.addUI(ui);
+
+ }
+
+ @Test
+ public void threadLocalsAfterUnderlyingSessionTimeout() {
+
+ final AtomicBoolean detachCalled = new AtomicBoolean(false);
+ ui.addDetachListener(new DetachListener() {
+ @Override
+ public void detach(DetachEvent event) {
+ detachCalled.set(true);
+ Assert.assertEquals(ui, UI.getCurrent());
+ Assert.assertEquals(ui.getPage(), Page.getCurrent());
+ Assert.assertEquals(session, VaadinSession.getCurrent());
+ Assert.assertEquals(mockService, VaadinService.getCurrent());
+ Assert.assertEquals(mockServlet, VaadinServlet.getCurrent());
+ }
+ });
+
+ session.valueUnbound(EasyMock.createMock(HttpSessionBindingEvent.class));
+ Assert.assertTrue(detachCalled.get());
+ }
+
+ @Test
+ public void threadLocalsAfterSessionDestroy() {
+ final AtomicBoolean detachCalled = new AtomicBoolean(false);
+ ui.addDetachListener(new DetachListener() {
+ @Override
+ public void detach(DetachEvent event) {
+ detachCalled.set(true);
+ Assert.assertEquals(ui, UI.getCurrent());
+ Assert.assertEquals(ui.getPage(), Page.getCurrent());
+ Assert.assertEquals(session, VaadinSession.getCurrent());
+ Assert.assertEquals(mockService, VaadinService.getCurrent());
+ Assert.assertEquals(mockServlet, VaadinServlet.getCurrent());
+ }
+ });
+ CurrentInstance.clearAll();
+ session.close();
+ mockService.cleanupSession(session);
+ Assert.assertTrue(detachCalled.get());
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/data/converter/ConverterFactory.java b/server/tests/src/com/vaadin/tests/data/converter/ConverterFactory.java
index 5067da8861..9da8406507 100644
--- a/server/tests/src/com/vaadin/tests/data/converter/ConverterFactory.java
+++ b/server/tests/src/com/vaadin/tests/data/converter/ConverterFactory.java
@@ -22,6 +22,7 @@ import junit.framework.TestCase;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.DefaultConverterFactory;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.TextField;
public class ConverterFactory extends TestCase {
@@ -66,7 +67,7 @@ public class ConverterFactory extends TestCase {
public void testApplicationConverterFactoryInBackgroundThread() {
VaadinSession.setCurrent(null);
- final VaadinSession appWithCustomIntegerConverter = new VaadinSession(
+ final VaadinSession appWithCustomIntegerConverter = new AlwaysLockedVaadinSession(
null);
appWithCustomIntegerConverter
.setConverterFactory(new ConverterFactory42());
@@ -84,7 +85,7 @@ public class ConverterFactory extends TestCase {
}
public void testApplicationConverterFactoryForDetachedComponent() {
- final VaadinSession appWithCustomIntegerConverter = new VaadinSession(
+ final VaadinSession appWithCustomIntegerConverter = new AlwaysLockedVaadinSession(
null);
appWithCustomIntegerConverter
.setConverterFactory(new ConverterFactory42());
@@ -98,11 +99,11 @@ public class ConverterFactory extends TestCase {
}
public void testApplicationConverterFactoryForDifferentThanCurrentApplication() {
- final VaadinSession fieldAppWithCustomIntegerConverter = new VaadinSession(
+ final VaadinSession fieldAppWithCustomIntegerConverter = new AlwaysLockedVaadinSession(
null);
fieldAppWithCustomIntegerConverter
.setConverterFactory(new ConverterFactory42());
- VaadinSession.setCurrent(new VaadinSession(null));
+ VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null));
TextField tf = new TextField("", "123") {
@Override
diff --git a/server/tests/src/com/vaadin/tests/data/validator/TestStringLengthValidator.java b/server/tests/src/com/vaadin/tests/data/validator/TestStringLengthValidator.java
index 032b8b6d14..6b4b2b0d51 100644
--- a/server/tests/src/com/vaadin/tests/data/validator/TestStringLengthValidator.java
+++ b/server/tests/src/com/vaadin/tests/data/validator/TestStringLengthValidator.java
@@ -45,7 +45,7 @@ public class TestStringLengthValidator extends TestCase {
validatorMinValue
.isValid("This is a really long string to test that no upper bound exists"));
}
-
+
public void testNoLowerBound() {
assertTrue("Didn't accept short string", validatorMaxValue.isValid(""));
assertTrue("Didn't accept short string", validatorMaxValue.isValid("1"));
diff --git a/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java b/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java
new file mode 100644
index 0000000000..5c27ef0752
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/TestAtmosphereVersion.java
@@ -0,0 +1,18 @@
+package com.vaadin.tests.server;
+
+import junit.framework.TestCase;
+
+import org.atmosphere.util.Version;
+
+import com.vaadin.server.Constants;
+
+public class TestAtmosphereVersion extends TestCase {
+ /**
+ * Test that the atmosphere version constant matches the version on our
+ * classpath
+ */
+ public void testAtmosphereVersion() {
+ assertEquals(Constants.REQUIRED_ATMOSPHERE_VERSION,
+ Version.getRawVersion());
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java
index 3172b759a1..90cb6b9994 100644
--- a/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java
+++ b/server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java
@@ -45,9 +45,7 @@ public class TestClassesSerializable extends TestCase {
"com\\.vaadin\\.util\\.SerializerHelper", // fully static
// class level filtering, also affecting nested classes and
// interfaces
- "com\\.vaadin\\.server\\.AbstractCommunicationManager.*", //
- "com\\.vaadin\\.server\\.CommunicationManager.*", //
- "com\\.vaadin\\.server\\.PortletCommunicationManager.*", //
+ "com\\.vaadin\\.server\\.LegacyCommunicationManager.*", //
"com\\.vaadin\\.buildhelpers.*", //
"com\\.vaadin\\.util\\.ReflectTools.*", //
"com\\.vaadin\\.data\\.util\\.ReflectTools.*", //
diff --git a/server/tests/src/com/vaadin/tests/server/TestSimpleMultiPartInputStream.java b/server/tests/src/com/vaadin/tests/server/TestSimpleMultiPartInputStream.java
index 84247c81c1..6907594b5e 100644
--- a/server/tests/src/com/vaadin/tests/server/TestSimpleMultiPartInputStream.java
+++ b/server/tests/src/com/vaadin/tests/server/TestSimpleMultiPartInputStream.java
@@ -7,7 +7,7 @@ import java.util.Arrays;
import junit.framework.TestCase;
-import com.vaadin.server.AbstractCommunicationManager.SimpleMultiPartInputStream;
+import com.vaadin.server.communication.FileUploadHandler.SimpleMultiPartInputStream;
public class TestSimpleMultiPartInputStream extends TestCase {
diff --git a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
index 467a76dfa6..bee932a29f 100644
--- a/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
+++ b/server/tests/src/com/vaadin/tests/server/TestStreamVariableMapping.java
@@ -4,10 +4,14 @@ import junit.framework.TestCase;
import org.easymock.EasyMock;
-import com.vaadin.server.CommunicationManager;
+import com.vaadin.server.LegacyCommunicationManager;
import com.vaadin.server.StreamVariable;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinServlet;
+import com.vaadin.server.VaadinServletService;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
+import com.vaadin.tests.util.MockDeploymentConfiguration;
import com.vaadin.ui.ConnectorTracker;
import com.vaadin.ui.UI;
import com.vaadin.ui.Upload;
@@ -18,11 +22,11 @@ public class TestStreamVariableMapping extends TestCase {
private Upload owner;
private StreamVariable streamVariable;
- private CommunicationManager cm;
+ private LegacyCommunicationManager cm;
@Override
protected void setUp() throws Exception {
- final VaadinSession application = new VaadinSession(null);
+ final VaadinSession application = new AlwaysLockedVaadinSession(null);
final UI uI = new UI() {
@Override
protected void init(VaadinRequest request) {
@@ -67,13 +71,19 @@ public class TestStreamVariableMapping extends TestCase {
assertNotNull(tracker.getStreamVariable(owner.getConnectorId(),
variableName));
- cm.cleanStreamVariable(owner, variableName);
+ tracker.cleanStreamVariable(owner.getConnectorId(), variableName);
assertNull(tracker.getStreamVariable(owner.getConnectorId(),
variableName));
}
- private CommunicationManager createCommunicationManager() {
- return new CommunicationManager(new VaadinSession(null));
+ private LegacyCommunicationManager createCommunicationManager()
+ throws Exception {
+ VaadinServletService vss = new VaadinServletService(
+ EasyMock.createMock(VaadinServlet.class),
+ new MockDeploymentConfiguration());
+ vss.init();
+ return new LegacyCommunicationManager(
+ new AlwaysLockedVaadinSession(vss));
}
}
diff --git a/server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java b/server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java
index 8a61ec6352..bd7053af40 100644
--- a/server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java
+++ b/server/tests/src/com/vaadin/tests/server/clientconnector/AttachDetachListeners.java
@@ -18,6 +18,7 @@ import com.vaadin.server.ClientConnector.DetachListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.Label;
@@ -40,7 +41,8 @@ public class AttachDetachListeners {
public void setUp() {
control = EasyMock.createStrictControl();
- session = new VaadinSession(control.createMock(VaadinService.class));
+ session = new AlwaysLockedVaadinSession(
+ control.createMock(VaadinService.class));
ui = new UI() {
@Override
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java
index cd77101ac3..3c4d43543b 100644
--- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/AbstractFieldValueConversions.java
@@ -17,6 +17,7 @@ import com.vaadin.tests.data.bean.Address;
import com.vaadin.tests.data.bean.Country;
import com.vaadin.tests.data.bean.Person;
import com.vaadin.tests.data.bean.Sex;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.TextField;
@@ -45,7 +46,7 @@ public class AbstractFieldValueConversions extends TestCase {
}
public void testNonmodifiedBufferedFieldConversion() {
- VaadinSession.setCurrent(new VaadinSession(null));
+ VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null));
TextField tf = new TextField("salary");
tf.setBuffered(true);
tf.setLocale(new Locale("en", "US"));
@@ -61,7 +62,7 @@ public class AbstractFieldValueConversions extends TestCase {
}
public void testModifiedBufferedFieldConversion() {
- VaadinSession.setCurrent(new VaadinSession(null));
+ VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null));
TextField tf = new TextField("salary");
tf.setBuffered(true);
tf.setLocale(new Locale("en", "US"));
@@ -129,7 +130,7 @@ public class AbstractFieldValueConversions extends TestCase {
}
public void testChangeReadOnlyFieldLocale() {
- VaadinSession.setCurrent(new VaadinSession(null));
+ VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null));
TextField tf = new TextField("salary");
tf.setLocale(new Locale("en", "US"));
@@ -214,7 +215,7 @@ public class AbstractFieldValueConversions extends TestCase {
}
public void testNumberDoubleConverterChange() {
- final VaadinSession a = new VaadinSession(null);
+ final VaadinSession a = new AlwaysLockedVaadinSession(null);
VaadinSession.setCurrent(a);
TextField tf = new TextField() {
@Override
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java
index 698e9bcee4..bac024725f 100644
--- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/DefaultConverterFactory.java
@@ -11,6 +11,7 @@ import com.vaadin.tests.data.bean.Address;
import com.vaadin.tests.data.bean.Country;
import com.vaadin.tests.data.bean.Person;
import com.vaadin.tests.data.bean.Sex;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.TextField;
public class DefaultConverterFactory extends TestCase {
@@ -53,7 +54,7 @@ public class DefaultConverterFactory extends TestCase {
}
public void testFloatConversion() {
- VaadinSession sess = new VaadinSession(null);
+ VaadinSession sess = new AlwaysLockedVaadinSession(null);
VaadinSession.setCurrent(sess);
TextField tf = new TextField();
@@ -68,7 +69,7 @@ public class DefaultConverterFactory extends TestCase {
}
public void testDefaultNumberConversion() {
- VaadinSession app = new VaadinSession(null);
+ VaadinSession app = new AlwaysLockedVaadinSession(null);
VaadinSession.setCurrent(app);
TextField tf = new TextField();
tf.setLocale(new Locale("en", "US"));
diff --git a/server/tests/src/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java b/server/tests/src/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java
index cd9b6c6631..fcf17cc499 100644
--- a/server/tests/src/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java
+++ b/server/tests/src/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java
@@ -9,6 +9,7 @@ import com.vaadin.data.util.AbstractProperty;
import com.vaadin.data.util.converter.Converter.ConversionException;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.UI;
@@ -18,7 +19,8 @@ public class RemoveListenersOnDetach {
int numReadOnlyChanges = 0;
AbstractField field = new AbstractField() {
- final private VaadinSession application = new VaadinSession(null);
+ final private VaadinSession application = new AlwaysLockedVaadinSession(
+ null);
private UI uI = new UI() {
@Override
diff --git a/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java b/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java
new file mode 100644
index 0000000000..5926cfa1ca
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/calendar/CalendarBasics.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.server.component.calendar;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.junit.Test;
+
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.Calendar.TimeFormat;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventResize;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.MoveEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClick;
+import com.vaadin.ui.components.calendar.event.BasicEventProvider;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider;
+
+/**
+ * Basic API tests for the calendar
+ */
+public class CalendarBasics {
+
+ @Test
+ public void testEmptyConstructorInitialization() {
+
+ Calendar calendar = new Calendar();
+
+ // The calendar should have a basic event provider with no events
+ CalendarEventProvider provider = calendar.getEventProvider();
+ assertNotNull("Event provider should not be null", provider);
+
+ // Basic event handlers should be registered
+ assertNotNull(calendar.getHandler(BackwardEvent.EVENT_ID));
+ assertNotNull(calendar.getHandler(ForwardEvent.EVENT_ID));
+ assertNotNull(calendar.getHandler(WeekClick.EVENT_ID));
+ assertNotNull(calendar.getHandler(DateClickEvent.EVENT_ID));
+ assertNotNull(calendar.getHandler(MoveEvent.EVENT_ID));
+ assertNotNull(calendar.getHandler(EventResize.EVENT_ID));
+
+ // Calendar should have undefined size
+ assertTrue(calendar.getWidth() < 0);
+ assertTrue(calendar.getHeight() < 0);
+ }
+
+ @Test
+ public void testConstructorWithCaption() {
+ final String caption = "My Calendar Caption";
+ Calendar calendar = new Calendar(caption);
+ assertEquals(caption, calendar.getCaption());
+ }
+
+ @Test
+ public void testConstructorWithCustomEventProvider() {
+ BasicEventProvider myProvider = new BasicEventProvider();
+ Calendar calendar = new Calendar(myProvider);
+ assertEquals(myProvider, calendar.getEventProvider());
+ }
+
+ @Test
+ public void testConstructorWithCustomEventProviderAndCaption() {
+ BasicEventProvider myProvider = new BasicEventProvider();
+ final String caption = "My Calendar Caption";
+ Calendar calendar = new Calendar(caption, myProvider);
+ assertEquals(caption, calendar.getCaption());
+ assertEquals(myProvider, calendar.getEventProvider());
+ }
+
+ @Test
+ public void testDefaultStartAndEndDates() {
+ Calendar calendar = new Calendar();
+
+ // If no start and end date is set the calendar will display the current
+ // week
+ java.util.Calendar c = new GregorianCalendar();
+ java.util.Calendar c2 = new GregorianCalendar();
+
+ c2.setTime(calendar.getStartDate());
+ assertEquals(c.getFirstDayOfWeek(),
+ c2.get(java.util.Calendar.DAY_OF_WEEK));
+ c2.setTime(calendar.getEndDate());
+
+ c.set(java.util.Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6);
+ assertEquals(c.get(java.util.Calendar.DAY_OF_WEEK),
+ c2.get(java.util.Calendar.DAY_OF_WEEK));
+ }
+
+ @Test
+ public void testCustomStartAndEndDates() {
+ Calendar calendar = new Calendar();
+ java.util.Calendar c = new GregorianCalendar();
+
+ Date start = c.getTime();
+ c.add(java.util.Calendar.DATE, 3);
+ Date end = c.getTime();
+
+ calendar.setStartDate(start);
+ calendar.setEndDate(end);
+
+ assertEquals(start.getTime(), calendar.getStartDate().getTime());
+ assertEquals(end.getTime(), calendar.getEndDate().getTime());
+ }
+
+ @Test
+ public void testCustomLocale() {
+ Calendar calendar = new Calendar();
+ calendar.setLocale(Locale.CANADA_FRENCH);
+
+ // Setting the locale should set the internal calendars locale
+ assertEquals(Locale.CANADA_FRENCH, calendar.getLocale());
+ java.util.Calendar c = new GregorianCalendar(Locale.CANADA_FRENCH);
+ assertEquals(c.getTimeZone().getRawOffset(), calendar
+ .getInternalCalendar().getTimeZone().getRawOffset());
+ }
+
+ @Test
+ public void testTimeFormat() {
+ Calendar calendar = new Calendar();
+
+ // The default timeformat depends on the current locale
+ calendar.setLocale(Locale.ENGLISH);
+ assertEquals(TimeFormat.Format12H, calendar.getTimeFormat());
+
+ calendar.setLocale(Locale.ITALIAN);
+ assertEquals(TimeFormat.Format24H, calendar.getTimeFormat());
+
+ // Setting a specific time format overrides the locale
+ calendar.setTimeFormat(TimeFormat.Format12H);
+ assertEquals(TimeFormat.Format12H, calendar.getTimeFormat());
+ }
+
+ @Test
+ public void testTimeZone() {
+ Calendar calendar = new Calendar();
+ calendar.setLocale(Locale.CANADA_FRENCH);
+
+ // By default the calendars timezone is returned
+ assertEquals(calendar.getInternalCalendar().getTimeZone(),
+ calendar.getTimeZone());
+
+ // One can override the default behaviour by specifying a timezone
+ TimeZone customTimeZone = TimeZone.getTimeZone("Europe/Helsinki");
+ calendar.setTimeZone(customTimeZone);
+ assertEquals(customTimeZone, calendar.getTimeZone());
+ }
+
+ @Test
+ public void testVisibleDaysOfWeek() {
+ Calendar calendar = new Calendar();
+
+ // The defaults are the whole week
+ assertEquals(1, calendar.getFirstVisibleDayOfWeek());
+ assertEquals(7, calendar.getLastVisibleDayOfWeek());
+
+ calendar.setFirstVisibleDayOfWeek(0); // Invalid input
+ assertEquals(1, calendar.getFirstVisibleDayOfWeek());
+
+ calendar.setLastVisibleDayOfWeek(0); // Invalid input
+ assertEquals(7, calendar.getLastVisibleDayOfWeek());
+
+ calendar.setFirstVisibleDayOfWeek(8); // Invalid input
+ assertEquals(1, calendar.getFirstVisibleDayOfWeek());
+
+ calendar.setLastVisibleDayOfWeek(8); // Invalid input
+ assertEquals(7, calendar.getLastVisibleDayOfWeek());
+
+ calendar.setFirstVisibleDayOfWeek(4);
+ assertEquals(4, calendar.getFirstVisibleDayOfWeek());
+
+ calendar.setLastVisibleDayOfWeek(6);
+ assertEquals(6, calendar.getLastVisibleDayOfWeek());
+
+ calendar.setFirstVisibleDayOfWeek(7); // Invalid since last day is 6
+ assertEquals(4, calendar.getFirstVisibleDayOfWeek());
+
+ calendar.setLastVisibleDayOfWeek(2); // Invalid since first day is 4
+ assertEquals(6, calendar.getLastVisibleDayOfWeek());
+ }
+
+ @Test
+ public void testVisibleHoursInDay() {
+ Calendar calendar = new Calendar();
+
+ // Defaults are the whole day
+ assertEquals(0, calendar.getFirstVisibleHourOfDay());
+ assertEquals(23, calendar.getLastVisibleHourOfDay());
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/calendar/ContainerDataSource.java b/server/tests/src/com/vaadin/tests/server/component/calendar/ContainerDataSource.java
new file mode 100644
index 0000000000..2bc95e371c
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/calendar/ContainerDataSource.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.server.component.calendar;
+
+import java.util.Date;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+import com.vaadin.data.Container.Indexed;
+import com.vaadin.data.Container.Sortable;
+import com.vaadin.data.Item;
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.components.calendar.ContainerEventProvider;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+
+public class ContainerDataSource extends TestCase {
+
+ private Calendar calendar;
+
+ @Override
+ public void setUp() {
+ calendar = new Calendar();
+ }
+
+ /**
+ * Tests adding a bean item container to the Calendar
+ */
+ @Test
+ public void testWithBeanItemContainer() {
+
+ // Create a container to use as a datasource
+ Indexed container = createTestBeanItemContainer();
+
+ // Set datasource
+ calendar.setContainerDataSource(container);
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.setTime(((CalendarEvent) container.getIdByIndex(0)).getStart());
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Test the all events are returned
+ List<CalendarEvent> events = calendar.getEventProvider().getEvents(
+ start, end);
+ assertEquals(container.size(), events.size());
+
+ // Test that a certain range is returned
+ cal.setTime(((CalendarEvent) container.getIdByIndex(6)).getStart());
+ end = cal.getTime();
+ events = calendar.getEventProvider().getEvents(start, end);
+ assertEquals(6, events.size());
+ }
+
+ /**
+ * This tests tests that if you give the Calendar an unsorted (== not sorted
+ * by starting date) container then the calendar should gracefully handle
+ * it. In this case the size of the container will be wrong. The test is
+ * exactly the same as {@link #testWithBeanItemContainer()} except that the
+ * beans has been intentionally sorted by caption instead of date.
+ */
+ @Test
+ public void testWithUnsortedBeanItemContainer() {
+ // Create a container to use as a datasource
+ Indexed container = createTestBeanItemContainer();
+
+ // Make the container sorted by caption
+ ((Sortable) container).sort(new Object[] { "caption" },
+ new boolean[] { true });
+
+ // Set data source
+ calendar.setContainerDataSource(container);
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.setTime(((CalendarEvent) container.getIdByIndex(0)).getStart());
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Test the all events are returned
+ List<CalendarEvent> events = calendar.getEventProvider().getEvents(
+ start, end);
+ assertEquals(container.size(), events.size());
+
+ // Test that a certain range is returned
+ cal.setTime(((CalendarEvent) container.getIdByIndex(6)).getStart());
+ end = cal.getTime();
+ events = calendar.getEventProvider().getEvents(start, end);
+
+ // The events size is 1 since the getEvents returns the wrong range
+ assertEquals(1, events.size());
+ }
+
+ /**
+ * Tests adding a Indexed container to the Calendar
+ */
+ @Test
+ public void testWithIndexedContainer() {
+
+ // Create a container to use as a datasource
+ Indexed container = createTestIndexedContainer();
+
+ // Set datasource
+ calendar.setContainerDataSource(container, "testCaption",
+ "testDescription", "testStartDate", "testEndDate", null);
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.setTime((Date) container.getItem(container.getIdByIndex(0))
+ .getItemProperty("testStartDate").getValue());
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Test the all events are returned
+ List<CalendarEvent> events = calendar.getEventProvider().getEvents(
+ start, end);
+ assertEquals(container.size(), events.size());
+
+ // Check that event values are present
+ CalendarEvent e = events.get(0);
+ assertEquals("Test 1", e.getCaption());
+ assertEquals("Description 1", e.getDescription());
+ assertTrue(e.getStart().compareTo(start) == 0);
+
+ // Test that a certain range is returned
+ cal.setTime((Date) container.getItem(container.getIdByIndex(6))
+ .getItemProperty("testStartDate").getValue());
+ end = cal.getTime();
+ events = calendar.getEventProvider().getEvents(start, end);
+ assertEquals(6, events.size());
+ }
+
+ @Test
+ public void testNullLimitsBeanItemContainer() {
+ // Create a container to use as a datasource
+ Indexed container = createTestBeanItemContainer();
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.setTime(((CalendarEvent) container.getIdByIndex(0)).getStart());
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Set datasource
+ calendar.setContainerDataSource(container);
+
+ // Test null start time
+ List<CalendarEvent> events = calendar.getEventProvider().getEvents(
+ null, end);
+ assertEquals(container.size(), events.size());
+
+ // Test null end time
+ events = calendar.getEventProvider().getEvents(start, null);
+ assertEquals(container.size(), events.size());
+
+ // Test both null times
+ events = calendar.getEventProvider().getEvents(null, null);
+ assertEquals(container.size(), events.size());
+ }
+
+ @Test
+ public void testNullLimitsIndexedContainer() {
+ // Create a container to use as a datasource
+ Indexed container = createTestIndexedContainer();
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.setTime((Date) container.getItem(container.getIdByIndex(0))
+ .getItemProperty("testStartDate").getValue());
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Set datasource
+ calendar.setContainerDataSource(container, "testCaption",
+ "testDescription", "testStartDate", "testEndDate", null);
+
+ // Test null start time
+ List<CalendarEvent> events = calendar.getEventProvider().getEvents(
+ null, end);
+ assertEquals(container.size(), events.size());
+
+ // Test null end time
+ events = calendar.getEventProvider().getEvents(start, null);
+ assertEquals(container.size(), events.size());
+
+ // Test both null times
+ events = calendar.getEventProvider().getEvents(null, null);
+ assertEquals(container.size(), events.size());
+ }
+
+ /**
+ * Tests the addEvent convenience method with the default event provider
+ */
+ @Test
+ public void testAddEventConvinienceMethod() {
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Ensure no events
+ assertEquals(0, calendar.getEvents(start, end).size());
+
+ // Add an event
+ BasicEvent event = new BasicEvent("Test", "Test", start);
+ calendar.addEvent(event);
+
+ // Ensure event exists
+ List<CalendarEvent> events = calendar.getEvents(start, end);
+ assertEquals(1, events.size());
+ assertEquals(events.get(0).getCaption(), event.getCaption());
+ assertEquals(events.get(0).getDescription(), event.getDescription());
+ assertEquals(events.get(0).getStart(), event.getStart());
+ }
+
+ /**
+ * Test the removeEvent convenience method with the default event provider
+ */
+ @Test
+ public void testRemoveEventConvinienceMethod() {
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Ensure no events
+ assertEquals(0, calendar.getEvents(start, end).size());
+
+ // Add an event
+ CalendarEvent event = new BasicEvent("Test", "Test", start);
+ calendar.addEvent(event);
+
+ // Ensure event exists
+ assertEquals(1, calendar.getEvents(start, end).size());
+
+ // Remove event
+ calendar.removeEvent(event);
+
+ // Ensure no events
+ assertEquals(0, calendar.getEvents(start, end).size());
+ }
+
+ @Test
+ public void testAddEventConvinienceMethodWithCustomEventProvider() {
+
+ // Use a container data source
+ calendar.setEventProvider(new ContainerEventProvider(
+ new BeanItemContainer<BasicEvent>(BasicEvent.class)));
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Ensure no events
+ assertEquals(0, calendar.getEvents(start, end).size());
+
+ // Add an event
+ BasicEvent event = new BasicEvent("Test", "Test", start);
+ calendar.addEvent(event);
+
+ // Ensure event exists
+ List<CalendarEvent> events = calendar.getEvents(start, end);
+ assertEquals(1, events.size());
+ assertEquals(events.get(0).getCaption(), event.getCaption());
+ assertEquals(events.get(0).getDescription(), event.getDescription());
+ assertEquals(events.get(0).getStart(), event.getStart());
+ }
+
+ @Test
+ public void testRemoveEventConvinienceMethodWithCustomEventProvider() {
+
+ // Use a container data source
+ calendar.setEventProvider(new ContainerEventProvider(
+ new BeanItemContainer<BasicEvent>(BasicEvent.class)));
+
+ // Start and end dates to query for
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ Date start = cal.getTime();
+ cal.add(java.util.Calendar.MONTH, 1);
+ Date end = cal.getTime();
+
+ // Ensure no events
+ assertEquals(0, calendar.getEvents(start, end).size());
+
+ // Add an event
+ BasicEvent event = new BasicEvent("Test", "Test", start);
+ calendar.addEvent(event);
+
+ // Ensure event exists
+ List<CalendarEvent> events = calendar.getEvents(start, end);
+ assertEquals(1, events.size());
+
+ // Remove event
+ calendar.removeEvent(event);
+
+ // Ensure no events
+ assertEquals(0, calendar.getEvents(start, end).size());
+ }
+
+ private static Indexed createTestBeanItemContainer() {
+ BeanItemContainer<CalendarEvent> eventContainer = new BeanItemContainer<CalendarEvent>(
+ CalendarEvent.class);
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ for (int i = 1; i <= 10; i++) {
+ eventContainer.addBean(new BasicEvent("Test " + i, "Description "
+ + i, cal.getTime()));
+ cal.add(java.util.Calendar.DAY_OF_MONTH, 2);
+ }
+ return eventContainer;
+ }
+
+ private static Indexed createTestIndexedContainer() {
+ IndexedContainer container = new IndexedContainer();
+ container.addContainerProperty("testCaption", String.class, "");
+ container.addContainerProperty("testDescription", String.class, "");
+ container.addContainerProperty("testStartDate", Date.class, null);
+ container.addContainerProperty("testEndDate", Date.class, null);
+
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ for (int i = 1; i <= 10; i++) {
+ Item item = container.getItem(container.addItem());
+ item.getItemProperty("testCaption").setValue("Test " + i);
+ item.getItemProperty("testDescription")
+ .setValue("Description " + i);
+ item.getItemProperty("testStartDate").setValue(cal.getTime());
+ item.getItemProperty("testEndDate").setValue(cal.getTime());
+ cal.add(java.util.Calendar.DAY_OF_MONTH, 2);
+ }
+ return container;
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java
index 68c1133dc0..44b77e88e2 100644
--- a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/BeanFieldGroupTest.java
@@ -3,6 +3,7 @@ package com.vaadin.tests.server.component.fieldgroup;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
+
import com.vaadin.data.fieldgroup.BeanFieldGroup;
public class BeanFieldGroupTest {
diff --git a/server/tests/src/com/vaadin/tests/server/component/fieldgroup/CaseInsensitiveBinding.java b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/CaseInsensitiveBinding.java
new file mode 100644
index 0000000000..e571576990
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/fieldgroup/CaseInsensitiveBinding.java
@@ -0,0 +1,85 @@
+package com.vaadin.tests.server.component.fieldgroup;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.data.util.PropertysetItem;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.TextField;
+
+public class CaseInsensitiveBinding {
+
+ @Test
+ public void caseInsensitivityAndUnderscoreRemoval() {
+ PropertysetItem item = new PropertysetItem();
+ item.addItemProperty("LastName", new ObjectProperty<String>("Sparrow"));
+
+ class MyForm extends FormLayout {
+ TextField lastName = new TextField("Last name");
+
+ public MyForm() {
+
+ // Should bind to the LastName property
+ addComponent(lastName);
+ }
+ }
+
+ MyForm form = new MyForm();
+
+ FieldGroup binder = new FieldGroup(item);
+ binder.bindMemberFields(form);
+
+ assertTrue("Sparrow".equals(form.lastName.getValue()));
+ }
+
+ @Test
+ public void UnderscoreRemoval() {
+ PropertysetItem item = new PropertysetItem();
+ item.addItemProperty("first_name", new ObjectProperty<String>("Jack"));
+
+ class MyForm extends FormLayout {
+ TextField firstName = new TextField("First name");
+
+ public MyForm() {
+ // Should bind to the first_name property
+ addComponent(firstName);
+ }
+ }
+
+ MyForm form = new MyForm();
+
+ FieldGroup binder = new FieldGroup(item);
+ binder.bindMemberFields(form);
+
+ assertTrue("Jack".equals(form.firstName.getValue()));
+ }
+
+ @Test
+ public void perfectMatchPriority() {
+ PropertysetItem item = new PropertysetItem();
+ item.addItemProperty("first_name", new ObjectProperty<String>(
+ "Not this"));
+ item.addItemProperty("firstName", new ObjectProperty<String>("This"));
+
+ class MyForm extends FormLayout {
+ TextField firstName = new TextField("First name");
+
+ public MyForm() {
+ // should bind to the firstName property, not first_name
+ // property
+ addComponent(firstName);
+ }
+ }
+
+ MyForm form = new MyForm();
+
+ FieldGroup binder = new FieldGroup(item);
+ binder.bindMemberFields(form);
+
+ assertTrue("This".equals(form.firstName.getValue()));
+ }
+
+} \ No newline at end of file
diff --git a/server/tests/src/com/vaadin/tests/server/component/gridlayout/DefaultAlignment.java b/server/tests/src/com/vaadin/tests/server/component/gridlayout/DefaultAlignment.java
new file mode 100644
index 0000000000..2faa65d1f2
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/gridlayout/DefaultAlignment.java
@@ -0,0 +1,46 @@
+package com.vaadin.tests.server.component.gridlayout;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+
+public class DefaultAlignment {
+
+ private GridLayout gridLayout;
+
+ @Before
+ public void setup() {
+ gridLayout = new GridLayout(2, 2);
+ }
+
+ @Test
+ public void testDefaultAlignment() {
+ Label label = new Label("A label");
+ TextField tf = new TextField("A TextField");
+ gridLayout.addComponent(label);
+ gridLayout.addComponent(tf);
+ Assert.assertEquals(Alignment.TOP_LEFT,
+ gridLayout.getComponentAlignment(label));
+ Assert.assertEquals(Alignment.TOP_LEFT,
+ gridLayout.getComponentAlignment(tf));
+ }
+
+ @Test
+ public void testAlteredDefaultAlignment() {
+ Label label = new Label("A label");
+ TextField tf = new TextField("A TextField");
+ gridLayout.setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
+ gridLayout.addComponent(label);
+ gridLayout.addComponent(tf);
+ Assert.assertEquals(Alignment.MIDDLE_CENTER,
+ gridLayout.getComponentAlignment(label));
+ Assert.assertEquals(Alignment.MIDDLE_CENTER,
+ gridLayout.getComponentAlignment(tf));
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/label/LabelConverters.java b/server/tests/src/com/vaadin/tests/server/component/label/LabelConverters.java
index 7fd2930865..9d71db89a6 100644
--- a/server/tests/src/com/vaadin/tests/server/component/label/LabelConverters.java
+++ b/server/tests/src/com/vaadin/tests/server/component/label/LabelConverters.java
@@ -21,6 +21,7 @@ import com.vaadin.data.Property;
import com.vaadin.data.util.MethodProperty;
import com.vaadin.server.VaadinSession;
import com.vaadin.tests.data.bean.Person;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.Label;
public class LabelConverters extends TestCase {
@@ -37,7 +38,7 @@ public class LabelConverters extends TestCase {
}
public void testIntegerDataSource() {
- VaadinSession.setCurrent(new VaadinSession(null));
+ VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null));
Label l = new Label("Foo");
Property ds = new MethodProperty<Integer>(Person.createTestPerson1(),
"age");
diff --git a/server/tests/src/com/vaadin/tests/server/component/orderedlayout/DefaultAlignment.java b/server/tests/src/com/vaadin/tests/server/component/orderedlayout/DefaultAlignment.java
new file mode 100644
index 0000000000..701373aba0
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/server/component/orderedlayout/DefaultAlignment.java
@@ -0,0 +1,68 @@
+package com.vaadin.tests.server.component.orderedlayout;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.ui.AbstractOrderedLayout;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class DefaultAlignment {
+
+ private VerticalLayout verticalLayout;
+ private HorizontalLayout horizontalLayout;
+
+ @Before
+ public void setup() {
+ verticalLayout = new VerticalLayout();
+ horizontalLayout = new HorizontalLayout();
+ }
+
+ @Test
+ public void testDefaultAlignmentVerticalLayout() {
+ testDefaultAlignment(verticalLayout);
+ }
+
+ @Test
+ public void testDefaultAlignmentHorizontalLayout() {
+ testDefaultAlignment(horizontalLayout);
+ }
+
+ public void testDefaultAlignment(AbstractOrderedLayout layout) {
+ Label label = new Label("A label");
+ TextField tf = new TextField("A TextField");
+ layout.addComponent(label);
+ layout.addComponent(tf);
+ Assert.assertEquals(Alignment.TOP_LEFT,
+ layout.getComponentAlignment(label));
+ Assert.assertEquals(Alignment.TOP_LEFT,
+ layout.getComponentAlignment(tf));
+ }
+
+ @Test
+ public void testAlteredDefaultAlignmentVerticalLayout() {
+ testAlteredDefaultAlignment(verticalLayout);
+ }
+
+ @Test
+ public void testAlteredDefaultAlignmentHorizontalLayout() {
+ testAlteredDefaultAlignment(horizontalLayout);
+ }
+
+ public void testAlteredDefaultAlignment(AbstractOrderedLayout layout) {
+ Label label = new Label("A label");
+ TextField tf = new TextField("A TextField");
+ layout.setDefaultComponentAlignment(Alignment.MIDDLE_CENTER);
+ layout.addComponent(label);
+ layout.addComponent(tf);
+ Assert.assertEquals(Alignment.MIDDLE_CENTER,
+ layout.getComponentAlignment(label));
+ Assert.assertEquals(Alignment.MIDDLE_CENTER,
+ layout.getComponentAlignment(tf));
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/server/component/tree/TreeTest.java b/server/tests/src/com/vaadin/tests/server/component/tree/TreeTest.java
index 634e6a86f3..3c9fc4c0cd 100644
--- a/server/tests/src/com/vaadin/tests/server/component/tree/TreeTest.java
+++ b/server/tests/src/com/vaadin/tests/server/component/tree/TreeTest.java
@@ -9,7 +9,6 @@ import java.lang.reflect.Field;
import java.util.HashSet;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import com.vaadin.data.Container;
@@ -84,17 +83,12 @@ public class TreeTest {
.getContainerDataSource().getClass()));
}
- @Ignore("This test tests that item ids which are removed are also "
- + "removed from the expand list to prevent a memory leak. "
- + "Fixing the memory leak cannot be done without changing some API (see #11053) "
- + "so ignoring this test for the 7.0.x series.")
@Test
public void testRemoveExpandedItems() throws Exception {
tree.expandItem("parent");
tree.expandItem("child");
- Field expandedField = tree.getClass()
- .getDeclaredField("expanded");
+ Field expandedField = tree.getClass().getDeclaredField("expanded");
Field expandedItemIdField = tree.getClass().getDeclaredField(
"expandedItemId");
diff --git a/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java b/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java
index 8884c0c27c..1df1d36cab 100644
--- a/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java
+++ b/server/tests/src/com/vaadin/tests/server/component/ui/CustomUIClassLoader.java
@@ -15,6 +15,7 @@ import com.vaadin.server.UIClassSelectionEvent;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.UI;
public class CustomUIClassLoader extends TestCase {
@@ -113,7 +114,7 @@ public class CustomUIClassLoader extends TestCase {
}
private VaadinSession createStubApplication() {
- return new VaadinSession(null) {
+ return new AlwaysLockedVaadinSession(null) {
@Override
public DeploymentConfiguration getConfiguration() {
return createConfigurationMock();
diff --git a/server/tests/src/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java b/server/tests/src/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java
index bf6d127a83..774eafceaf 100644
--- a/server/tests/src/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java
+++ b/server/tests/src/com/vaadin/tests/server/component/window/AddRemoveSubWindow.java
@@ -8,6 +8,7 @@ import org.junit.Test;
import com.vaadin.server.LegacyApplication;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.LegacyWindow;
import com.vaadin.ui.UI;
import com.vaadin.ui.Window;
@@ -25,7 +26,7 @@ public class AddRemoveSubWindow {
@Test
public void addSubWindow() {
- VaadinSession.setCurrent(new VaadinSession(null));
+ VaadinSession.setCurrent(new AlwaysLockedVaadinSession(null));
TestApp app = new TestApp();
app.init();
Window subWindow = new Window("Sub window");
diff --git a/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java b/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java
index 63a58bcab3..485b17830f 100644
--- a/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java
+++ b/server/tests/src/com/vaadin/tests/server/component/window/AttachDetachWindow.java
@@ -8,6 +8,7 @@ import org.junit.Test;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
@@ -15,7 +16,7 @@ import com.vaadin.ui.Window;
public class AttachDetachWindow {
- private VaadinSession testApp = new VaadinSession(null);
+ private VaadinSession testApp = new AlwaysLockedVaadinSession(null);
private interface TestContainer {
public boolean attachCalled();
diff --git a/server/tests/src/com/vaadin/tests/server/componentcontainer/AddRemoveComponentTest.java b/server/tests/src/com/vaadin/tests/server/componentcontainer/AddRemoveComponentTest.java
index 828404bd5a..91a302a274 100644
--- a/server/tests/src/com/vaadin/tests/server/componentcontainer/AddRemoveComponentTest.java
+++ b/server/tests/src/com/vaadin/tests/server/componentcontainer/AddRemoveComponentTest.java
@@ -9,6 +9,7 @@ import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CustomLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
+import com.vaadin.ui.components.colorpicker.ColorPickerPreview;
public class AddRemoveComponentTest extends TestCase {
@@ -19,6 +20,7 @@ public class AddRemoveComponentTest extends TestCase {
// No default constructor, special case
containerClasses.remove(CustomLayout.class);
+ containerClasses.remove(ColorPickerPreview.class);
testRemoveComponentFromWrongContainer(new CustomLayout("dummy"));
for (Class<? extends ComponentContainer> c : containerClasses) {
diff --git a/server/tests/src/com/vaadin/tests/util/AlwaysLockedVaadinSession.java b/server/tests/src/com/vaadin/tests/util/AlwaysLockedVaadinSession.java
new file mode 100644
index 0000000000..9b0b524b6a
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/util/AlwaysLockedVaadinSession.java
@@ -0,0 +1,23 @@
+package com.vaadin.tests.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+
+public class AlwaysLockedVaadinSession extends VaadinSession {
+
+ private ReentrantLock lock;
+
+ public AlwaysLockedVaadinSession(VaadinService service) {
+ super(service);
+ lock = new ReentrantLock();
+ lock.lock();
+ }
+
+ @Override
+ public Lock getLockInstance() {
+ return lock;
+ }
+}
diff --git a/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java b/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java
new file mode 100644
index 0000000000..d113efdfaf
--- /dev/null
+++ b/server/tests/src/com/vaadin/tests/util/MockDeploymentConfiguration.java
@@ -0,0 +1,111 @@
+package com.vaadin.tests.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import com.vaadin.server.DeploymentConfiguration;
+import com.vaadin.shared.communication.PushMode;
+
+public class MockDeploymentConfiguration implements DeploymentConfiguration {
+
+ private boolean productionMode = false;
+ private boolean xsrfProtectionEnabled = true;
+
+ private int resourceCacheTime = 12;
+ private int heartbeatInterval = 300;
+ private boolean closeIdleSessions = false;
+ private PushMode pushMode = PushMode.DISABLED;
+ private Properties initParameters = new Properties();
+ private Map<String, String> applicationOrSystemProperty = new HashMap<String, String>();
+ private LegacyProperyToStringMode legacyPropertyToStringMode = LegacyProperyToStringMode.DISABLED;
+
+ @Override
+ public boolean isProductionMode() {
+ return productionMode;
+ }
+
+ public void setProductionMode(boolean productionMode) {
+ this.productionMode = productionMode;
+ }
+
+ @Override
+ public boolean isXsrfProtectionEnabled() {
+ return xsrfProtectionEnabled;
+ }
+
+ public void setXsrfProtectionEnabled(boolean xsrfProtectionEnabled) {
+ this.xsrfProtectionEnabled = xsrfProtectionEnabled;
+ }
+
+ @Override
+ public int getResourceCacheTime() {
+ return resourceCacheTime;
+ }
+
+ public void setResourceCacheTime(int resourceCacheTime) {
+ this.resourceCacheTime = resourceCacheTime;
+ }
+
+ @Override
+ public int getHeartbeatInterval() {
+ return heartbeatInterval;
+ }
+
+ public void setHeartbeatInterval(int heartbeatInterval) {
+ this.heartbeatInterval = heartbeatInterval;
+ }
+
+ @Override
+ public boolean isCloseIdleSessions() {
+ return closeIdleSessions;
+ }
+
+ public void setCloseIdleSessions(boolean closeIdleSessions) {
+ this.closeIdleSessions = closeIdleSessions;
+ }
+
+ @Override
+ public PushMode getPushMode() {
+ return pushMode;
+ }
+
+ public void setPushMode(PushMode pushMode) {
+ this.pushMode = pushMode;
+ }
+
+ @Override
+ public Properties getInitParameters() {
+ return initParameters;
+ }
+
+ public void setInitParameter(String key, String value) {
+ initParameters.setProperty(key, value);
+ }
+
+ public void setApplicationOrSystemProperty(String key, String value) {
+ applicationOrSystemProperty.put(key, value);
+ }
+
+ @Override
+ public String getApplicationOrSystemProperty(String propertyName,
+ String defaultValue) {
+ if (applicationOrSystemProperty.containsKey(propertyName)) {
+ return applicationOrSystemProperty.get(propertyName);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ @Override
+ @Deprecated
+ public LegacyProperyToStringMode getLegacyPropertyToStringMode() {
+ return legacyPropertyToStringMode;
+ }
+
+ public void setLegacyPropertyToStringMode(
+ LegacyProperyToStringMode legacyPropertyToStringMode) {
+ this.legacyPropertyToStringMode = legacyPropertyToStringMode;
+ }
+
+}
diff --git a/server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java b/server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java
new file mode 100644
index 0000000000..9810873f0b
--- /dev/null
+++ b/server/tests/src/com/vaadin/ui/AbstractFieldDataSourceLocaleChange.java
@@ -0,0 +1,63 @@
+package com.vaadin.ui;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.data.util.converter.StringToIntegerConverter;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinSession;
+
+public class AbstractFieldDataSourceLocaleChange {
+
+ private VaadinSession vaadinSession;
+ private UI ui;
+
+ @Before
+ public void setup() {
+ vaadinSession = new VaadinSession(null);
+ VaadinSession.setCurrent(vaadinSession);
+ ui = new UI() {
+
+ @Override
+ protected void init(VaadinRequest request) {
+
+ }
+ };
+ ui.setSession(vaadinSession);
+ UI.setCurrent(ui);
+ }
+
+ @Test
+ public void localeChangesOnAttach() {
+ TextField tf = new TextField();
+
+ ;
+ tf.setConverter(new StringToIntegerConverter() {
+ @Override
+ protected NumberFormat getFormat(Locale locale) {
+ if (locale == null) {
+ NumberFormat format = super.getFormat(locale);
+ format.setGroupingUsed(false);
+ format.setMinimumIntegerDigits(10);
+ return format;
+ }
+ return super.getFormat(locale);
+ }
+ });
+ tf.setImmediate(true);
+ tf.setConvertedValue(10000);
+ Assert.assertEquals("0000010000", tf.getValue());
+
+ VerticalLayout vl = new VerticalLayout();
+ ui.setContent(vl);
+ ui.setLocale(new Locale("en", "US"));
+
+ vl.addComponent(tf);
+ Assert.assertEquals("10,000", tf.getValue());
+ }
+}
diff --git a/server/tests/src/com/vaadin/ui/LabelDataSource.java b/server/tests/src/com/vaadin/ui/LabelDataSource.java
index 7dcb382124..21d3e56d57 100644
--- a/server/tests/src/com/vaadin/ui/LabelDataSource.java
+++ b/server/tests/src/com/vaadin/ui/LabelDataSource.java
@@ -24,6 +24,7 @@ import org.junit.Test;
import com.vaadin.data.util.ObjectProperty;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.util.AlwaysLockedVaadinSession;
public class LabelDataSource {
@@ -39,7 +40,7 @@ public class LabelDataSource {
@Before
public void setup() {
- vaadinSession = new VaadinSession(null);
+ vaadinSession = new AlwaysLockedVaadinSession(null);
VaadinSession.setCurrent(vaadinSession);
label = new Label();
diff --git a/server/tests/src/com/vaadin/util/ReflectToolsGetFieldValueByType.java b/server/tests/src/com/vaadin/util/ReflectToolsGetFieldValueByType.java
index 78be9b04fb..540ffb852d 100644
--- a/server/tests/src/com/vaadin/util/ReflectToolsGetFieldValueByType.java
+++ b/server/tests/src/com/vaadin/util/ReflectToolsGetFieldValueByType.java
@@ -3,8 +3,6 @@ package com.vaadin.util;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import java.lang.reflect.InvocationTargetException;
-
import org.junit.Test;
public class ReflectToolsGetFieldValueByType {
@@ -56,8 +54,8 @@ public class ReflectToolsGetFieldValueByType {
memberField = myInstance.getClass().getField("field");
// Should throw an IllegalArgument exception as the mySubClass class
// doesn't have an Integer field.
- ReflectTools.getJavaFieldValue(myInstance,
- memberField, Integer.class);
+ ReflectTools.getJavaFieldValue(myInstance, memberField,
+ Integer.class);
fail("Previous method call should have thrown an exception");
} catch (Exception e) {
}
diff --git a/server/tests/src/com/vaadin/util/ReflectToolsGetPrimitiveFieldValue.java b/server/tests/src/com/vaadin/util/ReflectToolsGetPrimitiveFieldValue.java
index df192c51f2..1e1fafe31c 100644
--- a/server/tests/src/com/vaadin/util/ReflectToolsGetPrimitiveFieldValue.java
+++ b/server/tests/src/com/vaadin/util/ReflectToolsGetPrimitiveFieldValue.java
@@ -17,8 +17,8 @@ public class ReflectToolsGetPrimitiveFieldValue {
Object fieldValue = new Boolean(false);
try {
memberField = myInstance.getClass().getField("field");
- fieldValue = ReflectTools.getJavaFieldValue(myInstance,
- memberField);
+ fieldValue = ReflectTools
+ .getJavaFieldValue(myInstance, memberField);
} catch (Exception e) {
}
assertFalse(fieldValue instanceof Boolean);
diff --git a/shared/build.xml b/shared/build.xml
index 6ea753afa1..8520ee6eba 100644
--- a/shared/build.xml
+++ b/shared/build.xml
@@ -56,8 +56,8 @@
</antcall>
</target>
- <target name="tests" depends="checkstyle">
- <!--<antcall target="common.tests.run" />-->
+ <target name="test" depends="checkstyle">
+ <!--<antcall target="common.test.run" />-->
<echo>WHAT? No tests for ${module.name}!</echo>
</target>
diff --git a/shared/ivy.xml b/shared/ivy.xml
index 88020e8d09..3b044e9ab4 100644
--- a/shared/ivy.xml
+++ b/shared/ivy.xml
@@ -11,7 +11,7 @@
<conf name="build" />
<conf name="build-provided" />
<conf name="ide" visibility="private" />
- <conf name="tests" />
+ <conf name="test" />
</configurations>
<publications>
<artifact type="jar" ext="jar" />
@@ -21,7 +21,7 @@
</publications>
<dependencies>
<dependency org="com.vaadin" name="vaadin-shared-deps"
- rev="1.0.2" conf="build,ide,tests->default" />
+ rev="1.0.2" conf="build,ide,test->default" />
</dependencies>
</ivy-module>
diff --git a/shared/src/com/vaadin/shared/ApplicationConstants.java b/shared/src/com/vaadin/shared/ApplicationConstants.java
index 333833ab60..fc4abd1988 100644
--- a/shared/src/com/vaadin/shared/ApplicationConstants.java
+++ b/shared/src/com/vaadin/shared/ApplicationConstants.java
@@ -28,6 +28,8 @@ public class ApplicationConstants implements Serializable {
public static final String HEARTBEAT_PATH = "HEARTBEAT";
+ public static final String PUSH_PATH = "PUSH";
+
public static final String PUBLISHED_FILE_PATH = APP_PATH + '/'
+ "PUBLISHED";
@@ -37,7 +39,6 @@ public class ApplicationConstants implements Serializable {
+ "://";
public static final String UIDL_SECURITY_TOKEN_ID = "Vaadin-Security-Key";
- public static final String PARAM_UNLOADBURST = "onunloadburst";
public static final String PARAM_ANALYZE_LAYOUTS = "analyzeLayouts";
public static final String PARAM_HIGHLIGHT_CONNECTOR = "highlightConnector";
@@ -71,4 +72,19 @@ public class ApplicationConstants implements Serializable {
* </p>
*/
public static final String VAADIN_DIR_URL = "vaadinDir";
+
+ /**
+ * The name of the javascript containing push support. The file is located
+ * in the VAADIN directory.
+ */
+ public static final String VAADIN_PUSH_JS = "vaadinPush.js";
+
+ /**
+ * Name of the parameter used to transmit the CSRF token.
+ */
+ public static final String CSRF_TOKEN_PARAMETER = "v-csrfToken";
+
+ public static final int WEBSOCKET_BUFFER_SIZE = 65536;
+
+ public static final char WEBSOCKET_MESSAGE_DELIMITER = '|';
}
diff --git a/shared/src/com/vaadin/shared/JsonConstants.java b/shared/src/com/vaadin/shared/JsonConstants.java
index 8a9e37f1a5..44aeac72e4 100644
--- a/shared/src/com/vaadin/shared/JsonConstants.java
+++ b/shared/src/com/vaadin/shared/JsonConstants.java
@@ -32,4 +32,6 @@ public class JsonConstants implements Serializable {
public static final String VTYPE_SET = "q";
public static final String VTYPE_NULL = "n";
+ public static final String JSON_CONTENT_TYPE = "application/json; charset=UTF-8";
+
}
diff --git a/shared/src/com/vaadin/shared/communication/MethodInvocation.java b/shared/src/com/vaadin/shared/communication/MethodInvocation.java
index 417ced76be..d5bf8324ef 100644
--- a/shared/src/com/vaadin/shared/communication/MethodInvocation.java
+++ b/shared/src/com/vaadin/shared/communication/MethodInvocation.java
@@ -19,6 +19,8 @@ package com.vaadin.shared.communication;
import java.io.Serializable;
import java.util.Arrays;
+import com.vaadin.shared.util.SharedUtil;
+
/**
* Information needed by the framework to send an RPC method invocation from the
* client to the server or vice versa.
@@ -85,4 +87,29 @@ public class MethodInvocation implements Serializable {
return connectorId + "-" + getInterfaceName() + "-" + getMethodName();
}
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MethodInvocation)) {
+ return false;
+ }
+ MethodInvocation other = (MethodInvocation) obj;
+ if (!SharedUtil.equals(getConnectorId(), other.getConnectorId())) {
+ return false;
+ }
+
+ if (!SharedUtil.equals(getInterfaceName(), other.getInterfaceName())) {
+ return false;
+ }
+
+ if (!SharedUtil.equals(getMethodName(), other.getMethodName())) {
+ return false;
+ }
+
+ if (!SharedUtil.equals(getParameters(), other.getParameters())) {
+ return false;
+ }
+
+ return true;
+
+ }
} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/communication/PushMode.java b/shared/src/com/vaadin/shared/communication/PushMode.java
new file mode 100644
index 0000000000..3fe8b4ea3e
--- /dev/null
+++ b/shared/src/com/vaadin/shared/communication/PushMode.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.shared.communication;
+
+/**
+ * The mode of bidirectional ("push") communication that is in use.
+ *
+ * @see com.vaadin.server.DeploymentConfiguration#getPushMode()
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public enum PushMode {
+ /**
+ * Push is disabled. Regular AJAX requests are used to communicate between
+ * the client and the server. Asynchronous messages from the server are not
+ * possible. {@link com.vaadin.ui.UI#push() ui.push()} throws
+ * IllegalStateException.
+ * <p>
+ * This is the default mode unless
+ * {@link com.vaadin.server.DeploymentConfiguration#getPushMode()
+ * configured} otherwise.
+ */
+ DISABLED,
+
+ /**
+ * Push is enabled. A bidirectional channel is established between the
+ * client and server and used to communicate state changes and RPC
+ * invocations. The client is not automatically updated if the server-side
+ * state is asynchronously changed; {@link com.vaadin.ui.UI#push()
+ * ui.push()} must be explicitly called.
+ */
+ MANUAL,
+
+ /**
+ * Push is enabled. Like {@link #MANUAL}, but asynchronous changes to the
+ * server-side state are automatically pushed to the client once the session
+ * lock is released.
+ */
+ AUTOMATIC;
+
+ /**
+ * Checks whether the push mode is using push functionality
+ *
+ * @return <code>true</code> if this mode requires push functionality;
+ * <code>false</code> if no push functionality is used for this
+ * mode.
+ */
+ public boolean isEnabled() {
+ return this != DISABLED;
+ }
+}
diff --git a/shared/src/com/vaadin/shared/ui/button/ButtonState.java b/shared/src/com/vaadin/shared/ui/button/ButtonState.java
index a33a9f78db..7e1fd52ed7 100644
--- a/shared/src/com/vaadin/shared/ui/button/ButtonState.java
+++ b/shared/src/com/vaadin/shared/ui/button/ButtonState.java
@@ -37,4 +37,5 @@ public class ButtonState extends TabIndexState {
* If caption should be rendered in HTML
*/
public boolean htmlContentAllowed = false;
+ public String iconAltText = "";
}
diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarClientRpc.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarClientRpc.java
new file mode 100644
index 0000000000..c1ff8bdda5
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarClientRpc.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.calendar;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+/**
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ *
+ */
+public interface CalendarClientRpc extends ClientRpc {
+ void scroll(int scrollPosition);
+}
diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java
new file mode 100644
index 0000000000..6f52aabf43
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarEventId.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.calendar;
+
+/**
+ * CalendarEventId contains static String identifiers for all Calendar events.
+ * These are used both in the client and server side code.
+ *
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public class CalendarEventId {
+
+ public static final String EVENTMOVE = "eventMove";
+ public static final String RANGESELECT = "rangeSelect";
+ public static final String FORWARD = "forward";
+ public static final String BACKWARD = "backward";
+ public static final String DATECLICK = "dateClick";
+ public static final String WEEKCLICK = "weekClick";
+ public static final String EVENTCLICK = "eventClick";
+ public static final String EVENTRESIZE = "eventResize";
+ public static final String ACTION = "action";
+}
diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarServerRpc.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarServerRpc.java
new file mode 100644
index 0000000000..5257310cbf
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarServerRpc.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.calendar;
+
+import com.vaadin.shared.annotations.Delayed;
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * @since 7.1
+ * @author Vaadin Ltd.
+ */
+public interface CalendarServerRpc extends ServerRpc {
+ void eventMove(int eventIndex, String newDate);
+
+ void rangeSelect(String range);
+
+ void forward();
+
+ void backward();
+
+ void dateClick(String date);
+
+ void weekClick(String event);
+
+ void eventClick(int eventIndex);
+
+ void eventResize(int eventIndex, String newStartDate, String newEndDate);
+
+ void actionOnEmptyCell(String actionKey, String startDate, String endDate);
+
+ void actionOnEvent(String actionKey, String startDate, String endDate,
+ int eventIndex);
+
+ @Delayed(lastOnly = true)
+ void scroll(int scrollPosition);
+}
diff --git a/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java b/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java
new file mode 100644
index 0000000000..fab5fd828e
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/calendar/CalendarState.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.calendar;
+
+import java.util.List;
+
+import com.vaadin.shared.AbstractComponentState;
+
+/**
+ * @since 7.1.0
+ * @author Vaadin Ltd.
+ */
+public class CalendarState extends AbstractComponentState {
+
+ public boolean format24H;
+ public String[] dayNames;
+ public String[] monthNames;
+ public int firstVisibleDayOfWeek = 1;
+ public int lastVisibleDayOfWeek = 7;
+ public int firstHourOfDay = 0;
+ public int lastHourOfDay = 23;
+ public int firstDayOfWeek;
+ public int scroll;
+ public String now;
+ public List<CalendarState.Day> days;
+ public List<CalendarState.Event> events;
+ public List<CalendarState.Action> actions;
+
+ public static class Day implements java.io.Serializable {
+ public String date;
+ public String localizedDateFormat;
+ public int dayOfWeek;
+ public int week;
+ }
+
+ public static class Action implements java.io.Serializable {
+
+ public String caption;
+ public String iconKey;
+ public String actionKey;
+ public String startDate;
+ public String endDate;
+ }
+
+ public static class Event implements java.io.Serializable {
+ public int index;
+ public String caption;
+ public String dateFrom;
+ public String dateTo;
+ public String timeFrom;
+ public String timeTo;
+ public String styleName;
+ public String description;
+ public boolean allDay;
+ }
+}
diff --git a/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java b/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java
new file mode 100644
index 0000000000..8a840274c2
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/calendar/DateConstants.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.calendar;
+
+/**
+ *
+ * @since 7.1
+ *
+ */
+public class DateConstants {
+
+ public static final String ACTION_DATE_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss";
+ public static final String CLIENT_DATE_FORMAT = "yyyy-MM-dd";
+ public static final String CLIENT_TIME_FORMAT = "HH-mm";
+ public static final long MINUTEINMILLIS = 60 * 1000;
+ public static final long HOURINMILLIS = 60 * MINUTEINMILLIS;
+ public static final long DAYINMILLIS = 24 * HOURINMILLIS;
+ public static final long WEEKINMILLIS = 7 * DAYINMILLIS;
+
+}
diff --git a/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java
index 405f89d538..d56e0d27b3 100644
--- a/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java
+++ b/shared/src/com/vaadin/shared/ui/datefield/InlineDateFieldState.java
@@ -15,9 +15,7 @@
*/
package com.vaadin.shared.ui.datefield;
-import com.vaadin.shared.AbstractFieldState;
-
-public class InlineDateFieldState extends AbstractFieldState {
+public class InlineDateFieldState extends TextualDateFieldState {
{
primaryStyleName = "v-inline-datefield";
}
diff --git a/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java
index 74cab3efb0..1c061b3ac3 100644
--- a/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java
+++ b/shared/src/com/vaadin/shared/ui/datefield/PopupDateFieldState.java
@@ -16,10 +16,12 @@
package com.vaadin.shared.ui.datefield;
public class PopupDateFieldState extends TextualDateFieldState {
+ public static final String DESCRIPTION_FOR_ASSISTIVE_DEVICES = "Arrow down key opens calendar element for choosing the date";
+
{
primaryStyleName = "v-datefield";
}
public boolean textFieldEnabled = true;
-
+ public String descriptionForAssistiveDevices = DESCRIPTION_FOR_ASSISTIVE_DEVICES;
}
diff --git a/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java b/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java
index c34f3d8eda..11ad4cdb59 100644
--- a/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java
+++ b/shared/src/com/vaadin/shared/ui/datefield/TextualDateFieldState.java
@@ -15,10 +15,24 @@
*/
package com.vaadin.shared.ui.datefield;
+import java.util.Date;
+
import com.vaadin.shared.AbstractFieldState;
public class TextualDateFieldState extends AbstractFieldState {
{
primaryStyleName = "v-datefield";
}
+
+ /*
+ * Start range that has been cleared, depending on the resolution of the
+ * date field
+ */
+ public Date rangeStart = null;
+
+ /*
+ * End range that has been cleared, depending on the resolution of the date
+ * field
+ */
+ public Date rangeEnd = null;
}
diff --git a/shared/src/com/vaadin/shared/ui/tree/TreeConstants.java b/shared/src/com/vaadin/shared/ui/tree/TreeConstants.java
index 7adc69511d..a57ca31246 100644
--- a/shared/src/com/vaadin/shared/ui/tree/TreeConstants.java
+++ b/shared/src/com/vaadin/shared/ui/tree/TreeConstants.java
@@ -26,6 +26,8 @@ public class TreeConstants implements Serializable {
public static final String ATTRIBUTE_NODE_CAPTION = "caption";
@Deprecated
public static final String ATTRIBUTE_NODE_ICON = "icon";
+ @Deprecated
+ public static final String ATTRIBUTE_NODE_ICON_ALT = "iconalt";
@Deprecated
public static final String ATTRIBUTE_ACTION_CAPTION = "caption";
diff --git a/shared/src/com/vaadin/shared/ui/ui/PageClientRpc.java b/shared/src/com/vaadin/shared/ui/ui/PageClientRpc.java
index 3d8f607cb8..eb847bacd0 100644
--- a/shared/src/com/vaadin/shared/ui/ui/PageClientRpc.java
+++ b/shared/src/com/vaadin/shared/ui/ui/PageClientRpc.java
@@ -22,4 +22,6 @@ public interface PageClientRpc extends ClientRpc {
public void setTitle(String title);
+ public void reload();
+
}
diff --git a/shared/src/com/vaadin/shared/ui/ui/PageState.java b/shared/src/com/vaadin/shared/ui/ui/PageState.java
new file mode 100644
index 0000000000..0b51eb4bba
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/ui/PageState.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.ui;
+
+import java.io.Serializable;
+
+/**
+ * The shared state of a {@link com.vaadin.server.Page Page}.
+ *
+ * Note that at the moment this is not a stand-alone state class but embedded in
+ * {@link UIState}. This might change in the future.
+ *
+ * @since 7.1
+ */
+public class PageState implements Serializable {
+ /**
+ * True if the page has browser window resize listeners.
+ */
+ public boolean hasResizeListeners = false;
+} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIClientRpc.java b/shared/src/com/vaadin/shared/ui/ui/UIClientRpc.java
new file mode 100644
index 0000000000..3067b10e24
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/ui/UIClientRpc.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.ui;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+/**
+ * Server to Client RPC methods for UI
+ *
+ * @since 7.1
+ * @author Vaadin Ltd
+ */
+public interface UIClientRpc extends ClientRpc {
+
+ /**
+ * @since
+ * @param sessionExpired
+ */
+ void uiClosed(boolean sessionExpired);
+
+}
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java b/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
index 358ba2e24e..576ee83980 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIServerRpc.java
@@ -26,4 +26,11 @@ public interface UIServerRpc extends ClickRpc, ServerRpc {
@Delayed(lastOnly = true)
public void scroll(int scrollTop, int scrollLeft);
+
+ @Delayed(lastOnly = true)
+ /*
+ * @Delayed just to get lastOnly semantics, sendPendingVariableChanges()
+ * should always be called to ensure the message is flushed right away.
+ */
+ public void poll();
} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/ui/UIState.java b/shared/src/com/vaadin/shared/ui/ui/UIState.java
index 9abaf47f4b..16c1ed16c7 100644
--- a/shared/src/com/vaadin/shared/ui/ui/UIState.java
+++ b/shared/src/com/vaadin/shared/ui/ui/UIState.java
@@ -15,12 +15,45 @@
*/
package com.vaadin.shared.ui.ui;
+import java.io.Serializable;
+
+import com.vaadin.shared.communication.PushMode;
import com.vaadin.shared.ui.TabIndexState;
public class UIState extends TabIndexState {
+ public TooltipConfigurationState tooltipConfiguration = new TooltipConfigurationState();
+ public LoadingIndicatorConfigurationState loadingIndicatorConfiguration = new LoadingIndicatorConfigurationState();
+ public int pollInterval = -1;
+
+ public PushMode pushMode = PushMode.DISABLED;
+
+ // Informing users of assistive devices, that the content of this container
+ // is announced automatically and does not need to be navigated into
+ public String overlayContainerLabel = "This content is announced automatically and does not need to be navigated into.";
+
+ public static class LoadingIndicatorConfigurationState implements
+ Serializable {
+ public int firstDelay = 300;
+ public int secondDelay = 1500;
+ public int thirdDelay = 5000;
+ }
+
+ public static class TooltipConfigurationState implements Serializable {
+ public int openDelay = 750;
+ public int quickOpenDelay = 100;
+ public int quickOpenTimeout = 1000;
+ public int closeTimeout = 300;
+ public int maxWidth = 500;
+ }
+
+ /**
+ * State related to the {@link Page} class.
+ */
+ public PageState pageState = new PageState();
+
{
primaryStyleName = "v-ui";
// Default is 1 for legacy reasons
tabIndex = 1;
}
-} \ No newline at end of file
+}
diff --git a/shared/src/com/vaadin/shared/ui/window/WindowMode.java b/shared/src/com/vaadin/shared/ui/window/WindowMode.java
new file mode 100644
index 0000000000..04af77a086
--- /dev/null
+++ b/shared/src/com/vaadin/shared/ui/window/WindowMode.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.window;
+
+/**
+ * Determines the mode of the Window.
+ * <p>
+ * A window mode decides the size and position of the Window. It can be set to
+ * {@link #NORMAL} or {@link #MAXIMIZED}.
+ *
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ */
+public enum WindowMode {
+ /**
+ * Normal mode. The window size and position is determined by the window
+ * state.
+ */
+ NORMAL,
+ /**
+ * Maximized mode. The window is positioned in the top left corner and fills
+ * the whole screen.
+ */
+ MAXIMIZED;
+}
diff --git a/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java b/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java
index c42f91c006..cfb10ad86a 100644
--- a/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java
+++ b/shared/src/com/vaadin/shared/ui/window/WindowServerRpc.java
@@ -15,8 +15,13 @@
*/
package com.vaadin.shared.ui.window;
+import com.vaadin.shared.annotations.Delayed;
import com.vaadin.shared.communication.ServerRpc;
import com.vaadin.shared.ui.ClickRpc;
public interface WindowServerRpc extends ClickRpc, ServerRpc {
+
+ @Delayed(lastOnly = true)
+ public void windowModeChanged(WindowMode newState);
+
} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/ui/window/WindowState.java b/shared/src/com/vaadin/shared/ui/window/WindowState.java
index 4afc20f2b1..5a2d2b81b0 100644
--- a/shared/src/com/vaadin/shared/ui/window/WindowState.java
+++ b/shared/src/com/vaadin/shared/ui/window/WindowState.java
@@ -21,6 +21,7 @@ public class WindowState extends PanelState {
{
primaryStyleName = "v-window";
}
+
public boolean modal = false;
public boolean resizable = true;
public boolean resizeLazy = false;
@@ -28,4 +29,5 @@ public class WindowState extends PanelState {
public boolean centered = false;;
public int positionX = -1;
public int positionY = -1;
+ public WindowMode windowMode = WindowMode.NORMAL;
} \ No newline at end of file
diff --git a/shared/src/com/vaadin/shared/util/SharedUtil.java b/shared/src/com/vaadin/shared/util/SharedUtil.java
new file mode 100644
index 0000000000..2242fa4363
--- /dev/null
+++ b/shared/src/com/vaadin/shared/util/SharedUtil.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.util;
+
+/**
+ * Misc internal utility methods used by both the server and the client package.
+ *
+ * @author Vaadin Ltd
+ * @since 7.1
+ *
+ */
+public class SharedUtil {
+ /**
+ * Checks if a and b are equals using {@link #equals(Object)}. Handles null
+ * values as well. Does not ensure that objects are of the same type.
+ * Assumes that the first object's equals method handle equals properly.
+ *
+ * @param o1
+ * The first value to compare
+ * @param o2
+ * The second value to compare
+ * @return true if the objects are equal, false otherwise
+ */
+ public static boolean equals(Object o1, Object o2) {
+ if (o1 == null) {
+ return o2 == null;
+ }
+
+ return o1.equals(o2);
+ }
+
+}
diff --git a/theme-compiler/build.xml b/theme-compiler/build.xml
index cd441dee70..277929d160 100644
--- a/theme-compiler/build.xml
+++ b/theme-compiler/build.xml
@@ -15,7 +15,7 @@
<property name="sass.parser.jj" location="src/com/vaadin/sass/internal/parser/Parser.jj" />
<path id="classpath.compile.custom">
</path>
- <path id="classpath.tests.custom" />
+ <path id="classpath.test.custom" />
<!--<property name="classes.exclude" value="com/vaadin/buildhelpers/**" />-->
@@ -51,8 +51,8 @@
</antcall>
</target>
- <target name="tests" depends="checkstyle">
- <antcall target="common.tests.run" />
+ <target name="test" depends="checkstyle">
+ <antcall target="common.test.run" />
</target>
</project> \ No newline at end of file
diff --git a/theme-compiler/ivy.xml b/theme-compiler/ivy.xml
index b1a98b7101..f0646c04e6 100644
--- a/theme-compiler/ivy.xml
+++ b/theme-compiler/ivy.xml
@@ -11,7 +11,7 @@
<conf name="build" />
<conf name="build-provided" />
<conf name="ide" visibility="private" />
- <conf name="tests" />
+ <conf name="test" />
</configurations>
<publications>
<artifact type="jar" ext="jar" />
@@ -23,17 +23,17 @@
<!-- LIBRARY DEPENDENCIES (compile time) -->
<!-- Project modules -->
<dependency org="com.vaadin" name="vaadin-shared"
- rev="${vaadin.version}" conf="build,tests" />
+ rev="${vaadin.version}" conf="build,test->build" />
<!-- Required build libs -->
<dependency org="org.apache.commons" name="commons-jexl"
- rev="2.1.1" conf="build,ide,tests->default" />
+ rev="2.1.1" conf="build,ide,test->default" />
<dependency org="org.w3c.css" name="sac" rev="1.3"
- conf="build,ide,tests->default" />
+ conf="build,ide,test->default" />
<dependency org="net.sourceforge.cssparser" name="cssparser"
- rev="0.9.5" conf="build,ide,tests->default" />
+ rev="0.9.5" conf="build,ide,test->default" />
<dependency org="commons-cli" name="commons-cli" rev="1.2"
- conf="build,ide,tests->default" />
+ conf="build,ide,test->default" />
<!-- Provided build libs -->
<dependency org="javax.servlet" name="servlet-api"
@@ -41,7 +41,7 @@
<!-- Testing libs -->
<dependency org="junit" name="junit" rev="4.5"
- conf="tests -> default" />
+ conf="test -> default" />
<!-- Internally used, for now -->
<dependency org="com.carrotsearch" name="smartsprites"
diff --git a/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml b/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml
index f921bec167..29dc2d3474 100644
--- a/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml
+++ b/theme-compiler/ivymodule/smartsprites-ivy-0.2.3-itmill.xml
@@ -31,7 +31,7 @@
<dependency org="com.google.collections" name="google-collections" rev="0.9" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
<dependency org="args4j" name="args4j" rev="2.0.9" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
<dependency org="commons-math" name="commons-math" rev="1.1" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
- <dependency org="commons-io" name="commons-io" rev="1.4" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
+ <dependency org="commons-io" name="commons-io" rev="2.2" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
<dependency org="commons-lang" name="commons-lang" rev="2.6" force="true" conf="compile->compile(*),master(*);runtime->runtime(*)"/>
<dependency org="junit" name="junit" rev="4.4" force="true" conf="test->runtime(*),master(*)"/>
</dependencies>
diff --git a/theme-compiler/src/com/vaadin/sass/SassCompiler.java b/theme-compiler/src/com/vaadin/sass/SassCompiler.java
index 48b2d24c46..6a83425ca1 100644
--- a/theme-compiler/src/com/vaadin/sass/SassCompiler.java
+++ b/theme-compiler/src/com/vaadin/sass/SassCompiler.java
@@ -17,7 +17,6 @@
package com.vaadin.sass;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
@@ -49,12 +48,12 @@ public class SassCompiler {
// ScssStylesheet.setStylesheetResolvers(new VaadinResolver());
ScssStylesheet scss = ScssStylesheet.get(input);
- if(scss == null){
+ if (scss == null) {
System.err.println("The scss file " + input
+ " could not be found.");
return;
}
-
+
scss.compile();
if (output == null) {
System.out.println(scss.toString());
diff --git a/theme-compiler/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluator.java b/theme-compiler/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluator.java
new file mode 100644
index 0000000000..7dbd8ae1a0
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluator.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.sass.internal.expression;
+
+import static com.vaadin.sass.internal.parser.SCSSLexicalUnit.SCSS_VARIABLE;
+
+import java.util.Stack;
+
+import com.vaadin.sass.internal.expression.exception.ArithmeticException;
+import com.vaadin.sass.internal.parser.LexicalUnitImpl;
+import com.vaadin.sass.internal.parser.SCSSLexicalUnit;
+
+public class ArithmeticExpressionEvaluator {
+ private static ArithmeticExpressionEvaluator instance;
+
+ public static ArithmeticExpressionEvaluator get() {
+ if (instance == null) {
+ instance = new ArithmeticExpressionEvaluator();
+ }
+ return instance;
+ }
+
+ private void createNewOperand(BinaryOperator operator,
+ Stack<Object> operands) {
+ Object rightOperand = operands.pop();
+ operands.push(new BinaryExpression(operands.pop(), operator,
+ rightOperand));
+ }
+
+ public boolean containsArithmeticalOperator(LexicalUnitImpl term) {
+ LexicalUnitImpl current = term;
+ while (current != null) {
+ for (BinaryOperator operator : BinaryOperator.values()) {
+ /*
+ * '/' is treated as an arithmetical operator when one of its
+ * operands is Variable, or there is another binary operator.
+ * Otherwise, '/' is treated as a CSS operator.
+ */
+ if (current.getLexicalUnitType() == operator.type) {
+ if (current.getLexicalUnitType() != BinaryOperator.DIV.type) {
+ return true;
+ } else {
+ if (current.getPreviousLexicalUnit()
+ .getLexicalUnitType() == SCSS_VARIABLE
+ || current.getNextLexicalUnit()
+ .getLexicalUnitType() == SCSS_VARIABLE) {
+ return true;
+ }
+ }
+ }
+ }
+ current = current.getNextLexicalUnit();
+ }
+ return false;
+ }
+
+ private Object createExpression(LexicalUnitImpl term) {
+ LexicalUnitImpl current = term;
+ boolean afterOperand = false;
+ Stack<Object> operands = new Stack<Object>();
+ Stack<Object> operators = new Stack<Object>();
+ inputTermLoop: while (current != null) {
+ if (afterOperand) {
+ if (current.getLexicalUnitType() == SCSSLexicalUnit.SCSS_OPERATOR_RIGHT_PAREN) {
+ Object operator = null;
+ while (!operators.isEmpty()
+ && ((operator = operators.pop()) != Parentheses.LEFT)) {
+ createNewOperand((BinaryOperator) operator, operands);
+ }
+ current = current.getNextLexicalUnit();
+ continue;
+ }
+ afterOperand = false;
+ for (BinaryOperator operator : BinaryOperator.values()) {
+ if (current.getLexicalUnitType() == operator.type) {
+ while (!operators.isEmpty()
+ && (operators.peek() != Parentheses.LEFT)
+ && (((BinaryOperator) operators.peek()).precedence >= operator.precedence)) {
+ createNewOperand((BinaryOperator) operators.pop(),
+ operands);
+ }
+ operators.push(operator);
+
+ current = current.getNextLexicalUnit();
+ continue inputTermLoop;
+ }
+ }
+ throw new ArithmeticException();
+ }
+ if (current.getLexicalUnitType() == SCSSLexicalUnit.SCSS_OPERATOR_LEFT_PAREN) {
+ operators.push(Parentheses.LEFT);
+ current = current.getNextLexicalUnit();
+ continue;
+ }
+ afterOperand = true;
+
+ operands.push(current);
+ current = current.getNextLexicalUnit();
+ }
+
+ while (!operators.isEmpty()) {
+ Object operator = operators.pop();
+ if (operator == Parentheses.LEFT) {
+ throw new ArithmeticException("Unexpected \"(\" found");
+ }
+ createNewOperand((BinaryOperator) operator, operands);
+ }
+ Object expression = operands.pop();
+ if (!operands.isEmpty()) {
+ LexicalUnitImpl operand = (LexicalUnitImpl) operands.peek();
+ throw new ArithmeticException("Unexpected operand "
+ + operand.toString() + " found");
+ }
+ return expression;
+ }
+
+ public LexicalUnitImpl evaluate(LexicalUnitImpl term) {
+ Object result = ArithmeticExpressionEvaluator.get().createExpression(
+ term);
+ if (result instanceof BinaryExpression) {
+ return ((BinaryExpression) result).eval();
+ }
+ return term;
+ }
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/expression/BinaryExpression.java b/theme-compiler/src/com/vaadin/sass/internal/expression/BinaryExpression.java
new file mode 100644
index 0000000000..bfcdf6f506
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/expression/BinaryExpression.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.sass.internal.expression;
+
+import com.vaadin.sass.internal.parser.LexicalUnitImpl;
+
+public class BinaryExpression {
+ public Object leftOperand = null;
+ public BinaryOperator operator = null;
+ public Object rightOperand = null;
+
+ public BinaryExpression(Object leftOperand, BinaryOperator operator,
+ Object rightOperand) {
+ this.leftOperand = leftOperand;
+ this.operator = operator;
+ this.rightOperand = rightOperand;
+ }
+
+ public LexicalUnitImpl eval() {
+ LexicalUnitImpl leftValue = (leftOperand instanceof BinaryExpression) ? ((BinaryExpression) leftOperand)
+ .eval() : (LexicalUnitImpl) leftOperand;
+ LexicalUnitImpl rightValue = (rightOperand instanceof BinaryExpression) ? ((BinaryExpression) rightOperand)
+ .eval() : (LexicalUnitImpl) rightOperand;
+ return operator.eval(leftValue, rightValue);
+ }
+
+ @Override
+ public String toString() {
+ return "(" + leftOperand + " " + operator.type + " " + rightOperand
+ + ")";
+ }
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/expression/BinaryOperator.java b/theme-compiler/src/com/vaadin/sass/internal/expression/BinaryOperator.java
new file mode 100644
index 0000000000..15d3da797f
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/expression/BinaryOperator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.sass.internal.expression;
+
+import org.w3c.css.sac.LexicalUnit;
+
+import com.vaadin.sass.internal.parser.LexicalUnitImpl;
+
+public enum BinaryOperator {
+ ADD(LexicalUnit.SAC_OPERATOR_PLUS, 1) {
+ @Override
+ public LexicalUnitImpl eval(LexicalUnitImpl leftValue,
+ LexicalUnitImpl rightValue) {
+ return leftValue.add(rightValue);
+ }
+ },
+ MINUS(LexicalUnit.SAC_OPERATOR_MINUS, 1) {
+ @Override
+ public LexicalUnitImpl eval(LexicalUnitImpl leftValue,
+ LexicalUnitImpl rightValue) {
+ return leftValue.minus(rightValue);
+ }
+ },
+ MUL(LexicalUnit.SAC_OPERATOR_MULTIPLY, 2) {
+ @Override
+ public LexicalUnitImpl eval(LexicalUnitImpl leftValue,
+ LexicalUnitImpl rightValue) {
+ return leftValue.multiply(rightValue);
+ }
+ },
+ DIV(LexicalUnit.SAC_OPERATOR_SLASH, 2) {
+ @Override
+ public LexicalUnitImpl eval(LexicalUnitImpl leftValue,
+ LexicalUnitImpl rightValue) {
+ return leftValue.divide(rightValue);
+ }
+ },
+ MOD(LexicalUnit.SAC_OPERATOR_MOD, 2) {
+ @Override
+ public LexicalUnitImpl eval(LexicalUnitImpl leftValue,
+ LexicalUnitImpl rightValue) {
+ return leftValue.modulo(rightValue);
+ }
+ };
+
+ public final short type;
+ public final int precedence;
+
+ BinaryOperator(short type, int precedence) {
+ this.type = type;
+ this.precedence = precedence;
+ }
+
+ public abstract LexicalUnitImpl eval(LexicalUnitImpl leftValue,
+ LexicalUnitImpl rightValue);
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/expression/Parentheses.java b/theme-compiler/src/com/vaadin/sass/internal/expression/Parentheses.java
new file mode 100644
index 0000000000..5df8607aaf
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/expression/Parentheses.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.sass.internal.expression;
+
+public enum Parentheses {
+ LEFT, RIGHT
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/expression/exception/ArithmeticException.java b/theme-compiler/src/com/vaadin/sass/internal/expression/exception/ArithmeticException.java
new file mode 100644
index 0000000000..13b6f0e936
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/expression/exception/ArithmeticException.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.sass.internal.expression.exception;
+
+public class ArithmeticException extends RuntimeException {
+ public ArithmeticException(String errorMsg) {
+ super(errorMsg);
+ }
+
+ public ArithmeticException() {
+ super("Illegal arithmetic expression");
+ }
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/expression/exception/IncompatibleUnitsException.java b/theme-compiler/src/com/vaadin/sass/internal/expression/exception/IncompatibleUnitsException.java
new file mode 100644
index 0000000000..bbeb0140f2
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/expression/exception/IncompatibleUnitsException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.sass.internal.expression.exception;
+
+public class IncompatibleUnitsException extends ArithmeticException {
+ public IncompatibleUnitsException(String errorExpr) {
+ super(getErrorMsg(errorExpr));
+ }
+
+ private static String getErrorMsg(String errorExpr) {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Incompatible units found in: ");
+ builder.append("'").append(errorExpr).append("'");
+ return builder.toString();
+ }
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandler.java b/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandler.java
index 9dc6e33873..b9672b6c78 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandler.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandler.java
@@ -96,4 +96,10 @@ public interface SCSSDocumentHandler extends DocumentHandler {
void endKeyframeSelector();
+ void contentDirective();
+
+ void startIncludeContentBlock(String name);
+
+ void endIncludeContentBlock();
+
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandlerImpl.java b/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandlerImpl.java
index d155d8522f..d77a404ae8 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandlerImpl.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/handler/SCSSDocumentHandlerImpl.java
@@ -30,6 +30,7 @@ import com.vaadin.sass.internal.ScssStylesheet;
import com.vaadin.sass.internal.parser.LexicalUnitImpl;
import com.vaadin.sass.internal.tree.BlockNode;
import com.vaadin.sass.internal.tree.CommentNode;
+import com.vaadin.sass.internal.tree.ContentNode;
import com.vaadin.sass.internal.tree.ExtendNode;
import com.vaadin.sass.internal.tree.FontFaceNode;
import com.vaadin.sass.internal.tree.ForNode;
@@ -365,4 +366,23 @@ public class SCSSDocumentHandlerImpl implements SCSSDocumentHandler {
public void endKeyframeSelector() {
nodeStack.pop();
}
+
+ @Override
+ public void contentDirective() {
+ ContentNode node = new ContentNode();
+ nodeStack.peek().appendChild(node);
+ }
+
+ @Override
+ public void startIncludeContentBlock(String name) {
+ MixinNode node = new MixinNode(name);
+ nodeStack.peek().appendChild(node);
+ nodeStack.push(node);
+
+ }
+
+ @Override
+ public void endIncludeContentBlock() {
+ nodeStack.pop();
+ }
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/LexicalUnitImpl.java b/theme-compiler/src/com/vaadin/sass/internal/parser/LexicalUnitImpl.java
index 7feeb6628a..498e1a941b 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/parser/LexicalUnitImpl.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/parser/LexicalUnitImpl.java
@@ -27,6 +27,7 @@ import java.io.Serializable;
import org.w3c.css.sac.LexicalUnit;
+import com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException;
import com.vaadin.sass.internal.util.ColorUtil;
import com.vaadin.sass.internal.util.DeepCopy;
@@ -68,12 +69,14 @@ public class LexicalUnitImpl implements LexicalUnit, SCSSLexicalUnit,
LexicalUnitImpl(int line, int column, LexicalUnitImpl previous, int i) {
this(SAC_INTEGER, line, column, previous);
this.i = i;
+ f = i;
}
LexicalUnitImpl(int line, int column, LexicalUnitImpl previous,
short dimension, String sdimension, float f) {
this(dimension, line, column, previous);
this.f = f;
+ i = (int) f;
this.dimension = dimension;
this.sdimension = sdimension;
}
@@ -137,6 +140,7 @@ public class LexicalUnitImpl implements LexicalUnit, SCSSLexicalUnit,
void setIntegerValue(int i) {
this.i = i;
+ f = i;
}
@Override
@@ -146,6 +150,7 @@ public class LexicalUnitImpl implements LexicalUnit, SCSSLexicalUnit,
public void setFloatValue(float f) {
this.f = f;
+ i = (int) f;
}
@Override
@@ -364,28 +369,65 @@ public class LexicalUnitImpl implements LexicalUnit, SCSSLexicalUnit,
@Override
public LexicalUnitImpl divide(LexicalUnitImpl denominator) {
- setFloatValue(getFloatValue() / denominator.getIntegerValue());
+ if (denominator.getLexicalUnitType() != SAC_INTEGER
+ && denominator.getLexicalUnitType() != SAC_REAL
+ && getLexicalUnitType() != denominator.getLexicalUnitType()) {
+ throw new IncompatibleUnitsException(toString());
+ }
+ setFloatValue(getFloatValue() / denominator.getFloatValue());
+ if (getLexicalUnitType() == denominator.getLexicalUnitType()) {
+ setLexicalUnitType(SAC_REAL);
+ }
+ setNextLexicalUnit(denominator.getNextLexicalUnit());
return this;
}
@Override
public LexicalUnitImpl add(LexicalUnitImpl another) {
+ checkAndSetUnit(another);
setFloatValue(getFloatValue() + another.getFloatValue());
return this;
}
@Override
public LexicalUnitImpl minus(LexicalUnitImpl another) {
+ checkAndSetUnit(another);
setFloatValue(getFloatValue() - another.getFloatValue());
return this;
}
@Override
public LexicalUnitImpl multiply(LexicalUnitImpl another) {
+ checkAndSetUnit(another);
setFloatValue(getFloatValue() * another.getIntegerValue());
return this;
}
+ protected void checkAndSetUnit(LexicalUnitImpl another) {
+ if (getLexicalUnitType() != SAC_INTEGER
+ && getLexicalUnitType() != SAC_REAL
+ && another.getLexicalUnitType() != SAC_INTEGER
+ && another.getLexicalUnitType() != SAC_REAL
+ && getLexicalUnitType() != another.getLexicalUnitType()) {
+ throw new IncompatibleUnitsException(toString());
+ }
+ if (another.getLexicalUnitType() != SAC_INTEGER
+ && another.getLexicalUnitType() != SAC_REAL) {
+ setLexicalUnitType(another.getLexicalUnitType());
+ }
+ setNextLexicalUnit(another.getNextLexicalUnit());
+ }
+
+ @Override
+ public LexicalUnitImpl modulo(LexicalUnitImpl another) {
+ if (getLexicalUnitType() != another.getLexicalUnitType()) {
+ throw new IncompatibleUnitsException(toString());
+ }
+ setIntegerValue(getIntegerValue() % another.getIntegerValue());
+ setNextLexicalUnit(another.getNextLexicalUnit());
+ return this;
+ }
+
public void replaceValue(LexicalUnitImpl another) {
// shouldn't modify 'another' directly, should only modify its copy.
LexicalUnitImpl deepCopyAnother = (LexicalUnitImpl) DeepCopy
@@ -470,16 +512,12 @@ public class LexicalUnitImpl implements LexicalUnit, SCSSLexicalUnit,
return new LexicalUnitImpl(line, column, previous, SAC_EX, null, v);
}
- public static LexicalUnitImpl createPixel(float p) {
- return new LexicalUnitImpl(0, 0, null, SAC_PIXEL, null, p);
- }
-
- static LexicalUnitImpl createPX(int line, int column,
+ public static LexicalUnitImpl createPX(int line, int column,
LexicalUnitImpl previous, float v) {
return new LexicalUnitImpl(line, column, previous, SAC_PIXEL, null, v);
}
- static LexicalUnitImpl createCM(int line, int column,
+ public static LexicalUnitImpl createCM(int line, int column,
LexicalUnitImpl previous, float v) {
return new LexicalUnitImpl(line, column, previous, SAC_CENTIMETER,
null, v);
@@ -637,6 +675,39 @@ public class LexicalUnitImpl implements LexicalUnit, SCSSLexicalUnit,
return new LexicalUnitImpl(SAC_OPERATOR_SLASH, line, column, previous);
}
+ public static LexicalUnitImpl createAdd(int line, int column,
+ LexicalUnitImpl previous) {
+ return new LexicalUnitImpl(SAC_OPERATOR_PLUS, line, column, previous);
+ }
+
+ public static LexicalUnitImpl createMinus(int line, int column,
+ LexicalUnitImpl previous) {
+ return new LexicalUnitImpl(SAC_OPERATOR_MINUS, line, column, previous);
+ }
+
+ public static LexicalUnitImpl createMultiply(int line, int column,
+ LexicalUnitImpl previous) {
+ return new LexicalUnitImpl(SAC_OPERATOR_MULTIPLY, line, column,
+ previous);
+ }
+
+ public static LexicalUnitImpl createModulo(int line, int column,
+ LexicalUnitImpl previous) {
+ return new LexicalUnitImpl(SAC_OPERATOR_MOD, line, column, previous);
+ }
+
+ public static LexicalUnitImpl createLeftParenthesis(int line, int column,
+ LexicalUnitImpl previous) {
+ return new LexicalUnitImpl(SCSS_OPERATOR_LEFT_PAREN, line, column,
+ previous);
+ }
+
+ public static LexicalUnitImpl createRightParenthesis(int line, int column,
+ LexicalUnitImpl previous) {
+ return new LexicalUnitImpl(SCSS_OPERATOR_LEFT_PAREN, line, column,
+ previous);
+ }
+
@Override
public LexicalUnitImpl clone() {
LexicalUnitImpl cloned = new LexicalUnitImpl(type, line, column, prev);
diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java
index 981b9be2b9..d938dfefe8 100644..100755
--- a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.java
@@ -1,53 +1,39 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
/* Generated By:JavaCC: Do not edit this line. Parser.java */
package com.vaadin.sass.internal.parser;
-import java.io.BufferedInputStream;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.net.URL;
+import java.io.*;
+import java.net.*;
import java.util.ArrayList;
import java.util.Locale;
+import java.util.Map;
import java.util.UUID;
-import org.w3c.css.sac.CSSException;
-import org.w3c.css.sac.CSSParseException;
import org.w3c.css.sac.ConditionFactory;
+import org.w3c.css.sac.Condition;
+import org.w3c.css.sac.SelectorFactory;
+import org.w3c.css.sac.SelectorList;
+import org.w3c.css.sac.Selector;
+import org.w3c.css.sac.SimpleSelector;
import org.w3c.css.sac.DocumentHandler;
-import org.w3c.css.sac.ErrorHandler;
import org.w3c.css.sac.InputSource;
-import org.w3c.css.sac.LexicalUnit;
+import org.w3c.css.sac.ErrorHandler;
+import org.w3c.css.sac.CSSException;
+import org.w3c.css.sac.CSSParseException;
import org.w3c.css.sac.Locator;
-import org.w3c.css.sac.SelectorFactory;
-import org.w3c.css.sac.SelectorList;
-import org.w3c.flute.parser.selectors.ConditionFactoryImpl;
+import org.w3c.css.sac.LexicalUnit;
+
import org.w3c.flute.parser.selectors.SelectorFactoryImpl;
+import org.w3c.flute.parser.selectors.ConditionFactoryImpl;
+
import org.w3c.flute.util.Encoding;
-import com.vaadin.sass.internal.handler.SCSSDocumentHandlerImpl;
-import com.vaadin.sass.internal.tree.Node;
-import com.vaadin.sass.internal.tree.VariableNode;
+import com.vaadin.sass.internal.handler.*;
+
+import com.vaadin.sass.internal.tree.*;
/**
* A CSS2 parser
- *
+ *
* @author Philippe Le H�garet
* @version $Revision: 1.15 $
*/
@@ -78,14 +64,13 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
/**
* @@TODO
- * @exception CSSException
- * Not yet implemented
+ * @exception CSSException Not yet implemented
*/
public void setLocale(Locale locale) throws CSSException {
throw new CSSException(CSSException.SAC_NOT_SUPPORTED_ERR);
}
- public InputSource getInputSource() {
+ public InputSource getInputSource(){
return source;
}
@@ -93,7 +78,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
* Set the document handler for this parser
*/
public void setDocumentHandler(DocumentHandler handler) {
- documentHandler = (SCSSDocumentHandlerImpl) handler;
+ this.documentHandler = (SCSSDocumentHandlerImpl) handler;
}
public void setSelectorFactory(SelectorFactory selectorFactory) {
@@ -108,21 +93,18 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
* Set the error handler for this parser
*/
public void setErrorHandler(ErrorHandler error) {
- errorHandler = error;
+ this.errorHandler = error;
}
/**
* Main parse methods
- *
- * @param source
- * the source of the style sheet.
- * @exception IOException
- * the source can't be parsed.
- * @exception CSSException
- * the source is not CSS valid.
+ *
+ * @param source the source of the style sheet.
+ * @exception IOException the source can't be parsed.
+ * @exception CSSException the source is not CSS valid.
*/
- public void parseStyleSheet(InputSource source) throws CSSException,
- IOException {
+ public void parseStyleSheet(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
if (selectorFactory == null) {
@@ -137,32 +119,25 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
/**
* Convenient method for URIs.
- *
- * @param systemId
- * the fully resolved URI of the style sheet.
- * @exception IOException
- * the source can't be parsed.
- * @exception CSSException
- * the source is not CSS valid.
+ *
+ * @param systemId the fully resolved URI of the style sheet.
+ * @exception IOException the source can't be parsed.
+ * @exception CSSException the source is not CSS valid.
*/
- public void parseStyleSheet(String systemId) throws CSSException,
- IOException {
+ public void parseStyleSheet(String systemId)
+ throws CSSException, IOException {
parseStyleSheet(new InputSource(systemId));
}
/**
- * This method parses only one rule (style rule or at-rule, except
- *
- * @charset).
- *
- * @param source
- * the source of the rule.
- * @exception IOException
- * the source can't be parsed.
- * @exception CSSException
- * the source is not CSS valid.
+ * This method parses only one rule (style rule or at-rule, except @charset).
+ *
+ * @param source the source of the rule.
+ * @exception IOException the source can't be parsed.
+ * @exception CSSException the source is not CSS valid.
*/
- public void parseRule(InputSource source) throws CSSException, IOException {
+ public void parseRule(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
@@ -178,16 +153,13 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
/**
* This method parses a style declaration (including the surrounding curly
* braces).
- *
- * @param source
- * the source of the style declaration.
- * @exception IOException
- * the source can't be parsed.
- * @exception CSSException
- * the source is not CSS valid.
+ *
+ * @param source the source of the style declaration.
+ * @exception IOException the source can't be parsed.
+ * @exception CSSException the source is not CSS valid.
*/
- public void parseStyleDeclaration(InputSource source) throws CSSException,
- IOException {
+ public void parseStyleDeclaration(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
@@ -202,7 +174,6 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
/**
* This methods returns "http://www.w3.org/TR/REC-CSS2".
- *
* @return the string "http://www.w3.org/TR/REC-CSS2".
*/
public String getParserVersion() {
@@ -212,8 +183,8 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
/**
* Parse methods used by DOM Level 2 implementation.
*/
- public void parseImportRule(InputSource source) throws CSSException,
- IOException {
+ public void parseImportRule(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
@@ -226,8 +197,8 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
_parseImportRule();
}
- public void parseMediaRule(InputSource source) throws CSSException,
- IOException {
+ public void parseMediaRule(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
@@ -240,8 +211,8 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
_parseMediaRule();
}
- public SelectorList parseSelectors(InputSource source) throws CSSException,
- IOException {
+ public SelectorList parseSelectors(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
@@ -256,8 +227,8 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
return expr();
}
- public boolean parsePriority(InputSource source) throws CSSException,
- IOException {
+ public boolean parsePriority(InputSource source)
+ throws CSSException, IOException {
this.source = source;
ReInit(getCharStreamWithLurk(source));
@@ -265,8 +236,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
/**
- * Convert the source into a Reader. Used only by DOM Level 2 parser
- * methods.
+ * Convert the source into a Reader. Used only by DOM Level 2 parser methods.
*/
private Reader getReader(InputSource source) throws IOException {
if (source.getCharacterStream() != null) {
@@ -278,7 +248,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
return new InputStreamReader(source.getByteStream(), "ASCII");
} else {
return new InputStreamReader(source.getByteStream(),
- source.getEncoding());
+ source.getEncoding());
}
} else {
// systemId
@@ -288,10 +258,11 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
/**
- * Convert the source into a CharStream with encoding informations. The
- * encoding can be found in the InputSource or in the CSS document. Since
- * this method marks the reader and make a reset after looking for the
- * charset declaration, you'll find the charset declaration into the stream.
+ * Convert the source into a CharStream with encoding informations.
+ * The encoding can be found in the InputSource or in the CSS document.
+ * Since this method marks the reader and make a reset after looking for
+ * the charset declaration, you'll find the charset declaration into the
+ * stream.
*/
private CharStream getCharStreamWithLurk(InputSource source)
throws CSSException, IOException {
@@ -311,7 +282,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
}
}
- // use UTF-8 as the default encoding.
+ //use UTF-8 as the default encoding.
String encoding = source.getEncoding();
InputStream input = source.getByteStream();
if (!input.markSupported()) {
@@ -321,7 +292,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
// Mark either the original stream or the wrapped stream
input.mark(100);
- if (encoding == null) {
+ if(encoding == null){
encoding = "ASCII";
char c = ' ';
@@ -330,15 +301,14 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
if (c == '@') {
// hum, is it a charset ?
- int size = 100;
+ int size = 100;
byte[] buf = new byte[size];
input.read(buf, 0, 7);
String keyword = new String(buf, 0, 7);
if (keyword.equals("charset")) {
// Yes, this is the charset declaration !
- // here I don't use the right declaration : white space are
- // ' '.
+ // here I don't use the right declaration : white space are ' '.
while ((c = (char) input.read()) == ' ') {
// find the first quote
}
@@ -365,17 +335,15 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
if (c != ';') {
// no semi colon at the end ?
throw new CSSException("invalid charset declaration: "
- + "missing semi colon");
+ + "missing semi colon");
}
encoding = new String(buf, 0, i);
if (source.getEncoding() != null) {
// compare the two encoding informations.
- // For example, I don't accept to have ASCII and after
- // UTF-8.
+ // For example, I don't accept to have ASCII and after UTF-8.
// Is it really good ? That is the question.
if (!encoding.equals(source.getEncoding())) {
- throw new CSSException(
- "invalid encoding information.");
+ throw new CSSException("invalid encoding information.");
}
}
} // else no charset declaration available
@@ -385,7 +353,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
source.setEncoding(encoding);
// set the real reader of this source.
source.setCharacterStream(new InputStreamReader(source.getByteStream(),
- Encoding.getJavaEncoding(encoding)));
+ Encoding.getJavaEncoding(encoding)));
// reset the stream (leave the charset declaration in the stream).
input.reset();
@@ -393,7 +361,6 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
private LocatorImpl currentLocator;
-
private Locator getLocator() {
if (currentLocator == null) {
currentLocator = new LocatorImpl(this);
@@ -401,7 +368,6 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
return currentLocator.reInit(this);
}
-
private LocatorImpl getLocator(Token save) {
if (currentLocator == null) {
currentLocator = new LocatorImpl(this, save);
@@ -418,8 +384,8 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
if (pe.specialConstructor) {
StringBuffer errorM = new StringBuffer();
if (pe.currentToken != null) {
- errorM.append("encountered \u005c"").append(
- pe.currentToken.next);
+ errorM.append("encountered \u005c"")
+ .append(pe.currentToken.next);
}
errorM.append('"');
if (pe.expectedTokenSequences.length != 0) {
@@ -435,10 +401,10 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
}
errorHandler.error(new CSSParseException(errorM.toString(),
- l, e));
+ l, e));
} else {
- errorHandler.error(new CSSParseException(e.getMessage(), l,
- e));
+ errorHandler.error(new CSSParseException(e.getMessage(),
+ l, e));
}
} else if (e == null) {
errorHandler.error(new CSSParseException("error", l, null));
@@ -449,2369 +415,509 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
}
private void reportWarningSkipText(Locator l, String text) {
- if (errorHandler != null && text != null) {
+ if (errorHandler != null && text != null) {
errorHandler.warning(new CSSParseException("Skipping: " + text, l));
}
}
- /*
- * The grammar of CSS2
- */
-
- /**
- * The main entry for the parser.
- *
- * @exception ParseException
- * exception during the parse
- */
- final public void parserUnit() throws ParseException {
- try {
- documentHandler.startDocument(source);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case CHARSET_SYM:
- charset();
- break;
- default:
- jj_la1[0] = jj_gen;
- ;
- }
- label_1: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- case CDO:
- case CDC:
- case ATKEYWORD:
- ;
- break;
- default:
- jj_la1[1] = jj_gen;
- break label_1;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- jj_consume_token(S);
- comments();
- break;
- case CDO:
- case CDC:
- case ATKEYWORD:
- ignoreStatement();
- break;
- default:
- jj_la1[2] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- label_2: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IMPORT_SYM:
- ;
- break;
- default:
- jj_la1[3] = jj_gen;
- break label_2;
- }
- importDeclaration();
- label_3: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case CDO:
- case CDC:
- case ATKEYWORD:
- ;
- break;
- default:
- jj_la1[4] = jj_gen;
- break label_3;
- }
- ignoreStatement();
- label_4: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[5] = jj_gen;
- break label_4;
- }
- jj_consume_token(S);
- }
- }
- }
- afterImportDeclaration();
- jj_consume_token(0);
- } finally {
- documentHandler.endDocument(source);
- }
- }
-
- final public void charset() throws ParseException {
- Token n;
- try {
- jj_consume_token(CHARSET_SYM);
- label_5: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[6] = jj_gen;
- break label_5;
- }
- jj_consume_token(S);
- }
- n = jj_consume_token(STRING);
- label_6: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[7] = jj_gen;
- break label_6;
- }
- jj_consume_token(S);
- }
- jj_consume_token(SEMICOLON);
- } catch (ParseException e) {
- reportError(getLocator(e.currentToken.next), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- } catch (Exception e) {
- reportError(getLocator(), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- }
- }
-
- final public void afterImportDeclaration() throws ParseException {
- String ret;
- Locator l;
- label_7: while (true) {
- ;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DEBUG_SYM:
- case WARN_SYM:
- debuggingDirective();
- break;
- case MIXIN_SYM:
- mixinDirective();
- break;
- case EACH_SYM:
- case IF_SYM:
- controlDirective();
- break;
- case INCLUDE_SYM:
- includeDirective();
- break;
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case IDENT:
- case HASH:
- styleRule();
- break;
- case MEDIA_SYM:
- media();
- break;
- case PAGE_SYM:
- page();
- break;
- case FONT_FACE_SYM:
- fontFace();
- break;
- case KEY_FRAME_SYM:
- keyframes();
- break;
- default:
- jj_la1[8] = jj_gen;
- if (jj_2_1(2147483647)) {
- variable();
- } else {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case VARIABLE:
- listModifyDirective();
- break;
- default:
- jj_la1[9] = jj_gen;
- l = getLocator();
- ret = skipStatement();
- if ((ret == null) || (ret.length() == 0)) {
- {
- if (true) {
- return;
- }
- }
- }
- if (ret.charAt(0) == '@') {
- documentHandler.unrecognizedRule(ret);
- } else {
- reportWarningSkipText(l, ret);
- }
- }
- }
- }
- label_8: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case CDO:
- case CDC:
- case ATKEYWORD:
- ;
- break;
- default:
- jj_la1[10] = jj_gen;
- break label_8;
- }
- ignoreStatement();
- label_9: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[11] = jj_gen;
- break label_9;
- }
- jj_consume_token(S);
- }
- }
- }
- }
+/*
+ * The grammar of CSS2
+ */
- final public void ignoreStatement() throws ParseException {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+/**
+ * The main entry for the parser.
+ *
+ * @exception ParseException exception during the parse
+ */
+ final public void parserUnit() throws ParseException {
+ try {
+ documentHandler.startDocument(source);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case CHARSET_SYM:
+ charset();
+ break;
+ default:
+ jj_la1[0] = jj_gen;
+ ;
+ }
+ label_1:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
case CDO:
- jj_consume_token(CDO);
- break;
case CDC:
- jj_consume_token(CDC);
- break;
case ATKEYWORD:
- atRuleDeclaration();
- break;
+ ;
+ break;
default:
- jj_la1[12] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
-
- /**
- * The import statement
- *
- * @exception ParseException
- * exception during the parse
- */
- final public void importDeclaration() throws ParseException {
- Token n;
- String uri;
- MediaListImpl ml = new MediaListImpl();
- boolean isURL = false;
- try {
- jj_consume_token(IMPORT_SYM);
- label_10: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[13] = jj_gen;
- break label_10;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case STRING:
- n = jj_consume_token(STRING);
- uri = convertStringIndex(n.image, 1, n.image.length() - 1);
- break;
- case URL:
- n = jj_consume_token(URL);
- isURL = true;
- uri = n.image.substring(4, n.image.length() - 1).trim();
- if ((uri.charAt(0) == '"') || (uri.charAt(0) == '\u005c'')) {
- uri = uri.substring(1, uri.length() - 1);
- }
- break;
- default:
- jj_la1[14] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_11: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[15] = jj_gen;
- break label_11;
- }
- jj_consume_token(S);
- }
- mediaStatement(ml);
- jj_consume_token(SEMICOLON);
- label_12: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[16] = jj_gen;
- break label_12;
- }
- jj_consume_token(S);
- }
- if (ml.getLength() == 0) {
- // see section 6.3 of the CSS2 recommandation.
- ml.addItem("all");
- }
- documentHandler.importStyle(uri, ml, isURL);
- } catch (ParseException e) {
- reportError(getLocator(), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- }
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void keyframes() throws ParseException {
- Token n;
- boolean start = false;
- String keyframeName = null;
- String animationname = "";
- try {
- n = jj_consume_token(KEY_FRAME_SYM);
- label_13: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[17] = jj_gen;
- break label_13;
- }
- jj_consume_token(S);
- }
- keyframeName = n.image;
- label_14: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- n = jj_consume_token(IDENT);
- animationname += n.image;
- break;
- case INTERPOLATION:
- n = jj_consume_token(INTERPOLATION);
- animationname += n.image;
- break;
- default:
- jj_la1[18] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- ;
- break;
- default:
- jj_la1[19] = jj_gen;
- break label_14;
- }
- }
- label_15: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[20] = jj_gen;
- break label_15;
- }
- jj_consume_token(S);
- }
- start = true;
- documentHandler.startKeyFrames(keyframeName, animationname);
- jj_consume_token(LBRACE);
- label_16: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[21] = jj_gen;
- break label_16;
- }
- jj_consume_token(S);
- }
- label_17: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case TO:
- case FROM:
- case PERCENTAGE:
- ;
- break;
- default:
- jj_la1[22] = jj_gen;
- break label_17;
- }
- keyframeSelector();
- }
- jj_consume_token(RBRACE);
- label_18: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[23] = jj_gen;
- break label_18;
- }
- jj_consume_token(S);
- }
- } catch (ParseException e) {
- reportError(getLocator(), e);
- skipStatement();
- } finally {
- if (start) {
- documentHandler.endKeyFrames();
- }
- }
- }
-
- final public void keyframeSelector() throws ParseException {
- Token n;
- boolean start = false;
- try {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case FROM:
- n = jj_consume_token(FROM);
- break;
- case TO:
- n = jj_consume_token(TO);
- break;
- case PERCENTAGE:
- n = jj_consume_token(PERCENTAGE);
- break;
- default:
- jj_la1[24] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_19: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[25] = jj_gen;
- break label_19;
- }
- jj_consume_token(S);
- }
- jj_consume_token(LBRACE);
- label_20: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[26] = jj_gen;
- break label_20;
- }
- jj_consume_token(S);
- }
- start = true;
- documentHandler.startKeyframeSelector(n.image);
- label_21: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EACH_SYM:
- case IF_SYM:
- case EXTEND_SYM:
- case MICROSOFT_RULE:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ;
- break;
- default:
- jj_la1[27] = jj_gen;
- break label_21;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ifContentStatement();
- break;
- case EACH_SYM:
- case IF_SYM:
- controlDirective();
- break;
- case MICROSOFT_RULE:
- microsoftExtension();
- break;
- default:
- jj_la1[28] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- jj_consume_token(RBRACE);
- label_22: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[29] = jj_gen;
- break label_22;
- }
- jj_consume_token(S);
- }
- } catch (ThrowedParseException e) {
- if (errorHandler != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.e.currentToken.next.beginLine,
- e.e.currentToken.next.beginColumn - 1);
- reportError(li, e.e);
- }
- } catch (ParseException e) {
- reportError(getLocator(), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- } catch (TokenMgrError e) {
- reportWarningSkipText(getLocator(), skipStatement());
- } finally {
- if (start) {
- documentHandler.endKeyframeSelector();
- }
- }
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- /* see http://www.w3.org/TR/css3-mediaqueries/ */
- final public void media() throws ParseException {
- boolean start = false;
- String ret;
- MediaListImpl ml = new MediaListImpl();
- try {
- jj_consume_token(MEDIA_SYM);
- label_23: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[30] = jj_gen;
- break label_23;
- }
- jj_consume_token(S);
- }
- mediaStatement(ml);
- start = true;
- documentHandler.startMedia(ml);
- jj_consume_token(LBRACE);
- label_24: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[31] = jj_gen;
- break label_24;
- }
- jj_consume_token(S);
- }
- label_25: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case CDO:
- case LBRACE:
- case DASHMATCH:
- case INCLUDES:
- case PLUS:
- case MINUS:
- case COMMA:
- case SEMICOLON:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case NONASCII:
- case DEBUG_SYM:
- case WARN_SYM:
- case STRING:
- case IDENT:
- case NUMBER:
- case URL:
- case PERCENTAGE:
- case HASH:
- case IMPORT_SYM:
- case MEDIA_SYM:
- case CHARSET_SYM:
- case PAGE_SYM:
- case FONT_FACE_SYM:
- case ATKEYWORD:
- case IMPORTANT_SYM:
- case UNICODERANGE:
- case FUNCTION:
- case UNKNOWN:
- ;
- break;
- default:
- jj_la1[32] = jj_gen;
- break label_25;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DEBUG_SYM:
- case WARN_SYM:
- debuggingDirective();
- break;
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case IDENT:
- case HASH:
- styleRule();
- break;
- case CDO:
- case LBRACE:
- case DASHMATCH:
- case INCLUDES:
- case MINUS:
- case COMMA:
- case SEMICOLON:
- case NONASCII:
- case STRING:
- case NUMBER:
- case URL:
- case PERCENTAGE:
- case IMPORT_SYM:
- case MEDIA_SYM:
- case CHARSET_SYM:
- case PAGE_SYM:
- case FONT_FACE_SYM:
- case ATKEYWORD:
- case IMPORTANT_SYM:
- case UNICODERANGE:
- case FUNCTION:
- case UNKNOWN:
- skipUnknownRule();
- break;
- default:
- jj_la1[33] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- jj_consume_token(RBRACE);
- label_26: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[34] = jj_gen;
- break label_26;
- }
- jj_consume_token(S);
- }
- } catch (ParseException e) {
- reportError(getLocator(), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- } finally {
- if (start) {
- documentHandler.endMedia(ml);
- }
- }
- }
-
- final public void mediaStatement(MediaListImpl ml) throws ParseException {
- Token t;
- t = getToken(1);
- // loop over comma separated parts, add each to ml
- while ((t.kind != LBRACE) && (t.kind != EOF) && (t.kind != SEMICOLON)) {
- StringBuffer s = new StringBuffer();
- s.append(getToken(0).image);
- while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF)
- && (t.kind != SEMICOLON)) {
- s.append(t.image);
- getNextToken();
- t = getToken(1);
- }
- if (t.kind == COMMA) {
- // skip the comma and the token before it that is still the
- // active token
- getNextToken();
- getNextToken();
- t = getToken(1);
- }
- String str = s.toString().trim();
- if (str.length() > 0) {
- ml.addItem(str);
- }
+ jj_la1[1] = jj_gen;
+ break label_1;
}
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String medium() throws ParseException {
- Token n;
- n = jj_consume_token(IDENT);
- {
- if (true) {
- return convertIdent(n.image);
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void page() throws ParseException {
- boolean start = false;
- Token n = null;
- String page = null;
- String pseudo = null;
- try {
- jj_consume_token(PAGE_SYM);
- label_27: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[35] = jj_gen;
- break label_27;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- n = jj_consume_token(IDENT);
- label_28: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[36] = jj_gen;
- break label_28;
- }
- jj_consume_token(S);
- }
- break;
- default:
- jj_la1[37] = jj_gen;
- ;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COLON:
- pseudo = pseudo_page();
- break;
- default:
- jj_la1[38] = jj_gen;
- ;
- }
- if (n != null) {
- page = convertIdent(n.image);
- }
- jj_consume_token(LBRACE);
- label_29: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[39] = jj_gen;
- break label_29;
- }
- jj_consume_token(S);
- }
- start = true;
- documentHandler.startPage(page, pseudo);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[40] = jj_gen;
- ;
- }
- label_30: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[41] = jj_gen;
- break label_30;
- }
- jj_consume_token(SEMICOLON);
- label_31: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[42] = jj_gen;
- break label_31;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[43] = jj_gen;
- ;
- }
- }
- jj_consume_token(RBRACE);
- label_32: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[44] = jj_gen;
- break label_32;
- }
- jj_consume_token(S);
- }
- } catch (ParseException e) {
- if (errorHandler != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.currentToken.next.beginLine,
- e.currentToken.next.beginColumn - 1);
- reportError(li, e);
- skipStatement();
- // reportWarningSkipText(li, skipStatement());
- } else {
- skipStatement();
- }
- } finally {
- if (start) {
- documentHandler.endPage(page, pseudo);
- }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ jj_consume_token(S);
+ comments();
+ break;
+ case CDO:
+ case CDC:
+ case ATKEYWORD:
+ ignoreStatement();
+ break;
+ default:
+ jj_la1[2] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ label_2:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IMPORT_SYM:
+ ;
+ break;
+ default:
+ jj_la1[3] = jj_gen;
+ break label_2;
}
- }
-
- final public String pseudo_page() throws ParseException {
- Token n;
- jj_consume_token(COLON);
- n = jj_consume_token(IDENT);
- label_33: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ importDeclaration();
+ label_3:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case CDO:
+ case CDC:
+ case ATKEYWORD:
+ ;
+ break;
+ default:
+ jj_la1[4] = jj_gen;
+ break label_3;
+ }
+ ignoreStatement();
+ label_4:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case S:
- ;
- break;
+ ;
+ break;
default:
- jj_la1[45] = jj_gen;
- break label_33;
+ jj_la1[5] = jj_gen;
+ break label_4;
}
jj_consume_token(S);
- }
- {
- if (true) {
- return convertIdent(n.image);
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public void fontFace() throws ParseException {
- boolean start = false;
- try {
- jj_consume_token(FONT_FACE_SYM);
- label_34: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[46] = jj_gen;
- break label_34;
- }
- jj_consume_token(S);
- }
- jj_consume_token(LBRACE);
- label_35: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[47] = jj_gen;
- break label_35;
- }
- jj_consume_token(S);
- }
- start = true;
- documentHandler.startFontFace();
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[48] = jj_gen;
- ;
- }
- label_36: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[49] = jj_gen;
- break label_36;
- }
- jj_consume_token(SEMICOLON);
- label_37: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[50] = jj_gen;
- break label_37;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[51] = jj_gen;
- ;
- }
- }
- jj_consume_token(RBRACE);
- label_38: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[52] = jj_gen;
- break label_38;
- }
- jj_consume_token(S);
- }
- } catch (ParseException e) {
- reportError(getLocator(), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- } finally {
- if (start) {
- documentHandler.endFontFace();
- }
- }
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void atRuleDeclaration() throws ParseException {
- Token n;
- String ret;
- n = jj_consume_token(ATKEYWORD);
- ret = skipStatement();
- if ((ret != null) && (ret.charAt(0) == '@')) {
- documentHandler.unrecognizedRule(ret);
+ }
+ }
+ }
+ afterImportDeclaration();
+ jj_consume_token(0);
+ } finally {
+ documentHandler.endDocument(source);
+ }
+ }
+
+ final public void charset() throws ParseException {
+ Token n;
+ try {
+ jj_consume_token(CHARSET_SYM);
+ label_5:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[6] = jj_gen;
+ break label_5;
+ }
+ jj_consume_token(S);
+ }
+ n = jj_consume_token(STRING);
+ label_6:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[7] = jj_gen;
+ break label_6;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(SEMICOLON);
+ } catch (ParseException e) {
+ reportError(getLocator(e.currentToken.next), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
+
+ } catch (Exception e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
+
+ }
+ }
+
+ final public void afterImportDeclaration() throws ParseException {
+ String ret;
+ Locator l;
+ label_7:
+ while (true) {
+ ;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case DEBUG_SYM:
+ case WARN_SYM:
+ debuggingDirective();
+ break;
+ case MIXIN_SYM:
+ mixinDirective();
+ break;
+ case EACH_SYM:
+ case IF_SYM:
+ controlDirective();
+ break;
+ case INCLUDE_SYM:
+ includeDirective();
+ break;
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case IDENT:
+ case HASH:
+ styleRule();
+ break;
+ case MEDIA_SYM:
+ media();
+ break;
+ case PAGE_SYM:
+ page();
+ break;
+ case FONT_FACE_SYM:
+ fontFace();
+ break;
+ case KEY_FRAME_SYM:
+ keyframes();
+ break;
+ default:
+ jj_la1[8] = jj_gen;
+ if (jj_2_1(2147483647)) {
+ variable();
} else {
- reportWarningSkipText(getLocator(), ret);
- }
- }
-
- final public void skipUnknownRule() throws ParseException {
- Token n;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case ATKEYWORD:
- n = jj_consume_token(ATKEYWORD);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case VARIABLE:
+ listModifyDirective();
break;
+ default:
+ jj_la1[9] = jj_gen;
+ l = getLocator();
+ ret = skipStatement();
+ if ((ret == null) || (ret.length() == 0)) {
+ {if (true) return;}
+ }
+ if (ret.charAt(0) == '@') {
+ documentHandler.unrecognizedRule(ret);
+ } else {
+ reportWarningSkipText(l, ret);
+ }
+ }
+ }
+ }
+ label_8:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case CDO:
- n = jj_consume_token(CDO);
- break;
- case CHARSET_SYM:
- n = jj_consume_token(CHARSET_SYM);
- break;
- case COMMA:
- n = jj_consume_token(COMMA);
- break;
- case DASHMATCH:
- n = jj_consume_token(DASHMATCH);
- break;
- case FONT_FACE_SYM:
- n = jj_consume_token(FONT_FACE_SYM);
- break;
- case FUNCTION:
- n = jj_consume_token(FUNCTION);
- break;
- case IMPORTANT_SYM:
- n = jj_consume_token(IMPORTANT_SYM);
- break;
- case IMPORT_SYM:
- n = jj_consume_token(IMPORT_SYM);
- break;
- case INCLUDES:
- n = jj_consume_token(INCLUDES);
- break;
- case LBRACE:
- n = jj_consume_token(LBRACE);
- break;
- case MEDIA_SYM:
- n = jj_consume_token(MEDIA_SYM);
- break;
- case NONASCII:
- n = jj_consume_token(NONASCII);
- break;
- case NUMBER:
- n = jj_consume_token(NUMBER);
- break;
- case PAGE_SYM:
- n = jj_consume_token(PAGE_SYM);
- break;
- case PERCENTAGE:
- n = jj_consume_token(PERCENTAGE);
- break;
- case STRING:
- n = jj_consume_token(STRING);
- break;
- case UNICODERANGE:
- n = jj_consume_token(UNICODERANGE);
- break;
- case URL:
- n = jj_consume_token(URL);
- break;
- case SEMICOLON:
- n = jj_consume_token(SEMICOLON);
- break;
- case MINUS:
- n = jj_consume_token(MINUS);
- break;
- case UNKNOWN:
- n = jj_consume_token(UNKNOWN);
- break;
+ case CDC:
+ case ATKEYWORD:
+ ;
+ break;
default:
- jj_la1[53] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- String ret;
- Locator loc = getLocator();
- ret = skipStatement();
- if ((ret != null) && (n.image.charAt(0) == '@')) {
- documentHandler.unrecognizedRule(ret);
- } else {
- reportWarningSkipText(loc, ret);
+ jj_la1[10] = jj_gen;
+ break label_8;
}
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public char combinator() throws ParseException {
- char connector = ' ';
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- connector = combinatorChar();
+ ignoreStatement();
+ label_9:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
break;
+ default:
+ jj_la1[11] = jj_gen;
+ break label_9;
+ }
+ jj_consume_token(S);
+ }
+ }
+ }
+ }
+
+ final public void ignoreStatement() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case CDO:
+ jj_consume_token(CDO);
+ break;
+ case CDC:
+ jj_consume_token(CDC);
+ break;
+ case ATKEYWORD:
+ atRuleDeclaration();
+ break;
+ default:
+ jj_la1[12] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+/**
+ * The import statement
+ *
+ * @exception ParseException exception during the parse
+ */
+ final public void importDeclaration() throws ParseException {
+ Token n;
+ String uri;
+ MediaListImpl ml = new MediaListImpl();
+ boolean isURL = false;
+ try {
+ jj_consume_token(IMPORT_SYM);
+ label_10:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case S:
- jj_consume_token(S);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- connector = combinatorChar();
- break;
- default:
- jj_la1[54] = jj_gen;
- ;
- }
- break;
+ ;
+ break;
default:
- jj_la1[55] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- {
- if (true) {
- return connector;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /** to refactor combinator and reuse in selector(). */
- final public char combinatorChar() throws ParseException {
- Token t;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- t = jj_consume_token(PLUS);
- break;
- case PRECEDES:
- t = jj_consume_token(PRECEDES);
- break;
- case SIBLING:
- t = jj_consume_token(SIBLING);
- break;
+ jj_la1[13] = jj_gen;
+ break label_10;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case STRING:
+ n = jj_consume_token(STRING);
+ uri = convertStringIndex(n.image, 1,
+ n.image.length() -1);
+ break;
+ case URL:
+ n = jj_consume_token(URL);
+ isURL=true;
+ uri = n.image.substring(4, n.image.length()-1).trim();
+ if ((uri.charAt(0) == '"')
+ || (uri.charAt(0) == '\u005c'')) {
+ uri = uri.substring(1, uri.length()-1);
+ }
+ break;
+ default:
+ jj_la1[14] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_11:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[56] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_39: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[57] = jj_gen;
- break label_39;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return t.image.charAt(0);
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public void microsoftExtension() throws ParseException {
- Token n;
- String name = "";
- String value = "";
- // This is not really taking the syntax of filter rules into account
- n = jj_consume_token(MICROSOFT_RULE);
- label_40: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[58] = jj_gen;
- break label_40;
- }
- jj_consume_token(S);
- }
- name = n.image;
- jj_consume_token(COLON);
- label_41: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- n = jj_consume_token(IDENT);
- value += n.image;
- break;
- case NUMBER:
- n = jj_consume_token(NUMBER);
- value += n.image;
- break;
- case STRING:
- n = jj_consume_token(STRING);
- value += n.image;
- break;
- case COMMA:
- n = jj_consume_token(COMMA);
- value += n.image;
- break;
- case INTERPOLATION:
- n = jj_consume_token(INTERPOLATION);
- value += n.image;
- break;
- case COLON:
- n = jj_consume_token(COLON);
- value += n.image;
- break;
- case FUNCTION:
- n = jj_consume_token(FUNCTION);
- value += n.image;
- break;
- case RPARAN:
- n = jj_consume_token(RPARAN);
- value += n.image;
- break;
- case EQ:
- n = jj_consume_token(EQ);
- value += n.image;
- break;
- case DOT:
- n = jj_consume_token(DOT);
- value += n.image;
- break;
- case S:
- n = jj_consume_token(S);
- if (value.lastIndexOf(' ') != value.length() - 1) {
- value += n.image;
- }
- break;
- default:
- jj_la1[59] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- case EQ:
- case COMMA:
- case DOT:
- case RPARAN:
- case COLON:
- case INTERPOLATION:
- case STRING:
- case IDENT:
- case NUMBER:
- case FUNCTION:
- ;
- break;
- default:
- jj_la1[60] = jj_gen;
- break label_41;
- }
- }
- jj_consume_token(SEMICOLON);
- label_42: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[61] = jj_gen;
- break label_42;
- }
- jj_consume_token(S);
- }
- documentHandler.microsoftDirective(name, value);
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String property() throws ParseException {
- Token t;
- String s = "";
- label_43: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- t = jj_consume_token(IDENT);
- s += t.image;
- break;
- case INTERPOLATION:
- t = jj_consume_token(INTERPOLATION);
- s += t.image;
- break;
- default:
- jj_la1[62] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- ;
- break;
- default:
- jj_la1[63] = jj_gen;
- break label_43;
- }
- }
- label_44: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[64] = jj_gen;
- break label_44;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return s;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public String variableName() throws ParseException {
- Token n;
- n = jj_consume_token(VARIABLE);
- label_45: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[65] = jj_gen;
- break label_45;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return convertIdent(n.image.substring(1));
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public String functionName() throws ParseException {
- Token n;
- n = jj_consume_token(FUNCTION);
- label_46: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[66] = jj_gen;
- break label_46;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return convertIdent(n.image.substring(0, n.image.length() - 1));
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void styleRule() throws ParseException {
- boolean start = false;
- ArrayList<String> l = null;
- Token save;
- Locator loc;
- try {
- l = selectorList();
- save = token;
- jj_consume_token(LBRACE);
- label_47: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[67] = jj_gen;
- break label_47;
- }
- jj_consume_token(S);
- }
- start = true;
- documentHandler.startSelector(l);
- label_48: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EACH_SYM:
- case IF_SYM:
- case EXTEND_SYM:
- case MICROSOFT_RULE:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ;
- break;
- default:
- jj_la1[68] = jj_gen;
- break label_48;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ifContentStatement();
- break;
- case EACH_SYM:
- case IF_SYM:
- controlDirective();
- break;
- case MICROSOFT_RULE:
- microsoftExtension();
- break;
- default:
- jj_la1[69] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- jj_consume_token(RBRACE);
- label_49: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[70] = jj_gen;
- break label_49;
- }
- jj_consume_token(S);
- }
- } catch (ThrowedParseException e) {
- if (errorHandler != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.e.currentToken.next.beginLine,
- e.e.currentToken.next.beginColumn - 1);
- reportError(li, e.e);
- }
- } catch (ParseException e) {
- reportError(getLocator(), e);
- skipStatement();
- // reportWarningSkipText(getLocator(), skipStatement());
-
- } catch (TokenMgrError e) {
- reportWarningSkipText(getLocator(), skipStatement());
- } finally {
- if (start) {
- documentHandler.endSelector();
- }
- }
- }
-
- final public ArrayList<String> selectorList() throws ParseException {
- ArrayList<String> selectors = new ArrayList<String>();
- String selector;
- selector = selector();
- label_50: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- ;
- break;
- default:
- jj_la1[71] = jj_gen;
- break label_50;
- }
- jj_consume_token(COMMA);
- label_51: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[72] = jj_gen;
- break label_51;
- }
- jj_consume_token(S);
- }
- selectors.add(selector);
- selector = selector();
- }
- selectors.add(selector);
- {
- if (true) {
- return selectors;
- }
+ jj_la1[15] = jj_gen;
+ break label_11;
+ }
+ jj_consume_token(S);
+ }
+ mediaStatement(ml);
+ jj_consume_token(SEMICOLON);
+ label_12:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[16] = jj_gen;
+ break label_12;
}
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String selector() throws ParseException {
- String selector = null;
- char comb;
- try {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case IDENT:
- case HASH:
- selector = simple_selector(null, ' ');
- break;
- case PLUS:
- case PRECEDES:
- case SIBLING:
- comb = combinatorChar();
- selector = simple_selector(selector, comb);
- break;
- default:
- jj_la1[73] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_52: while (true) {
- if (jj_2_2(2)) {
- ;
- } else {
- break label_52;
- }
- comb = combinator();
- selector = simple_selector(selector, comb);
- }
- label_53: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[74] = jj_gen;
- break label_53;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return selector;
- }
- }
- } catch (ParseException e) {
- /*
- * Token t = getToken(1); StringBuffer s = new StringBuffer();
- * s.append(getToken(0).image); while ((t.kind != COMMA) && (t.kind
- * != SEMICOLON) && (t.kind != LBRACE) && (t.kind != EOF)) {
- * s.append(t.image); getNextToken(); t = getToken(1); }
- * reportWarningSkipText(getLocator(), s.toString());
- */
- Token t = getToken(1);
- while ((t.kind != COMMA) && (t.kind != SEMICOLON)
- && (t.kind != LBRACE) && (t.kind != EOF)) {
- getNextToken();
- t = getToken(1);
- }
+ jj_consume_token(S);
+ }
+ if (ml.getLength() == 0) {
+ // see section 6.3 of the CSS2 recommandation.
+ ml.addItem("all");
+ }
+ documentHandler.importStyle(uri, ml, isURL);
+ } catch (ParseException e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
- {
- if (true) {
- throw new ThrowedParseException(e);
- }
- }
- }
- throw new Error("Missing return statement in function");
}
+ }
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String simple_selector(String selector, char comb)
- throws ParseException {
- String simple_current = null;
- String cond = null;
-
- pseudoElt = null;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case ANY:
- case PARENT:
- case INTERPOLATION:
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void keyframes() throws ParseException {
+ Token n;
+ boolean start = false;
+ String keyframeName = null;
+ String animationname = "";
+ try {
+ n = jj_consume_token(KEY_FRAME_SYM);
+ label_13:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[17] = jj_gen;
+ break label_13;
+ }
+ jj_consume_token(S);
+ }
+ keyframeName = n.image;
+ label_14:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case IDENT:
- simple_current = element_name();
- label_54: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case LBRACKET:
- case DOT:
- case COLON:
- case HASH:
- ;
- break;
- default:
- jj_la1[75] = jj_gen;
- break label_54;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case HASH:
- cond = hash(cond);
- break;
- case DOT:
- cond = _class(cond);
- break;
- case LBRACKET:
- cond = attrib(cond);
- break;
- case COLON:
- cond = pseudo(cond);
- break;
- default:
- jj_la1[76] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- break;
- case HASH:
- cond = hash(cond);
- label_55: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case LBRACKET:
- case DOT:
- case COLON:
- ;
- break;
- default:
- jj_la1[77] = jj_gen;
- break label_55;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DOT:
- cond = _class(cond);
- break;
- case LBRACKET:
- cond = attrib(cond);
- break;
- case COLON:
- cond = pseudo(cond);
- break;
- default:
- jj_la1[78] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- break;
- case DOT:
- cond = _class(cond);
- label_56: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case LBRACKET:
- case DOT:
- case COLON:
- case HASH:
- ;
- break;
- default:
- jj_la1[79] = jj_gen;
- break label_56;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case HASH:
- cond = hash(cond);
- break;
- case DOT:
- cond = _class(cond);
- break;
- case LBRACKET:
- cond = attrib(cond);
- break;
- case COLON:
- cond = pseudo(cond);
- break;
- default:
- jj_la1[80] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- break;
- case COLON:
- cond = pseudo(cond);
- label_57: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case LBRACKET:
- case DOT:
- case COLON:
- case HASH:
- ;
- break;
- default:
- jj_la1[81] = jj_gen;
- break label_57;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case HASH:
- cond = hash(cond);
- break;
- case DOT:
- cond = _class(cond);
- break;
- case LBRACKET:
- cond = attrib(cond);
- break;
- case COLON:
- cond = pseudo(cond);
- break;
- default:
- jj_la1[82] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- break;
- case LBRACKET:
- cond = attrib(cond);
- label_58: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case LBRACKET:
- case DOT:
- case COLON:
- case HASH:
- ;
- break;
- default:
- jj_la1[83] = jj_gen;
- break label_58;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case HASH:
- cond = hash(cond);
- break;
- case DOT:
- cond = _class(cond);
- break;
- case LBRACKET:
- cond = attrib(cond);
- break;
- case COLON:
- cond = pseudo(cond);
- break;
- default:
- jj_la1[84] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- break;
+ n = jj_consume_token(IDENT);
+ animationname += n.image;
+ break;
+ case INTERPOLATION:
+ n = jj_consume_token(INTERPOLATION);
+ animationname += n.image;
+ break;
default:
- jj_la1[85] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- if (simple_current == null) {
- simple_current = "";
- }
- if (cond != null) {
- simple_current = simple_current + cond;
+ jj_la1[18] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
}
- StringBuilder builder = new StringBuilder();
- switch (comb) {
- case ' ':
- if (selector != null) {
- builder.append(selector).append(" ");
- }
- break;
- case '+':
- case '>':
- case '~':
- if (selector != null) {
- builder.append(selector).append(" ");
- }
- builder.append(comb).append(" ");
- break;
- default: {
- if (true) {
- throw new ParseException("invalid state. send a bug report");
- }
- }
- }
- builder.append(simple_current);
- selector = builder.toString();
-
- if (pseudoElt != null) {
- selector = selector + pseudoElt;
- }
- {
- if (true) {
- return selector;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String _class(String pred) throws ParseException {
- Token t;
- String s = ".";
- jj_consume_token(DOT);
- label_59: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- t = jj_consume_token(IDENT);
- s += t.image;
- break;
- case INTERPOLATION:
- t = jj_consume_token(INTERPOLATION);
- s += t.image;
- break;
- default:
- jj_la1[86] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- ;
- break;
- default:
- jj_la1[87] = jj_gen;
- break label_59;
- }
- }
- if (pred == null) {
- {
- if (true) {
- return s;
- }
- }
- } else {
- {
- if (true) {
- return pred + s;
- }
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String element_name() throws ParseException {
- Token t;
- String s = "";
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case INTERPOLATION:
case IDENT:
- label_60: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- t = jj_consume_token(IDENT);
- s += t.image;
- break;
- case INTERPOLATION:
- t = jj_consume_token(INTERPOLATION);
- s += t.image;
- break;
- default:
- jj_la1[88] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- ;
- break;
- default:
- jj_la1[89] = jj_gen;
- break label_60;
- }
- }
- {
- if (true) {
- return s;
- }
- }
- break;
- case ANY:
- jj_consume_token(ANY);
- {
- if (true) {
- return "*";
- }
- }
- break;
- case PARENT:
- jj_consume_token(PARENT);
- {
- if (true) {
- return "&";
- }
- }
- break;
+ ;
+ break;
default:
- jj_la1[90] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[19] = jj_gen;
+ break label_14;
}
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String attrib(String pred) throws ParseException {
- int cases = 0;
- Token att = null;
- Token val = null;
- String attValue = null;
- jj_consume_token(LBRACKET);
- label_61: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[91] = jj_gen;
- break label_61;
- }
- jj_consume_token(S);
- }
- att = jj_consume_token(IDENT);
- label_62: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[92] = jj_gen;
- break label_62;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DASHMATCH:
- case CARETMATCH:
- case DOLLARMATCH:
- case STARMATCH:
- case INCLUDES:
- case EQ:
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case EQ:
- jj_consume_token(EQ);
- cases = 1;
- break;
- case INCLUDES:
- jj_consume_token(INCLUDES);
- cases = 2;
- break;
- case DASHMATCH:
- jj_consume_token(DASHMATCH);
- cases = 3;
- break;
- case CARETMATCH:
- jj_consume_token(CARETMATCH);
- cases = 4;
- break;
- case DOLLARMATCH:
- jj_consume_token(DOLLARMATCH);
- cases = 5;
- break;
- case STARMATCH:
- jj_consume_token(STARMATCH);
- cases = 6;
- break;
- default:
- jj_la1[93] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_63: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[94] = jj_gen;
- break label_63;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- val = jj_consume_token(IDENT);
- attValue = val.image;
- break;
- case STRING:
- val = jj_consume_token(STRING);
- attValue = val.image;
- break;
- default:
- jj_la1[95] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_64: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[96] = jj_gen;
- break label_64;
- }
- jj_consume_token(S);
- }
- break;
+ }
+ label_15:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[97] = jj_gen;
- ;
- }
- jj_consume_token(RBRACKET);
- String name = convertIdent(att.image);
- String c;
- switch (cases) {
- case 0:
- c = name;
- break;
- case 1:
- c = name + "=" + attValue;
- break;
- case 2:
- c = name + "~=" + attValue;
- break;
- case 3:
- c = name + "|=" + attValue;
- break;
- case 4:
- c = name + "^=" + attValue;
- break;
- case 5:
- c = name + "$=" + attValue;
- break;
- case 6:
- c = name + "*=" + attValue;
- break;
+ jj_la1[20] = jj_gen;
+ break label_15;
+ }
+ jj_consume_token(S);
+ }
+ start = true; documentHandler.startKeyFrames(keyframeName, animationname);
+ jj_consume_token(LBRACE);
+ label_16:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- // never reached.
- c = null;
- }
- c = "[" + c + "]";
- if (pred == null) {
- {
- if (true) {
- return c;
- }
- }
- } else {
- {
- if (true) {
- return pred + c;
- }
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String pseudo(String pred) throws ParseException {
- Token n;
- Token param;
- String d;
- boolean isPseudoElement = false;
- jj_consume_token(COLON);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COLON:
- jj_consume_token(COLON);
- isPseudoElement = true;
- break;
+ jj_la1[21] = jj_gen;
+ break label_16;
+ }
+ jj_consume_token(S);
+ }
+ label_17:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case TO:
+ case FROM:
+ case PERCENTAGE:
+ ;
+ break;
default:
- jj_la1[98] = jj_gen;
- ;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- n = jj_consume_token(IDENT);
- String s = ":" + convertIdent(n.image);
- if (isPseudoElement) {
- if (pseudoElt != null) {
- {
- if (true) {
- throw new CSSParseException(
- "duplicate pseudo element definition " + s,
- getLocator());
- }
- }
- } else {
- pseudoElt = ":" + s;
- {
- if (true) {
- return pred;
- }
- }
- }
- } else {
- String c = s;
- if (pred == null) {
- {
- if (true) {
- return c;
- }
- }
- } else {
- {
- if (true) {
- return pred + c;
- }
- }
- }
- }
- break;
- case FUNCTION:
- n = jj_consume_token(FUNCTION);
- label_65: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[99] = jj_gen;
- break label_65;
- }
- jj_consume_token(S);
- }
- d = skipStatementUntilRightParan();
- jj_consume_token(RPARAN);
- // accept anything between function and a right parenthesis
- String f = convertIdent(n.image);
- String colons = isPseudoElement ? "::" : ":";
- String pseudofn = colons + f + d + ")";
- if (pred == null) {
- {
- if (true) {
- return pseudofn;
- }
- }
- } else {
- {
- if (true) {
- return pred + pseudofn;
- }
- }
- }
- break;
+ jj_la1[22] = jj_gen;
+ break label_17;
+ }
+ keyframeSelector();
+ }
+ jj_consume_token(RBRACE);
+ label_18:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[100] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String hash(String pred) throws ParseException {
- Token n;
- n = jj_consume_token(HASH);
- String d = n.image;
- if (pred == null) {
- {
- if (true) {
- return d;
- }
- }
- } else {
- {
- if (true) {
- return pred + d;
- }
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public void variable() throws ParseException {
- String name;
- LexicalUnitImpl exp = null;
- boolean guarded = false;
- String raw;
- try {
- name = variableName();
- jj_consume_token(COLON);
- label_66: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[101] = jj_gen;
- break label_66;
- }
- jj_consume_token(S);
- }
- exp = expr();
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case GUARDED_SYM:
- guarded = guarded();
- break;
- default:
- jj_la1[102] = jj_gen;
- ;
- }
- label_67: while (true) {
- jj_consume_token(SEMICOLON);
- label_68: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[103] = jj_gen;
- break label_68;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[104] = jj_gen;
- break label_67;
- }
- }
- documentHandler.variable(name, exp, guarded);
- } catch (JumpException e) {
- skipAfterExpression();
- } catch (NumberFormatException e) {
- if (errorHandler != null) {
- errorHandler.error(new CSSParseException("Invalid number "
- + e.getMessage(), getLocator(), e));
- }
- reportWarningSkipText(getLocator(), skipAfterExpression());
- } catch (ParseException e) {
- if (errorHandler != null) {
- if (e.currentToken != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.currentToken.next.beginLine,
- e.currentToken.next.beginColumn - 1);
- reportError(li, e);
- } else {
- reportError(getLocator(), e);
- }
- skipAfterExpression();
- } else {
- skipAfterExpression();
- }
- }
- }
-
- final public void controlDirective() throws ParseException {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IF_SYM:
- ifDirective();
- break;
- case EACH_SYM:
- eachDirective();
- break;
+ jj_la1[23] = jj_gen;
+ break label_18;
+ }
+ jj_consume_token(S);
+ }
+ } catch (ParseException e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ } finally {
+ if (start) {
+ documentHandler.endKeyFrames();
+ }
+ }
+ }
+
+ final public void keyframeSelector() throws ParseException {
+ Token n;
+ boolean start = false;
+ try {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case FROM:
+ n = jj_consume_token(FROM);
+ break;
+ case TO:
+ n = jj_consume_token(TO);
+ break;
+ case PERCENTAGE:
+ n = jj_consume_token(PERCENTAGE);
+ break;
+ default:
+ jj_la1[24] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_19:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[105] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
-
- final public void ifContentStatement() throws ParseException {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INCLUDE_SYM:
- includeDirective();
- break;
- case MEDIA_SYM:
- media();
- break;
- case EXTEND_SYM:
- extendDirective();
- break;
+ jj_la1[25] = jj_gen;
+ break label_19;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(LBRACE);
+ label_20:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[26] = jj_gen;
+ break label_20;
+ }
+ jj_consume_token(S);
+ }
+ start = true;
+ documentHandler.startKeyframeSelector(n.image);
+ label_21:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case PLUS:
case PRECEDES:
case SIBLING:
@@ -2821,2323 +927,2684 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
case DOT:
case COLON:
case INTERPOLATION:
+ case INCLUDE_SYM:
case DEBUG_SYM:
case WARN_SYM:
+ case EACH_SYM:
+ case IF_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case MICROSOFT_RULE:
case IDENT:
+ case VARIABLE:
case HASH:
- styleRuleOrDeclarationOrNestedProperties();
- break;
+ case MEDIA_SYM:
case KEY_FRAME_SYM:
- keyframes();
- break;
+ ;
+ break;
default:
- jj_la1[106] = jj_gen;
- if (jj_2_3(2147483647)) {
- variable();
- } else {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case VARIABLE:
- listModifyDirective();
- break;
- default:
- jj_la1[107] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- }
- }
-
- final public void ifDirective() throws ParseException {
- Token n = null;
- String s = null;
- String evaluator = "";
- jj_consume_token(IF_SYM);
- label_69: while (true) {
- s = booleanExpressionToken();
- evaluator += s;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- case EQ:
- case PLUS:
- case MINUS:
- case PRECEDES:
- case SUCCEEDS:
- case DIV:
- case ANY:
- case LPARAN:
- case RPARAN:
- case COMPARE:
- case OR:
- case AND:
- case NOT_EQ:
- case IDENT:
- case NUMBER:
- case VARIABLE:
- case CONTAINS:
- ;
- break;
- default:
- jj_la1[108] = jj_gen;
- break label_69;
- }
- }
- jj_consume_token(LBRACE);
- label_70: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[109] = jj_gen;
- break label_70;
- }
- jj_consume_token(S);
- }
- documentHandler.startIfElseDirective();
- documentHandler.ifDirective(evaluator);
- label_71: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ;
- break;
- default:
- jj_la1[110] = jj_gen;
- break label_71;
- }
- ifContentStatement();
+ jj_la1[27] = jj_gen;
+ break label_21;
}
- jj_consume_token(RBRACE);
- label_72: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[111] = jj_gen;
- break label_72;
- }
- jj_consume_token(S);
- }
- label_73: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case ELSE_SYM:
- ;
- break;
- default:
- jj_la1[112] = jj_gen;
- break label_73;
- }
- elseDirective();
- }
- documentHandler.endIfElseDirective();
- }
-
- final public void elseDirective() throws ParseException {
- String evaluator = "";
- Token n = null;
- String s = null;
- jj_consume_token(ELSE_SYM);
- label_74: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[113] = jj_gen;
- break label_74;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IF:
- jj_consume_token(IF);
- label_75: while (true) {
- s = booleanExpressionToken();
- evaluator += s;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- case EQ:
- case PLUS:
- case MINUS:
- case PRECEDES:
- case SUCCEEDS:
- case DIV:
- case ANY:
- case LPARAN:
- case RPARAN:
- case COMPARE:
- case OR:
- case AND:
- case NOT_EQ:
- case IDENT:
- case NUMBER:
- case VARIABLE:
- case CONTAINS:
- ;
- break;
- default:
- jj_la1[114] = jj_gen;
- break label_75;
- }
- }
- break;
- default:
- jj_la1[115] = jj_gen;
- ;
- }
- jj_consume_token(LBRACE);
- label_76: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[116] = jj_gen;
- break label_76;
- }
- jj_consume_token(S);
- }
- if (!evaluator.trim().equals("")) {
- documentHandler.ifDirective(evaluator);
- } else {
- documentHandler.elseDirective();
- }
- label_77: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ;
- break;
- default:
- jj_la1[117] = jj_gen;
- break label_77;
- }
- ifContentStatement();
- }
- jj_consume_token(RBRACE);
- label_78: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[118] = jj_gen;
- break label_78;
- }
- jj_consume_token(S);
- }
- }
-
- final public String booleanExpressionToken() throws ParseException {
- Token n = null;
- String s = null;
- if (jj_2_4(2147483647)) {
- s = containsDirective();
- } else {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case VARIABLE:
- n = jj_consume_token(VARIABLE);
- break;
- case IDENT:
- n = jj_consume_token(IDENT);
- break;
- case NUMBER:
- n = jj_consume_token(NUMBER);
- break;
- case LPARAN:
- n = jj_consume_token(LPARAN);
- break;
- case RPARAN:
- n = jj_consume_token(RPARAN);
- break;
- case PLUS:
- n = jj_consume_token(PLUS);
- break;
- case MINUS:
- n = jj_consume_token(MINUS);
- break;
- case DIV:
- n = jj_consume_token(DIV);
- break;
- case ANY:
- n = jj_consume_token(ANY);
- break;
- case COMPARE:
- n = jj_consume_token(COMPARE);
- break;
- case EQ:
- n = jj_consume_token(EQ);
- break;
- case PRECEDES:
- n = jj_consume_token(PRECEDES);
- break;
- case SUCCEEDS:
- n = jj_consume_token(SUCCEEDS);
- break;
- case OR:
- n = jj_consume_token(OR);
- break;
- case AND:
- n = jj_consume_token(AND);
- break;
- case S:
- n = jj_consume_token(S);
- break;
- case NOT_EQ:
- n = jj_consume_token(NOT_EQ);
- break;
- default:
- jj_la1[119] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- if (n != null) {
- {
- if (true) {
- return n.image;
- }
- }
- } else {
- {
- if (true) {
- return s;
- }
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public void eachDirective() throws ParseException {
- Token var;
- ArrayList<String> list = null;
- String listVariable = null;
- jj_consume_token(EACH_SYM);
- label_79: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[120] = jj_gen;
- break label_79;
- }
- jj_consume_token(S);
- }
- var = jj_consume_token(VARIABLE);
- label_80: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[121] = jj_gen;
- break label_80;
- }
- jj_consume_token(S);
- }
- jj_consume_token(EACH_IN);
- label_81: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[122] = jj_gen;
- break label_81;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
case IDENT:
- list = stringList();
- documentHandler.startEachDirective(var.image, list);
- break;
case VARIABLE:
- listVariable = variableName();
- documentHandler.startEachDirective(var.image, listVariable);
- break;
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ifContentStatement();
+ break;
+ case EACH_SYM:
+ case IF_SYM:
+ controlDirective();
+ break;
+ case MICROSOFT_RULE:
+ microsoftExtension();
+ break;
default:
- jj_la1[123] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- jj_consume_token(LBRACE);
- label_82: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[124] = jj_gen;
- break label_82;
- }
- jj_consume_token(S);
- }
- label_83: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ;
- break;
- default:
- jj_la1[125] = jj_gen;
- break label_83;
- }
- ifContentStatement();
+ jj_la1[28] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ jj_consume_token(RBRACE);
+ label_22:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[29] = jj_gen;
+ break label_22;
}
- jj_consume_token(RBRACE);
- label_84: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[126] = jj_gen;
- break label_84;
- }
- jj_consume_token(S);
+ jj_consume_token(S);
+ }
+ } catch (ThrowedParseException e) {
+ if (errorHandler != null) {
+ LocatorImpl li = new LocatorImpl(this,
+ e.e.currentToken.next.beginLine,
+ e.e.currentToken.next.beginColumn-1);
+ reportError(li, e.e);
}
- documentHandler.endEachDirective();
- }
+ } catch (ParseException e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
- final public ArrayList<String> stringList() throws ParseException {
- ArrayList<String> strings = new ArrayList<String>();
- Token input;
- input = jj_consume_token(IDENT);
- label_85: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[127] = jj_gen;
- break label_85;
- }
- jj_consume_token(S);
+ } catch (TokenMgrError e) {
+ reportWarningSkipText(getLocator(), skipStatement());
+ } finally {
+ if (start) {
+ documentHandler.endKeyframeSelector();
}
- strings.add(input.image);
- label_86: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- ;
- break;
- default:
- jj_la1[128] = jj_gen;
- break label_86;
- }
- jj_consume_token(COMMA);
- label_87: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[129] = jj_gen;
- break label_87;
- }
- jj_consume_token(S);
- }
- input = jj_consume_token(IDENT);
- strings.add(input.image);
- label_88: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[130] = jj_gen;
- break label_88;
- }
- jj_consume_token(S);
- }
- }
- {
- if (true) {
- return strings;
- }
- }
- throw new Error("Missing return statement in function");
}
+ }
- final public void mixinDirective() throws ParseException {
- String name;
- ArrayList<VariableNode> args = null;
- String body;
- jj_consume_token(MIXIN_SYM);
- label_89: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[131] = jj_gen;
- break label_89;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+/**
+ * @exception ParseException exception during the parse
+ */
+/* see http://www.w3.org/TR/css3-mediaqueries/ */
+ final public void media() throws ParseException {
+ boolean start = false;
+ String ret;
+ MediaListImpl ml = new MediaListImpl();
+ try {
+ jj_consume_token(MEDIA_SYM);
+ label_23:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[30] = jj_gen;
+ break label_23;
+ }
+ jj_consume_token(S);
+ }
+ mediaStatement(ml);
+ start = true; documentHandler.startMedia(ml);
+ jj_consume_token(LBRACE);
+ label_24:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[31] = jj_gen;
+ break label_24;
+ }
+ jj_consume_token(S);
+ }
+ label_25:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case CDO:
+ case LBRACE:
+ case DASHMATCH:
+ case INCLUDES:
+ case PLUS:
+ case MINUS:
+ case COMMA:
+ case SEMICOLON:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
case INTERPOLATION:
+ case NONASCII:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case STRING:
case IDENT:
- name = property();
- break;
+ case NUMBER:
+ case URL:
+ case PERCENTAGE:
+ case HASH:
+ case IMPORT_SYM:
+ case MEDIA_SYM:
+ case CHARSET_SYM:
+ case PAGE_SYM:
+ case FONT_FACE_SYM:
+ case ATKEYWORD:
+ case IMPORTANT_SYM:
+ case UNICODERANGE:
case FUNCTION:
- name = functionName();
- args = arglist();
- jj_consume_token(RPARAN);
- label_90: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[132] = jj_gen;
- break label_90;
- }
- jj_consume_token(S);
- }
- break;
+ case UNKNOWN:
+ ;
+ break;
default:
- jj_la1[133] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[32] = jj_gen;
+ break label_25;
}
- jj_consume_token(LBRACE);
- label_91: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[134] = jj_gen;
- break label_91;
- }
- jj_consume_token(S);
- }
- documentHandler.startMixinDirective(name, args);
- label_92: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EACH_SYM:
- case IF_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case PAGE_SYM:
- case FONT_FACE_SYM:
- case KEY_FRAME_SYM:
- ;
- break;
- default:
- jj_la1[135] = jj_gen;
- break label_92;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case INCLUDE_SYM:
- case DEBUG_SYM:
- case WARN_SYM:
- case EXTEND_SYM:
- case IDENT:
- case VARIABLE:
- case HASH:
- case MEDIA_SYM:
- case KEY_FRAME_SYM:
- ifContentStatement();
- break;
- case EACH_SYM:
- case IF_SYM:
- controlDirective();
- break;
- case FONT_FACE_SYM:
- fontFace();
- break;
- case PAGE_SYM:
- page();
- break;
- default:
- jj_la1[136] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- jj_consume_token(RBRACE);
- label_93: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[137] = jj_gen;
- break label_93;
- }
- jj_consume_token(S);
- }
- documentHandler.endMixinDirective(name, args);
- }
-
- final public ArrayList<VariableNode> arglist() throws ParseException {
- ArrayList<VariableNode> args = new ArrayList<VariableNode>();
- VariableNode arg;
- boolean hasNonOptionalArgument = false;
- arg = mixinArg();
- label_94: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- ;
- break;
- default:
- jj_la1[138] = jj_gen;
- break label_94;
- }
- jj_consume_token(COMMA);
- label_95: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[139] = jj_gen;
- break label_95;
- }
- jj_consume_token(S);
- }
- hasNonOptionalArgument = checkMixinForNonOptionalArguments(arg,
- hasNonOptionalArgument);
- args.add(arg);
- arg = mixinArg();
- }
- hasNonOptionalArgument = checkMixinForNonOptionalArguments(arg,
- hasNonOptionalArgument);
- args.add(arg);
- {
- if (true) {
- return args;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- boolean checkMixinForNonOptionalArguments(VariableNode arg,
- boolean hasNonOptionalArguments) throws ParseException {
- boolean currentArgHasArguments = arg.getExpr() != null
- && arg.getExpr().getLexicalUnitType() == LexicalUnitImpl.SCSS_VARIABLE
- && arg.getExpr().getNextLexicalUnit() != null;
-
- if (currentArgHasArguments) {
- if (hasNonOptionalArguments) {
- throw new ParseException("Sass Error: Required argument $"
- + arg.getName()
- + " must come before any optional arguments.");
- }
- return hasNonOptionalArguments;
- } else {
- return true;
- }
- }
-
- final public VariableNode mixinArg() throws ParseException {
- String name;
- Token variable = null;
- LexicalUnitImpl first = null;
- LexicalUnitImpl prev = null;
- LexicalUnitImpl next = null;
- name = variableName();
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case DEBUG_SYM:
+ case WARN_SYM:
+ debuggingDirective();
+ break;
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
case COLON:
- case VARIABLE:
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COLON:
- jj_consume_token(COLON);
- label_96: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[140] = jj_gen;
- break label_96;
- }
- jj_consume_token(S);
- }
- first = nonVariableTerm(null);
- prev = first;
- label_97: while (true) {
- if (jj_2_5(3)) {
- ;
- } else {
- break label_97;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- jj_consume_token(COMMA);
- label_98: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[141] = jj_gen;
- break label_98;
- }
- jj_consume_token(S);
- }
- break;
- default:
- jj_la1[142] = jj_gen;
- ;
- }
- prev = nonVariableTerm(prev);
- }
- break;
- case VARIABLE:
- variable = jj_consume_token(VARIABLE);
- first = LexicalUnitImpl.createVariable(token.beginLine,
- token.beginColumn, prev, variable.image);
- break;
- default:
- jj_la1[143] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- break;
- default:
- jj_la1[144] = jj_gen;
- ;
- }
- VariableNode arg = new VariableNode(name, first, false);
- {
- if (true) {
- return arg;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public ArrayList<LexicalUnitImpl> argValuelist()
- throws ParseException {
- ArrayList<LexicalUnitImpl> args = new ArrayList<LexicalUnitImpl>();
- LexicalUnitImpl first = null;
- LexicalUnitImpl next = null;
- LexicalUnitImpl prev = null;
- first = term(null);
- args.add(first);
- prev = first;
- label_99: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case MINUS:
- case DOT:
- case COLON:
- case TO:
- case THROUGH:
- case FROM:
- case STRING:
- case IDENT:
- case NUMBER:
- case URL:
- case VARIABLE:
- case PERCENTAGE:
- case PT:
- case MM:
- case CM:
- case PC:
- case IN:
- case PX:
- case EMS:
- case LEM:
- case REM:
- case EXS:
- case DEG:
- case RAD:
- case GRAD:
- case MS:
- case SECOND:
- case HZ:
- case KHZ:
- case DIMEN:
- case HASH:
- case UNICODERANGE:
- case FUNCTION:
- ;
- break;
- default:
- jj_la1[145] = jj_gen;
- break label_99;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COLON:
- jj_consume_token(COLON);
- label_100: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[146] = jj_gen;
- break label_100;
- }
- jj_consume_token(S);
- }
- break;
- default:
- jj_la1[147] = jj_gen;
- ;
- }
- next = term(prev);
- prev.setNextLexicalUnit(next);
- prev = next;
- }
- label_101: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- ;
- break;
- default:
- jj_la1[148] = jj_gen;
- break label_101;
- }
- jj_consume_token(COMMA);
- label_102: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[149] = jj_gen;
- break label_102;
- }
- jj_consume_token(S);
- }
- first = term(null);
- args.add(first);
- prev = first;
- label_103: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case MINUS:
- case DOT:
- case COLON:
- case TO:
- case THROUGH:
- case FROM:
- case STRING:
- case IDENT:
- case NUMBER:
- case URL:
- case VARIABLE:
- case PERCENTAGE:
- case PT:
- case MM:
- case CM:
- case PC:
- case IN:
- case PX:
- case EMS:
- case LEM:
- case REM:
- case EXS:
- case DEG:
- case RAD:
- case GRAD:
- case MS:
- case SECOND:
- case HZ:
- case KHZ:
- case DIMEN:
- case HASH:
- case UNICODERANGE:
- case FUNCTION:
- ;
- break;
- default:
- jj_la1[150] = jj_gen;
- break label_103;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COLON:
- jj_consume_token(COLON);
- label_104: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[151] = jj_gen;
- break label_104;
- }
- jj_consume_token(S);
- }
- break;
- default:
- jj_la1[152] = jj_gen;
- ;
- }
- next = term(prev);
- prev.setNextLexicalUnit(next);
- prev = next;
- }
- }
- {
- if (true) {
- return args;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public void includeDirective() throws ParseException {
- String name;
- ArrayList<LexicalUnitImpl> args = null;
- jj_consume_token(INCLUDE_SYM);
- label_105: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[153] = jj_gen;
- break label_105;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
case INTERPOLATION:
case IDENT:
- name = property();
- break;
- case VARIABLE:
- name = variableName();
- name = "$" + name;
- break;
+ case HASH:
+ styleRule();
+ break;
+ case CDO:
+ case LBRACE:
+ case DASHMATCH:
+ case INCLUDES:
+ case MINUS:
+ case COMMA:
+ case SEMICOLON:
+ case NONASCII:
+ case STRING:
+ case NUMBER:
+ case URL:
+ case PERCENTAGE:
+ case IMPORT_SYM:
+ case MEDIA_SYM:
+ case CHARSET_SYM:
+ case PAGE_SYM:
+ case FONT_FACE_SYM:
+ case ATKEYWORD:
+ case IMPORTANT_SYM:
+ case UNICODERANGE:
case FUNCTION:
- name = functionName();
- args = argValuelist();
- jj_consume_token(RPARAN);
- break;
+ case UNKNOWN:
+ skipUnknownRule();
+ break;
default:
- jj_la1[154] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[33] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ jj_consume_token(RBRACE);
+ label_26:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[34] = jj_gen;
+ break label_26;
+ }
+ jj_consume_token(S);
+ }
+ } catch (ParseException e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
+
+ } finally {
+ if (start) {
+ documentHandler.endMedia(ml);
+ }
+ }
+ }
+
+ final public void mediaStatement(MediaListImpl ml) throws ParseException {
+ Token t;
+ t = getToken(1);
+ // loop over comma separated parts, add each to ml
+ while ((t.kind != LBRACE) && (t.kind != EOF) && (t.kind != SEMICOLON)) {
+ StringBuffer s = new StringBuffer();
+ s.append(getToken(0).image);
+ while ((t.kind != COMMA) && (t.kind != LBRACE) && (t.kind != EOF) && (t.kind != SEMICOLON)) {
+ s.append(t.image);
+ getNextToken();
+ t = getToken(1);
}
- label_106: while (true) {
- jj_consume_token(SEMICOLON);
- label_107: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[155] = jj_gen;
- break label_107;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[156] = jj_gen;
- break label_106;
- }
+ if (t.kind == COMMA) {
+ // skip the comma and the token before it that is still the active token
+ getNextToken();
+ getNextToken();
+ t = getToken(1);
}
- documentHandler.includeDirective(name, args);
- }
-
- final public String interpolation() throws ParseException {
- Token n;
- n = jj_consume_token(INTERPOLATION);
- {
- if (true) {
- return n.image;
- }
+ String str = s.toString().trim();
+ if (str.length() > 0) {
+ ml.addItem(str);
}
- throw new Error("Missing return statement in function");
- }
+ }
+ }
- final public void listModifyDirective() throws ParseException {
- String list = null;
- String remove = null;
- String separator = null;
- String variable = null;
- Token n = null;
- Token type = null;
- // refactor, remove those 3 LOOKAHEAD(5).
- n = jj_consume_token(VARIABLE);
- variable = n.image;
- label_108: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[157] = jj_gen;
- break label_108;
- }
- jj_consume_token(S);
- }
- jj_consume_token(COLON);
- label_109: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[158] = jj_gen;
- break label_109;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case APPEND:
- type = jj_consume_token(APPEND);
- break;
- case REMOVE:
- type = jj_consume_token(REMOVE);
- break;
- case CONTAINS:
- type = jj_consume_token(CONTAINS);
- break;
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String medium() throws ParseException {
+ Token n;
+ n = jj_consume_token(IDENT);
+ {if (true) return convertIdent(n.image);}
+ throw new Error("Missing return statement in function");
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void page() throws ParseException {
+ boolean start = false;
+ Token n = null;
+ String page = null;
+ String pseudo = null;
+ try {
+ jj_consume_token(PAGE_SYM);
+ label_27:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[159] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[35] = jj_gen;
+ break label_27;
}
- label_110: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[160] = jj_gen;
- break label_110;
- }
- jj_consume_token(S);
- }
- list = listModifyDirectiveArgs(0);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case RPARAN:
- jj_consume_token(RPARAN);
- break;
- default:
- jj_la1[161] = jj_gen;
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ n = jj_consume_token(IDENT);
+ label_28:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
;
- }
- jj_consume_token(COMMA);
- label_111: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[162] = jj_gen;
- break label_111;
- }
- jj_consume_token(S);
- }
- remove = listModifyDirectiveArgs(1);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- jj_consume_token(COMMA);
- label_112: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[163] = jj_gen;
- break label_112;
- }
- jj_consume_token(S);
- }
- n = jj_consume_token(IDENT);
- separator = n.image;
- label_113: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[164] = jj_gen;
- break label_113;
- }
- jj_consume_token(S);
- }
break;
+ default:
+ jj_la1[36] = jj_gen;
+ break label_28;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[37] = jj_gen;
+ ;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COLON:
+ pseudo = pseudo_page();
+ break;
+ default:
+ jj_la1[38] = jj_gen;
+ ;
+ }
+ if (n != null) {
+ page = convertIdent(n.image);
+ }
+ jj_consume_token(LBRACE);
+ label_29:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[165] = jj_gen;
- ;
- }
- jj_consume_token(RPARAN);
- switch (type.kind) {
- case APPEND:
- documentHandler.appendDirective(variable, list, remove, separator);
- break;
- case REMOVE:
- documentHandler.removeDirective(variable, list, remove, separator);
- break;
- case CONTAINS:
- if (variable == null) {
- variable = "$var_" + UUID.randomUUID();
- }
- documentHandler
- .containsDirective(variable, list, remove, separator);
- break;
+ jj_la1[39] = jj_gen;
+ break label_29;
+ }
+ jj_consume_token(S);
+ }
+ start = true;
+ documentHandler.startPage(page, pseudo);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[40] = jj_gen;
+ ;
+ }
+ label_30:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
default:
- break;
- }
- label_114: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[166] = jj_gen;
- break label_114;
- }
- jj_consume_token(S);
+ jj_la1[41] = jj_gen;
+ break label_30;
}
jj_consume_token(SEMICOLON);
- label_115: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[167] = jj_gen;
- break label_115;
- }
- jj_consume_token(S);
- }
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void appendDirective() throws ParseException {
- String list = null;
- String remove = null;
- String separator = null;
- String variable = null;
- Token n = null;
- n = jj_consume_token(VARIABLE);
- variable = n.image;
- label_116: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[168] = jj_gen;
- break label_116;
- }
- jj_consume_token(S);
- }
- jj_consume_token(COLON);
- label_117: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[169] = jj_gen;
- break label_117;
- }
- jj_consume_token(S);
- }
- jj_consume_token(APPEND);
- label_118: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[170] = jj_gen;
- break label_118;
- }
- jj_consume_token(S);
- }
- list = listModifyDirectiveArgs(0);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case RPARAN:
- jj_consume_token(RPARAN);
- break;
- default:
- jj_la1[171] = jj_gen;
+ label_31:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
;
- }
- jj_consume_token(COMMA);
- label_119: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[172] = jj_gen;
- break label_119;
- }
- jj_consume_token(S);
- }
- remove = listModifyDirectiveArgs(1);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- jj_consume_token(COMMA);
- label_120: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[173] = jj_gen;
- break label_120;
- }
- jj_consume_token(S);
- }
- n = jj_consume_token(IDENT);
- separator = n.image;
- label_121: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[174] = jj_gen;
- break label_121;
- }
- jj_consume_token(S);
- }
break;
- default:
- jj_la1[175] = jj_gen;
- ;
+ default:
+ jj_la1[42] = jj_gen;
+ break label_31;
+ }
+ jj_consume_token(S);
}
- jj_consume_token(RPARAN);
- documentHandler.appendDirective(variable, list, remove, separator);
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void removeDirective() throws ParseException {
- String list = null;
- String remove = null;
- String separator = null;
- String variable = null;
- Token n = null;
- n = jj_consume_token(VARIABLE);
- variable = n.image;
- label_122: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[176] = jj_gen;
- break label_122;
- }
- jj_consume_token(S);
- }
- jj_consume_token(COLON);
- label_123: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[177] = jj_gen;
- break label_123;
- }
- jj_consume_token(S);
- }
- jj_consume_token(REMOVE);
- label_124: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[178] = jj_gen;
- break label_124;
- }
- jj_consume_token(S);
- }
- list = listModifyDirectiveArgs(0);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case RPARAN:
- jj_consume_token(RPARAN);
- break;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
default:
- jj_la1[179] = jj_gen;
- ;
- }
- jj_consume_token(COMMA);
- label_125: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[180] = jj_gen;
- break label_125;
- }
- jj_consume_token(S);
- }
- remove = listModifyDirectiveArgs(1);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- jj_consume_token(COMMA);
- label_126: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[181] = jj_gen;
- break label_126;
- }
- jj_consume_token(S);
- }
- n = jj_consume_token(IDENT);
- separator = n.image;
- label_127: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[182] = jj_gen;
- break label_127;
- }
- jj_consume_token(S);
- }
- break;
+ jj_la1[43] = jj_gen;
+ ;
+ }
+ }
+ jj_consume_token(RBRACE);
+ label_32:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[183] = jj_gen;
- ;
- }
- jj_consume_token(RPARAN);
- documentHandler.removeDirective(variable, list, remove, separator);
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public String containsDirective() throws ParseException {
- String list = null;
- String remove = null;
- String separator = null;
- String variable = null;
- Token n = null;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case VARIABLE:
- n = jj_consume_token(VARIABLE);
- variable = n.image;
- label_128: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[184] = jj_gen;
- break label_128;
- }
- jj_consume_token(S);
- }
- jj_consume_token(COLON);
- label_129: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[185] = jj_gen;
- break label_129;
- }
- jj_consume_token(S);
- }
- break;
+ jj_la1[44] = jj_gen;
+ break label_32;
+ }
+ jj_consume_token(S);
+ }
+ } catch (ParseException e) {
+ if (errorHandler != null) {
+ LocatorImpl li = new LocatorImpl(this,
+ e.currentToken.next.beginLine,
+ e.currentToken.next.beginColumn-1);
+ reportError(li, e);
+ skipStatement();
+ // reportWarningSkipText(li, skipStatement());
+ } else {
+ skipStatement();
+ }
+ } finally {
+ if (start) {
+ documentHandler.endPage(page, pseudo);
+ }
+ }
+ }
+
+ final public String pseudo_page() throws ParseException {
+ Token n;
+ jj_consume_token(COLON);
+ n = jj_consume_token(IDENT);
+ label_33:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[45] = jj_gen;
+ break label_33;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return convertIdent(n.image);}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void fontFace() throws ParseException {
+ boolean start = false;
+ try {
+ jj_consume_token(FONT_FACE_SYM);
+ label_34:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[186] = jj_gen;
- ;
- }
- jj_consume_token(CONTAINS);
- label_130: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[187] = jj_gen;
- break label_130;
- }
- jj_consume_token(S);
- }
- list = listModifyDirectiveArgs(0);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case RPARAN:
- jj_consume_token(RPARAN);
- break;
+ jj_la1[46] = jj_gen;
+ break label_34;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(LBRACE);
+ label_35:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[188] = jj_gen;
- ;
- }
- jj_consume_token(COMMA);
- label_131: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[189] = jj_gen;
- break label_131;
- }
- jj_consume_token(S);
- }
- remove = listModifyDirectiveArgs(1);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- jj_consume_token(COMMA);
- label_132: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[190] = jj_gen;
- break label_132;
- }
- jj_consume_token(S);
- }
- n = jj_consume_token(IDENT);
- separator = n.image;
- label_133: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[191] = jj_gen;
- break label_133;
- }
- jj_consume_token(S);
- }
- break;
+ jj_la1[47] = jj_gen;
+ break label_35;
+ }
+ jj_consume_token(S);
+ }
+ start = true; documentHandler.startFontFace();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[48] = jj_gen;
+ ;
+ }
+ label_36:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
default:
- jj_la1[192] = jj_gen;
- ;
+ jj_la1[49] = jj_gen;
+ break label_36;
}
- jj_consume_token(RPARAN);
- /*
- * if it is not in the form like
- * "$contains : contains($items, .v-button);"for example in @if, like
- * "@if (contains(a b c, b))", then create a tempvariable for contains(a
- * b c, b);
- */
- if (variable == null) {
- variable = "$var_" + UUID.randomUUID();
+ jj_consume_token(SEMICOLON);
+ label_37:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[50] = jj_gen;
+ break label_37;
+ }
+ jj_consume_token(S);
}
- documentHandler.containsDirective(variable, list, remove, separator);
- {
- if (true) {
- return variable;
- }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[51] = jj_gen;
+ ;
+ }
+ }
+ jj_consume_token(RBRACE);
+ label_38:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[52] = jj_gen;
+ break label_38;
}
- throw new Error("Missing return statement in function");
- }
-
- String listModifyDirectiveArgs(int nest) throws ParseException {
- String list = "";
- int nesting = nest;
- Token t = null;
+ jj_consume_token(S);
+ }
+ } catch (ParseException e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
- while (true) {
- t = getToken(1);
- String s = t.image;
- if (t.kind == VARIABLE || t.kind == IDENT) {
- list += s;
- } else if (s.toLowerCase().equals("auto")
- || s.toLowerCase().equals("space")
- || s.toLowerCase().equals("comma")) {
- int i = 2;
- Token temp = getToken(i);
- boolean isLast = true;
- while (temp.kind != SEMICOLON) {
- if (temp.kind != RPARAN || temp.kind != S) {
- isLast = false;
- }
- i++;
- temp = getToken(i);
- }
+ } finally {
+ if (start) {
+ documentHandler.endFontFace();
+ }
+ }
+ }
- if (isLast) {
- return list;
- }
- } else if (t.kind == STRING) {
- list += s.substring(1, s.length()).substring(0, s.length() - 2);
-
- } else if (t.kind == LPARAN) {
- nesting++;
- if (nesting > nest + 1) {
- throw new CSSParseException(
- "Only one ( ) pair per parameter allowed",
- getLocator());
- }
- } else if (t.kind == RPARAN) {
- nesting--;
- if (nesting == 0) {
- return list;
- }
- } else if (t.kind == COMMA) {
- if (nesting == nest) {
- return list;
- } else {
- list += ",";
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void atRuleDeclaration() throws ParseException {
+ Token n;
+ String ret;
+ n = jj_consume_token(ATKEYWORD);
+ ret=skipStatement();
+ if ((ret != null) && (ret.charAt(0) == '@')) {
+ documentHandler.unrecognizedRule(ret);
+ } else {
+ reportWarningSkipText(getLocator(), ret);
+ }
+ }
+
+ final public void skipUnknownRule() throws ParseException {
+ Token n;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case ATKEYWORD:
+ n = jj_consume_token(ATKEYWORD);
+ break;
+ case CDO:
+ n = jj_consume_token(CDO);
+ break;
+ case CHARSET_SYM:
+ n = jj_consume_token(CHARSET_SYM);
+ break;
+ case COMMA:
+ n = jj_consume_token(COMMA);
+ break;
+ case DASHMATCH:
+ n = jj_consume_token(DASHMATCH);
+ break;
+ case FONT_FACE_SYM:
+ n = jj_consume_token(FONT_FACE_SYM);
+ break;
+ case FUNCTION:
+ n = jj_consume_token(FUNCTION);
+ break;
+ case IMPORTANT_SYM:
+ n = jj_consume_token(IMPORTANT_SYM);
+ break;
+ case IMPORT_SYM:
+ n = jj_consume_token(IMPORT_SYM);
+ break;
+ case INCLUDES:
+ n = jj_consume_token(INCLUDES);
+ break;
+ case LBRACE:
+ n = jj_consume_token(LBRACE);
+ break;
+ case MEDIA_SYM:
+ n = jj_consume_token(MEDIA_SYM);
+ break;
+ case NONASCII:
+ n = jj_consume_token(NONASCII);
+ break;
+ case NUMBER:
+ n = jj_consume_token(NUMBER);
+ break;
+ case PAGE_SYM:
+ n = jj_consume_token(PAGE_SYM);
+ break;
+ case PERCENTAGE:
+ n = jj_consume_token(PERCENTAGE);
+ break;
+ case STRING:
+ n = jj_consume_token(STRING);
+ break;
+ case UNICODERANGE:
+ n = jj_consume_token(UNICODERANGE);
+ break;
+ case URL:
+ n = jj_consume_token(URL);
+ break;
+ case SEMICOLON:
+ n = jj_consume_token(SEMICOLON);
+ break;
+ case MINUS:
+ n = jj_consume_token(MINUS);
+ break;
+ case UNKNOWN:
+ n = jj_consume_token(UNKNOWN);
+ break;
+ default:
+ jj_la1[53] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ String ret;
+ Locator loc = getLocator();
+ ret=skipStatement();
+ if ((ret != null) && (n.image.charAt(0) == '@')) {
+ documentHandler.unrecognizedRule(ret);
+ } else {
+ reportWarningSkipText(loc, ret);
+ }
+ }
- } else if (t.kind == S) {
- list += " ";
- } else if (t.kind == LBRACE) {
- throw new CSSParseException("Invalid token,'{' found",
- getLocator());
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public char combinator() throws ParseException {
+char connector = ' ';
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ connector = combinatorChar();
+ break;
+ case S:
+ jj_consume_token(S);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ connector = combinatorChar();
+ break;
+ default:
+ jj_la1[54] = jj_gen;
+ ;
+ }
+ break;
+ default:
+ jj_la1[55] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ {if (true) return connector;}
+ throw new Error("Missing return statement in function");
+ }
+
+/**to refactor combinator and reuse in selector().*/
+ final public char combinatorChar() throws ParseException {
+ Token t;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ t = jj_consume_token(PLUS);
+ break;
+ case PRECEDES:
+ t = jj_consume_token(PRECEDES);
+ break;
+ case SIBLING:
+ t = jj_consume_token(SIBLING);
+ break;
+ default:
+ jj_la1[56] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_39:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[57] = jj_gen;
+ break label_39;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return t.image.charAt(0);}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void microsoftExtension() throws ParseException {
+ Token n;
+ String name = "";
+ String value = "";
+ // This is not really taking the syntax of filter rules into account
+ n = jj_consume_token(MICROSOFT_RULE);
+ label_40:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[58] = jj_gen;
+ break label_40;
+ }
+ jj_consume_token(S);
+ }
+ name = n.image;
+ jj_consume_token(COLON);
+ label_41:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ n = jj_consume_token(IDENT);
+ value += n.image;
+ break;
+ case NUMBER:
+ n = jj_consume_token(NUMBER);
+ value += n.image;
+ break;
+ case STRING:
+ n = jj_consume_token(STRING);
+ value += n.image;
+ break;
+ case COMMA:
+ n = jj_consume_token(COMMA);
+ value += n.image;
+ break;
+ case INTERPOLATION:
+ n = jj_consume_token(INTERPOLATION);
+ value += n.image;
+ break;
+ case COLON:
+ n = jj_consume_token(COLON);
+ value += n.image;
+ break;
+ case FUNCTION:
+ n = jj_consume_token(FUNCTION);
+ value += n.image;
+ break;
+ case RPARAN:
+ n = jj_consume_token(RPARAN);
+ value += n.image;
+ break;
+ case EQ:
+ n = jj_consume_token(EQ);
+ value += n.image;
+ break;
+ case DOT:
+ n = jj_consume_token(DOT);
+ value += n.image;
+ break;
+ case S:
+ n = jj_consume_token(S);
+ if(value.lastIndexOf(' ') != value.length()-1)
+ { value += n.image; }
+ break;
+ default:
+ jj_la1[59] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ case EQ:
+ case COMMA:
+ case DOT:
+ case RPARAN:
+ case COLON:
+ case INTERPOLATION:
+ case STRING:
+ case IDENT:
+ case NUMBER:
+ case FUNCTION:
+ ;
+ break;
+ default:
+ jj_la1[60] = jj_gen;
+ break label_41;
+ }
+ }
+ jj_consume_token(SEMICOLON);
+ label_42:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[61] = jj_gen;
+ break label_42;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.microsoftDirective(name, value);
+ }
- getNextToken();
- }
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String property() throws ParseException {
+ Token t;String s = "";
+ label_43:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ t = jj_consume_token(IDENT);
+ s += t.image;
+ break;
+ case INTERPOLATION:
+ t = jj_consume_token(INTERPOLATION);
+ s += t.image;
+ break;
+ default:
+ jj_la1[62] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ ;
+ break;
+ default:
+ jj_la1[63] = jj_gen;
+ break label_43;
+ }
+ }
+ label_44:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[64] = jj_gen;
+ break label_44;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return s;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public String variableName() throws ParseException {
+ Token n;
+ n = jj_consume_token(VARIABLE);
+ label_45:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[65] = jj_gen;
+ break label_45;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return convertIdent(n.image.substring(1));}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public String functionName() throws ParseException {
+ Token n;
+ n = jj_consume_token(FUNCTION);
+ label_46:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[66] = jj_gen;
+ break label_46;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return convertIdent(n.image.substring(0, n.image.length()-1));}
+ throw new Error("Missing return statement in function");
+ }
- final public Node returnDirective() throws ParseException {
- String raw;
- raw = skipStatement();
- {
- if (true) {
- return null;
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void styleRule() throws ParseException {
+ boolean start = false;
+ ArrayList<String> l = null;
+ Token save;
+ Locator loc;
+ try {
+ l = selectorList();
+ save = token;
+ jj_consume_token(LBRACE);
+ label_47:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[67] = jj_gen;
+ break label_47;
+ }
+ jj_consume_token(S);
+ }
+ start = true;
+ documentHandler.startSelector(l);
+ label_48:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EACH_SYM:
+ case IF_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case MICROSOFT_RULE:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ;
+ break;
+ default:
+ jj_la1[68] = jj_gen;
+ break label_48;
}
- throw new Error("Missing return statement in function");
- }
-
- final public void debuggingDirective() throws ParseException {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
case DEBUG_SYM:
- debugDirective();
- break;
case WARN_SYM:
- warnDirective();
- break;
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ifContentStatement();
+ break;
+ case EACH_SYM:
+ case IF_SYM:
+ controlDirective();
+ break;
+ case MICROSOFT_RULE:
+ microsoftExtension();
+ break;
default:
- jj_la1[193] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[69] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ jj_consume_token(RBRACE);
+ label_49:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[70] = jj_gen;
+ break label_49;
+ }
+ jj_consume_token(S);
+ }
+ } catch (ThrowedParseException e) {
+ if (errorHandler != null) {
+ LocatorImpl li = new LocatorImpl(this,
+ e.e.currentToken.next.beginLine,
+ e.e.currentToken.next.beginColumn-1);
+ reportError(li, e.e);
+ }
+ } catch (ParseException e) {
+ reportError(getLocator(), e);
+ skipStatement();
+ // reportWarningSkipText(getLocator(), skipStatement());
+
+ } catch (TokenMgrError e) {
+ reportWarningSkipText(getLocator(), skipStatement());
+ } finally {
+ if (start) {
+ documentHandler.endSelector();
+ }
+ }
+ }
+
+ final public ArrayList<String> selectorList() throws ParseException {
+ ArrayList<String> selectors = new ArrayList<String>();
+ String selector;
+ selector = selector();
+ label_50:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ ;
+ break;
+ default:
+ jj_la1[71] = jj_gen;
+ break label_50;
+ }
+ jj_consume_token(COMMA);
+ label_51:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[72] = jj_gen;
+ break label_51;
}
+ jj_consume_token(S);
+ }
+ selectors.add(selector);
+ selector = selector();
}
+ selectors.add(selector);
+ {if (true) return selectors;}
+ throw new Error("Missing return statement in function");
+ }
- final public void debugDirective() throws ParseException {
- jj_consume_token(DEBUG_SYM);
- String content = skipStatementUntilSemiColon();
- // TODO should evaluate the content expression, call
- // documentHandler.debugDirective() etc.
- System.out.println(content);
- label_134: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[194] = jj_gen;
- break label_134;
- }
- jj_consume_token(S);
- }
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String selector() throws ParseException {
+ String selector = null;
+ char comb;
+ try {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case IDENT:
+ case HASH:
+ selector = simple_selector(null, ' ');
+ break;
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ comb = combinatorChar();
+ selector = simple_selector(selector, comb);
+ break;
+ default:
+ jj_la1[73] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_52:
+ while (true) {
+ if (jj_2_2(2)) {
+ ;
+ } else {
+ break label_52;
+ }
+ comb = combinator();
+ selector = simple_selector(selector, comb);
+ }
+ label_53:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[74] = jj_gen;
+ break label_53;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return selector;}
+ } catch (ParseException e) {
+ /*
+ Token t = getToken(1);
+ StringBuffer s = new StringBuffer();
+ s.append(getToken(0).image);
+ while ((t.kind != COMMA) && (t.kind != SEMICOLON)
+ && (t.kind != LBRACE) && (t.kind != EOF)) {
+ s.append(t.image);
+ getNextToken();
+ t = getToken(1);
+ }
+ reportWarningSkipText(getLocator(), s.toString());
+ */
+ Token t = getToken(1);
+ while ((t.kind != COMMA) && (t.kind != SEMICOLON)
+ && (t.kind != LBRACE) && (t.kind != EOF)) {
+ getNextToken();
+ t = getToken(1);
+ }
- final public void warnDirective() throws ParseException {
- jj_consume_token(WARN_SYM);
- String content = skipStatementUntilSemiColon();
- // TODO should evaluate the content expression, call
- // documentHandler.warnDirective() etc.
- System.err.println(content);
- label_135: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[195] = jj_gen;
- break label_135;
- }
- jj_consume_token(S);
- }
+ {if (true) throw new ThrowedParseException(e);}
}
+ throw new Error("Missing return statement in function");
+ }
- final public Node forDirective() throws ParseException {
- String var;
- String from;
- String to;
- boolean exclusive;
- String body;
- Token tok;
- var = variableName();
- int[] toThrough = { TO, THROUGH };
- from = skipStatementUntil(toThrough);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case TO:
- tok = jj_consume_token(TO);
- exclusive = true;
- break;
- case THROUGH:
- tok = jj_consume_token(THROUGH);
- exclusive = false;
- break;
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String simple_selector(String selector, char comb) throws ParseException {
+ String simple_current = null;
+ String cond = null;
+
+ pseudoElt = null;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case ANY:
+ case PARENT:
+ case INTERPOLATION:
+ case IDENT:
+ simple_current = element_name();
+ label_54:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case LBRACKET:
+ case DOT:
+ case COLON:
+ case HASH:
+ ;
+ break;
default:
- jj_la1[196] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[75] = jj_gen;
+ break label_54;
}
- to = skipStatementUntilLeftBrace();
- label_136: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[197] = jj_gen;
- break label_136;
- }
- jj_consume_token(S);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case HASH:
+ cond = hash(cond);
+ break;
+ case DOT:
+ cond = _class(cond);
+ break;
+ case LBRACKET:
+ cond = attrib(cond);
+ break;
+ case COLON:
+ cond = pseudo(cond);
+ break;
+ default:
+ jj_la1[76] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ break;
+ case HASH:
+ cond = hash(cond);
+ label_55:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case LBRACKET:
+ case DOT:
+ case COLON:
+ ;
+ break;
+ default:
+ jj_la1[77] = jj_gen;
+ break label_55;
}
- body = skipStatement();
- {
- if (true) {
- return documentHandler.forDirective(var, from, to, exclusive,
- body);
- }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case DOT:
+ cond = _class(cond);
+ break;
+ case LBRACKET:
+ cond = attrib(cond);
+ break;
+ case COLON:
+ cond = pseudo(cond);
+ break;
+ default:
+ jj_la1[78] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ break;
+ case DOT:
+ cond = _class(cond);
+ label_56:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case LBRACKET:
+ case DOT:
+ case COLON:
+ case HASH:
+ ;
+ break;
+ default:
+ jj_la1[79] = jj_gen;
+ break label_56;
}
- throw new Error("Missing return statement in function");
- }
-
- final public Node whileDirective() throws ParseException {
- String condition;
- String body;
- condition = skipStatementUntilLeftBrace();
- body = skipStatement();
- {
- if (true) {
- return documentHandler.whileDirective(condition, body);
- }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case HASH:
+ cond = hash(cond);
+ break;
+ case DOT:
+ cond = _class(cond);
+ break;
+ case LBRACKET:
+ cond = attrib(cond);
+ break;
+ case COLON:
+ cond = pseudo(cond);
+ break;
+ default:
+ jj_la1[80] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ break;
+ case COLON:
+ cond = pseudo(cond);
+ label_57:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case LBRACKET:
+ case DOT:
+ case COLON:
+ case HASH:
+ ;
+ break;
+ default:
+ jj_la1[81] = jj_gen;
+ break label_57;
}
- throw new Error("Missing return statement in function");
- }
-
- final public void extendDirective() throws ParseException {
- ArrayList<String> list;
- jj_consume_token(EXTEND_SYM);
- label_137: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[198] = jj_gen;
- break label_137;
- }
- jj_consume_token(S);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case HASH:
+ cond = hash(cond);
+ break;
+ case DOT:
+ cond = _class(cond);
+ break;
+ case LBRACKET:
+ cond = attrib(cond);
+ break;
+ case COLON:
+ cond = pseudo(cond);
+ break;
+ default:
+ jj_la1[82] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ break;
+ case LBRACKET:
+ cond = attrib(cond);
+ label_58:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case LBRACKET:
+ case DOT:
+ case COLON:
+ case HASH:
+ ;
+ break;
+ default:
+ jj_la1[83] = jj_gen;
+ break label_58;
}
- list = selectorList();
- label_138: while (true) {
- jj_consume_token(SEMICOLON);
- label_139: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case HASH:
+ cond = hash(cond);
+ break;
+ case DOT:
+ cond = _class(cond);
+ break;
+ case LBRACKET:
+ cond = attrib(cond);
+ break;
+ case COLON:
+ cond = pseudo(cond);
+ break;
+ default:
+ jj_la1[84] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ break;
+ default:
+ jj_la1[85] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ if (simple_current == null) {
+ simple_current = "";
+ }
+ if (cond != null) {
+ simple_current = simple_current + cond;
+ }
+ StringBuilder builder = new StringBuilder();
+ switch (comb) {
+ case ' ':
+ if(selector!=null){
+ builder.append(selector).append(" ");
+ }
+ break;
+ case '+':
+ case '>':
+ case '~':
+ if(selector!=null){
+ builder.append(selector).append(" ");
+ }
+ builder.append(comb).append(" ");
break;
default:
- jj_la1[199] = jj_gen;
- break label_139;
- }
- jj_consume_token(S);
+ {if (true) throw new ParseException("invalid state. send a bug report");}
}
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[200] = jj_gen;
- break label_138;
- }
- }
- documentHandler.extendDirective(list);
- }
+ builder.append(simple_current);
+ selector = builder.toString();
- Node importDirective() throws ParseException {
- return null;
- }
-
- Node charsetDirective() throws ParseException {
- return null;
- }
-
- Node mozDocumentDirective() throws ParseException {
- return null;
- }
+ if (pseudoElt != null) {
+ selector = selector + pseudoElt;
+ }
+ {if (true) return selector;}
+ throw new Error("Missing return statement in function");
+ }
- Node supportsDirective() throws ParseException {
- return null;
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String _class(String pred) throws ParseException {
+ Token t;
+String s = ".";
+ jj_consume_token(DOT);
+ label_59:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ t = jj_consume_token(IDENT);
+ s += t.image;
+ break;
+ case INTERPOLATION:
+ t = jj_consume_token(INTERPOLATION);
+ s += t.image;
+ break;
+ default:
+ jj_la1[86] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ ;
+ break;
+ default:
+ jj_la1[87] = jj_gen;
+ break label_59;
+ }
+ }
+ if (pred == null) {
+ {if (true) return s;}
+ } else {
+ {if (true) return pred + s;}
+ }
+ throw new Error("Missing return statement in function");
+ }
- final public void nestedProperties() throws ParseException {
- String name;
- LexicalUnit exp;
- name = property();
- jj_consume_token(COLON);
- label_140: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[201] = jj_gen;
- break label_140;
- }
- jj_consume_token(S);
- }
- jj_consume_token(LBRACE);
- label_141: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[202] = jj_gen;
- break label_141;
- }
- jj_consume_token(S);
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String element_name() throws ParseException {
+ Token t; String s = "";
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ label_60:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ t = jj_consume_token(IDENT);
+ s += t.image;
+ break;
+ case INTERPOLATION:
+ t = jj_consume_token(INTERPOLATION);
+ s += t.image;
+ break;
+ default:
+ jj_la1[88] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
}
- documentHandler.startNestedProperties(name);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case INTERPOLATION:
case IDENT:
- declaration();
- break;
+ ;
+ break;
default:
- jj_la1[203] = jj_gen;
- ;
- }
- label_142: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[204] = jj_gen;
- break label_142;
- }
- jj_consume_token(SEMICOLON);
- label_143: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[205] = jj_gen;
- break label_143;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[206] = jj_gen;
- ;
- }
- }
- jj_consume_token(RBRACE);
- documentHandler.endNestedProperties(name);
- label_144: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[207] = jj_gen;
- break label_144;
- }
- jj_consume_token(S);
- }
- }
+ jj_la1[89] = jj_gen;
+ break label_60;
+ }
+ }
+ {if (true) return s;}
+ break;
+ case ANY:
+ jj_consume_token(ANY);
+ {if (true) return "*";}
+ break;
+ case PARENT:
+ jj_consume_token(PARENT);
+ {if (true) return "&";}
+ break;
+ default:
+ jj_la1[90] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ throw new Error("Missing return statement in function");
+ }
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void styleRuleOrDeclarationOrNestedProperties()
- throws ParseException {
- try {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DEBUG_SYM:
- case WARN_SYM:
- debuggingDirective();
- break;
- default:
- jj_la1[208] = jj_gen;
- if (jj_2_6(2147483647)) {
- styleRule();
- } else if (jj_2_7(3)) {
- declarationOrNestedProperties();
- } else {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case IDENT:
- case HASH:
- styleRule();
- break;
- default:
- jj_la1[209] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- }
- } catch (JumpException e) {
- skipAfterExpression();
- // reportWarningSkipText(getLocator(), skipAfterExpression());
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String attrib(String pred) throws ParseException {
+ int cases = 0;
+ Token att = null;
+ Token val = null;
+ String attValue = null;
+ jj_consume_token(LBRACKET);
+ label_61:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[91] = jj_gen;
+ break label_61;
+ }
+ jj_consume_token(S);
+ }
+ att = jj_consume_token(IDENT);
+ label_62:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[92] = jj_gen;
+ break label_62;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case DASHMATCH:
+ case CARETMATCH:
+ case DOLLARMATCH:
+ case STARMATCH:
+ case INCLUDES:
+ case EQ:
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case EQ:
+ jj_consume_token(EQ);
+ cases = 1;
+ break;
+ case INCLUDES:
+ jj_consume_token(INCLUDES);
+ cases = 2;
+ break;
+ case DASHMATCH:
+ jj_consume_token(DASHMATCH);
+ cases = 3;
+ break;
+ case CARETMATCH:
+ jj_consume_token(CARETMATCH);
+ cases = 4;
+ break;
+ case DOLLARMATCH:
+ jj_consume_token(DOLLARMATCH);
+ cases = 5;
+ break;
+ case STARMATCH:
+ jj_consume_token(STARMATCH);
+ cases = 6;
+ break;
+ default:
+ jj_la1[93] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_63:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[94] = jj_gen;
+ break label_63;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ val = jj_consume_token(IDENT);
+ attValue = val.image;
+ break;
+ case STRING:
+ val = jj_consume_token(STRING);
+ attValue = val.image;
+ break;
+ default:
+ jj_la1[95] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_64:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[96] = jj_gen;
+ break label_64;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[97] = jj_gen;
+ ;
+ }
+ jj_consume_token(RBRACKET);
+ String name = convertIdent(att.image);
+ String c;
+ switch (cases) {
+ case 0:
+ c = name;
+ break;
+ case 1:
+ c = name + "=" + attValue;
+ break;
+ case 2:
+ c = name + "~=" + attValue;
+ break;
+ case 3:
+ c = name + "|=" +attValue;
+ break;
+ case 4:
+ c = name + "^=" +attValue;
+ break;
+ case 5:
+ c = name + "$=" +attValue;
+ break;
+ case 6:
+ c = name + "*=" +attValue;
+ break;
+ default:
+ // never reached.
+ c = null;
+ }
+ c = "[" + c + "]";
+ if (pred == null) {
+ {if (true) return c;}
+ } else {
+ {if (true) return pred + c;}
+ }
+ throw new Error("Missing return statement in function");
+ }
- } catch (ParseException e) {
- if (errorHandler != null) {
- if (e.currentToken != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.currentToken.next.beginLine,
- e.currentToken.next.beginColumn - 1);
- reportError(li, e);
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String pseudo(String pred) throws ParseException {
+ Token n;
+Token param;
+String d;
+boolean isPseudoElement = false;
+ jj_consume_token(COLON);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COLON:
+ jj_consume_token(COLON);
+ isPseudoElement=true;
+ break;
+ default:
+ jj_la1[98] = jj_gen;
+ ;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ n = jj_consume_token(IDENT);
+ String s = ":" + convertIdent(n.image);
+ if (isPseudoElement) {
+ if (pseudoElt != null) {
+ {if (true) throw new CSSParseException("duplicate pseudo element definition "
+ + s, getLocator());}
} else {
- reportError(getLocator(), e);
+ pseudoElt = ":"+s;
+ {if (true) return pred;}
}
- skipAfterExpression();
- /*
- * LocatorImpl loc = (LocatorImpl) getLocator(); loc.column--;
- * reportWarningSkipText(loc, skipAfterExpression());
- */
} else {
- skipAfterExpression();
- }
- }
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void declarationOrNestedProperties() throws ParseException {
- boolean important = false;
- String name;
- LexicalUnitImpl exp;
- Token save;
- String comment = null;
- try {
- name = property();
- save = token;
- jj_consume_token(COLON);
- label_145: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[210] = jj_gen;
- break label_145;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case MINUS:
- case DOT:
- case TO:
- case THROUGH:
- case FROM:
- case STRING:
- case IDENT:
- case NUMBER:
- case URL:
- case VARIABLE:
- case PERCENTAGE:
- case PT:
- case MM:
- case CM:
- case PC:
- case IN:
- case PX:
- case EMS:
- case LEM:
- case REM:
- case EXS:
- case DEG:
- case RAD:
- case GRAD:
- case MS:
- case SECOND:
- case HZ:
- case KHZ:
- case DIMEN:
- case HASH:
- case UNICODERANGE:
- case FUNCTION:
- exp = expr();
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IMPORTANT_SYM:
- important = prio();
- break;
- default:
- jj_la1[211] = jj_gen;
- ;
- }
- Token next = getToken(1);
- if (next.kind == SEMICOLON || next.kind == RBRACE) {
- while (next.kind == SEMICOLON) {
- skipStatement();
- next = getToken(1);
- }
- if (token.specialToken != null) {
- documentHandler.property(name, exp, important,
- token.specialToken.image);
- } else {
- documentHandler.property(name, exp, important, null);
- }
- }
- break;
- case LBRACE:
- jj_consume_token(LBRACE);
- label_146: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[212] = jj_gen;
- break label_146;
- }
- jj_consume_token(S);
- }
- documentHandler.startNestedProperties(name);
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[213] = jj_gen;
- ;
- }
- label_147: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[214] = jj_gen;
- break label_147;
- }
- jj_consume_token(SEMICOLON);
- label_148: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[215] = jj_gen;
- break label_148;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[216] = jj_gen;
- ;
- }
- }
- jj_consume_token(RBRACE);
- label_149: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[217] = jj_gen;
- break label_149;
- }
- jj_consume_token(S);
- }
- documentHandler.endNestedProperties(name);
- break;
- default:
- jj_la1[218] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- } catch (JumpException e) {
- skipAfterExpression();
- // reportWarningSkipText(getLocator(), skipAfterExpression());
-
- } catch (NumberFormatException e) {
- if (errorHandler != null) {
- errorHandler.error(new CSSParseException("Invalid number "
- + e.getMessage(), getLocator(), e));
- }
- reportWarningSkipText(getLocator(), skipAfterExpression());
- } catch (ParseException e) {
- if (errorHandler != null) {
- if (e.currentToken != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.currentToken.next.beginLine,
- e.currentToken.next.beginColumn - 1);
- reportError(li, e);
+ String c = s;
+ if (pred == null) {
+ {if (true) return c;}
} else {
- reportError(getLocator(), e);
+ {if (true) return pred + c;}
}
- skipAfterExpression();
- /*
- * LocatorImpl loc = (LocatorImpl) getLocator(); loc.column--;
- * reportWarningSkipText(loc, skipAfterExpression());
- */
- } else {
- skipAfterExpression();
}
- }
- }
+ break;
+ case FUNCTION:
+ n = jj_consume_token(FUNCTION);
+ label_65:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[99] = jj_gen;
+ break label_65;
+ }
+ jj_consume_token(S);
+ }
+ d = skipStatementUntilRightParan();
+ jj_consume_token(RPARAN);
+ // accept anything between function and a right parenthesis
+ String f = convertIdent(n.image);
+ String colons = isPseudoElement ? "::" : ":";
+ String pseudofn = colons + f + d + ")";
+ if (pred == null) {
+ {if (true) return pseudofn;}
+ } else {
+ {if (true) return pred + pseudofn;}
+ }
+ break;
+ default:
+ jj_la1[100] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ throw new Error("Missing return statement in function");
+ }
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public void declaration() throws ParseException {
- boolean important = false;
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String hash(String pred) throws ParseException {
+ Token n;
+ n = jj_consume_token(HASH);
+ String d = n.image;
+ if (pred == null) {
+ {if (true) return d;}
+ } else {
+ {if (true) return pred + d;}
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void variable() throws ParseException {
String name;
- LexicalUnit exp;
- Token save;
- try {
- name = property();
- save = token;
- jj_consume_token(COLON);
- label_150: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[219] = jj_gen;
- break label_150;
- }
- jj_consume_token(S);
- }
- exp = expr();
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IMPORTANT_SYM:
- important = prio();
- break;
- default:
- jj_la1[220] = jj_gen;
- ;
- }
- documentHandler.property(name, exp, important);
- } catch (JumpException e) {
+ LexicalUnitImpl exp = null;
+ boolean guarded = false;
+ String raw;
+ try {
+ name = variableName();
+ jj_consume_token(COLON);
+ label_66:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[101] = jj_gen;
+ break label_66;
+ }
+ jj_consume_token(S);
+ }
+ exp = expr();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case GUARDED_SYM:
+ guarded = guarded();
+ break;
+ default:
+ jj_la1[102] = jj_gen;
+ ;
+ }
+ label_67:
+ while (true) {
+ jj_consume_token(SEMICOLON);
+ label_68:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[103] = jj_gen;
+ break label_68;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[104] = jj_gen;
+ break label_67;
+ }
+ }
+ documentHandler.variable(name, exp, guarded);
+ } catch (JumpException e) {
skipAfterExpression();
- // reportWarningSkipText(getLocator(), skipAfterExpression());
-
- } catch (NumberFormatException e) {
+ } catch (NumberFormatException e) {
if (errorHandler != null) {
errorHandler.error(new CSSParseException("Invalid number "
- + e.getMessage(), getLocator(), e));
+ + e.getMessage(),
+ getLocator(),
+ e));
}
reportWarningSkipText(getLocator(), skipAfterExpression());
- } catch (ParseException e) {
+ } catch (ParseException e) {
if (errorHandler != null) {
if (e.currentToken != null) {
- LocatorImpl li = new LocatorImpl(this,
- e.currentToken.next.beginLine,
- e.currentToken.next.beginColumn - 1);
- reportError(li, e);
+ LocatorImpl li = new LocatorImpl(this,
+ e.currentToken.next.beginLine,
+ e.currentToken.next.beginColumn-1);
+ reportError(li, e);
} else {
- reportError(getLocator(), e);
- }
+ reportError(getLocator(), e);
+ }
skipAfterExpression();
- /*
- * LocatorImpl loc = (LocatorImpl) getLocator(); loc.column--;
- * reportWarningSkipText(loc, skipAfterExpression());
- */
} else {
skipAfterExpression();
}
- }
}
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public boolean prio() throws ParseException {
- jj_consume_token(IMPORTANT_SYM);
- label_151: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[221] = jj_gen;
- break label_151;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return true;
- }
+ }
+
+ final public void controlDirective() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IF_SYM:
+ ifDirective();
+ break;
+ case EACH_SYM:
+ eachDirective();
+ break;
+ default:
+ jj_la1[105] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+ final public void ifContentStatement() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case CONTENT_SYM:
+ contentDirective();
+ break;
+ case INCLUDE_SYM:
+ includeDirective();
+ break;
+ case MEDIA_SYM:
+ media();
+ break;
+ case EXTEND_SYM:
+ extendDirective();
+ break;
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case IDENT:
+ case HASH:
+ styleRuleOrDeclarationOrNestedProperties();
+ break;
+ case KEY_FRAME_SYM:
+ keyframes();
+ break;
+ default:
+ jj_la1[106] = jj_gen;
+ if (jj_2_3(2147483647)) {
+ variable();
+ } else {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case VARIABLE:
+ listModifyDirective();
+ break;
+ default:
+ jj_la1[107] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ }
+ }
+
+ final public void ifDirective() throws ParseException {
+ Token n = null;
+ String s = null;
+ String evaluator = "";
+ jj_consume_token(IF_SYM);
+ label_69:
+ while (true) {
+ s = booleanExpressionToken();
+ evaluator += s;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ case EQ:
+ case PLUS:
+ case MINUS:
+ case PRECEDES:
+ case SUCCEEDS:
+ case DIV:
+ case ANY:
+ case LPARAN:
+ case RPARAN:
+ case COMPARE:
+ case OR:
+ case AND:
+ case NOT_EQ:
+ case IDENT:
+ case NUMBER:
+ case VARIABLE:
+ case CONTAINS:
+ ;
+ break;
+ default:
+ jj_la1[108] = jj_gen;
+ break label_69;
+ }
+ }
+ jj_consume_token(LBRACE);
+ label_70:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[109] = jj_gen;
+ break label_70;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.startIfElseDirective();
+ documentHandler.ifDirective(evaluator);
+ label_71:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ;
+ break;
+ default:
+ jj_la1[110] = jj_gen;
+ break label_71;
+ }
+ ifContentStatement();
+ }
+ jj_consume_token(RBRACE);
+ label_72:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[111] = jj_gen;
+ break label_72;
+ }
+ jj_consume_token(S);
+ }
+ label_73:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case ELSE_SYM:
+ ;
+ break;
+ default:
+ jj_la1[112] = jj_gen;
+ break label_73;
+ }
+ elseDirective();
+ }
+ documentHandler.endIfElseDirective();
+ }
+
+ final public void elseDirective() throws ParseException {
+ String evaluator = "";
+ Token n = null;
+ String s = null;
+ jj_consume_token(ELSE_SYM);
+ label_74:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[113] = jj_gen;
+ break label_74;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IF:
+ jj_consume_token(IF);
+ label_75:
+ while (true) {
+ s = booleanExpressionToken();
+ evaluator += s;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ case EQ:
+ case PLUS:
+ case MINUS:
+ case PRECEDES:
+ case SUCCEEDS:
+ case DIV:
+ case ANY:
+ case LPARAN:
+ case RPARAN:
+ case COMPARE:
+ case OR:
+ case AND:
+ case NOT_EQ:
+ case IDENT:
+ case NUMBER:
+ case VARIABLE:
+ case CONTAINS:
+ ;
+ break;
+ default:
+ jj_la1[114] = jj_gen;
+ break label_75;
+ }
+ }
+ break;
+ default:
+ jj_la1[115] = jj_gen;
+ ;
+ }
+ jj_consume_token(LBRACE);
+ label_76:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[116] = jj_gen;
+ break label_76;
+ }
+ jj_consume_token(S);
+ }
+ if(!evaluator.trim().equals("")){ documentHandler.ifDirective(evaluator); }
+ else{ documentHandler.elseDirective(); }
+ label_77:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ;
+ break;
+ default:
+ jj_la1[117] = jj_gen;
+ break label_77;
+ }
+ ifContentStatement();
+ }
+ jj_consume_token(RBRACE);
+ label_78:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[118] = jj_gen;
+ break label_78;
+ }
+ jj_consume_token(S);
+ }
+ }
+
+ final public String booleanExpressionToken() throws ParseException {
+ Token n = null;
+ String s = null;
+ if (jj_2_4(2147483647)) {
+ s = containsDirective();
+ } else {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case VARIABLE:
+ n = jj_consume_token(VARIABLE);
+ break;
+ case IDENT:
+ n = jj_consume_token(IDENT);
+ break;
+ case NUMBER:
+ n = jj_consume_token(NUMBER);
+ break;
+ case LPARAN:
+ n = jj_consume_token(LPARAN);
+ break;
+ case RPARAN:
+ n = jj_consume_token(RPARAN);
+ break;
+ case PLUS:
+ n = jj_consume_token(PLUS);
+ break;
+ case MINUS:
+ n = jj_consume_token(MINUS);
+ break;
+ case DIV:
+ n = jj_consume_token(DIV);
+ break;
+ case ANY:
+ n = jj_consume_token(ANY);
+ break;
+ case COMPARE:
+ n = jj_consume_token(COMPARE);
+ break;
+ case EQ:
+ n = jj_consume_token(EQ);
+ break;
+ case PRECEDES:
+ n = jj_consume_token(PRECEDES);
+ break;
+ case SUCCEEDS:
+ n = jj_consume_token(SUCCEEDS);
+ break;
+ case OR:
+ n = jj_consume_token(OR);
+ break;
+ case AND:
+ n = jj_consume_token(AND);
+ break;
+ case S:
+ n = jj_consume_token(S);
+ break;
+ case NOT_EQ:
+ n = jj_consume_token(NOT_EQ);
+ break;
+ default:
+ jj_la1[119] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ if(n!=null){{if (true) return n.image;}}
+ else{{if (true) return s;}}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void eachDirective() throws ParseException {
+ Token var;
+ ArrayList<String> list = null;
+ String listVariable = null;
+ jj_consume_token(EACH_SYM);
+ label_79:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[120] = jj_gen;
+ break label_79;
+ }
+ jj_consume_token(S);
+ }
+ var = jj_consume_token(VARIABLE);
+ label_80:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[121] = jj_gen;
+ break label_80;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(EACH_IN);
+ label_81:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[122] = jj_gen;
+ break label_81;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ list = stringList();
+ documentHandler.startEachDirective(var.image, list);
+ break;
+ case VARIABLE:
+ listVariable = variableName();
+ documentHandler.startEachDirective(var.image, listVariable);
+ break;
+ default:
+ jj_la1[123] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ jj_consume_token(LBRACE);
+ label_82:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[124] = jj_gen;
+ break label_82;
+ }
+ jj_consume_token(S);
+ }
+ label_83:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ;
+ break;
+ default:
+ jj_la1[125] = jj_gen;
+ break label_83;
+ }
+ ifContentStatement();
+ }
+ jj_consume_token(RBRACE);
+ label_84:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[126] = jj_gen;
+ break label_84;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.endEachDirective();
+ }
+
+ final public ArrayList<String > stringList() throws ParseException {
+ ArrayList<String > strings = new ArrayList<String >();
+ Token input;
+ input = jj_consume_token(IDENT);
+ label_85:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[127] = jj_gen;
+ break label_85;
+ }
+ jj_consume_token(S);
+ }
+ strings.add(input.image);
+ label_86:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ ;
+ break;
+ default:
+ jj_la1[128] = jj_gen;
+ break label_86;
+ }
+ jj_consume_token(COMMA);
+ label_87:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[129] = jj_gen;
+ break label_87;
+ }
+ jj_consume_token(S);
+ }
+ input = jj_consume_token(IDENT);
+ strings.add(input.image);
+ label_88:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[130] = jj_gen;
+ break label_88;
+ }
+ jj_consume_token(S);
+ }
+ }
+ {if (true) return strings;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void mixinDirective() throws ParseException {
+ String name;
+ ArrayList<VariableNode> args = null;
+ String body;
+ jj_consume_token(MIXIN_SYM);
+ label_89:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[131] = jj_gen;
+ break label_89;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ name = property();
+ break;
+ case FUNCTION:
+ name = functionName();
+ args = arglist();
+ jj_consume_token(RPARAN);
+ label_90:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[132] = jj_gen;
+ break label_90;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[133] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ jj_consume_token(LBRACE);
+ label_91:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[134] = jj_gen;
+ break label_91;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.startMixinDirective(name, args);
+ label_92:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EACH_SYM:
+ case IF_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case PAGE_SYM:
+ case FONT_FACE_SYM:
+ case KEY_FRAME_SYM:
+ ;
+ break;
+ default:
+ jj_la1[135] = jj_gen;
+ break label_92;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case INCLUDE_SYM:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case EXTEND_SYM:
+ case CONTENT_SYM:
+ case IDENT:
+ case VARIABLE:
+ case HASH:
+ case MEDIA_SYM:
+ case KEY_FRAME_SYM:
+ ifContentStatement();
+ break;
+ case EACH_SYM:
+ case IF_SYM:
+ controlDirective();
+ break;
+ case FONT_FACE_SYM:
+ fontFace();
+ break;
+ case PAGE_SYM:
+ page();
+ break;
+ default:
+ jj_la1[136] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+ jj_consume_token(RBRACE);
+ label_93:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[137] = jj_gen;
+ break label_93;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.endMixinDirective(name, args);
+ }
+
+ final public ArrayList<VariableNode> arglist() throws ParseException {
+ ArrayList<VariableNode> args = new ArrayList<VariableNode>();
+ VariableNode arg;
+ boolean hasNonOptionalArgument = false;
+ arg = mixinArg();
+ label_94:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ ;
+ break;
+ default:
+ jj_la1[138] = jj_gen;
+ break label_94;
+ }
+ jj_consume_token(COMMA);
+ label_95:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[139] = jj_gen;
+ break label_95;
}
- throw new Error("Missing return statement in function");
+ jj_consume_token(S);
+ }
+ hasNonOptionalArgument = checkMixinForNonOptionalArguments(arg, hasNonOptionalArgument); args.add(arg);
+ arg = mixinArg();
}
+ hasNonOptionalArgument = checkMixinForNonOptionalArguments(arg, hasNonOptionalArgument); args.add(arg);
+ {if (true) return args;}
+ throw new Error("Missing return statement in function");
+ }
- final public boolean guarded() throws ParseException {
- jj_consume_token(GUARDED_SYM);
- label_152: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[222] = jj_gen;
- break label_152;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return true;
- }
- }
- throw new Error("Missing return statement in function");
- }
+ boolean checkMixinForNonOptionalArguments(VariableNode arg, boolean hasNonOptionalArguments) throws ParseException {
+ boolean currentArgHasArguments = arg.getExpr() != null && arg.getExpr().getLexicalUnitType() == LexicalUnitImpl.SCSS_VARIABLE && arg.getExpr().getNextLexicalUnit() != null;
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public LexicalUnitImpl operator(LexicalUnitImpl prev)
- throws ParseException {
- Token n;
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DIV:
- n = jj_consume_token(DIV);
- label_153: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[223] = jj_gen;
- break label_153;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return LexicalUnitImpl.createSlash(n.beginLine,
- n.beginColumn, prev);
- }
- }
- break;
- case COMMA:
- n = jj_consume_token(COMMA);
- label_154: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[224] = jj_gen;
- break label_154;
- }
- jj_consume_token(S);
- }
- {
- if (true) {
- return LexicalUnitImpl.createComma(n.beginLine,
- n.beginColumn, prev);
+ if(currentArgHasArguments)
+ {
+ if(hasNonOptionalArguments)
+ {
+ throw new ParseException("Sass Error: Required argument $"+ arg.getName() +" must come before any optional arguments.");
}
- }
+ return hasNonOptionalArguments;
+ }else
+ {
+ return true;
+ }
+ }
+
+ final public VariableNode mixinArg() throws ParseException {
+ String name;
+ Token variable = null;
+ LexicalUnitImpl first = null;
+ LexicalUnitImpl prev = null;
+ LexicalUnitImpl next = null;
+ name = variableName();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COLON:
+ case VARIABLE:
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COLON:
+ jj_consume_token(COLON);
+ label_96:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
break;
- default:
- jj_la1[225] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ default:
+ jj_la1[140] = jj_gen;
+ break label_96;
+ }
+ jj_consume_token(S);
}
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public LexicalUnitImpl expr() throws ParseException {
- LexicalUnitImpl first, res;
- char op;
- first = term(null);
- res = first;
- label_155: while (true) {
- if (jj_2_8(2)) {
+ first = nonVariableTerm(null);
+ prev = first;
+ label_97:
+ while (true) {
+ if (jj_2_5(3)) {
+ ;
+ } else {
+ break label_97;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ jj_consume_token(COMMA);
+ label_98:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
;
- } else {
- break label_155;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case COMMA:
- case DIV:
- res = operator(res);
break;
- default:
- jj_la1[226] = jj_gen;
- ;
- }
- res = term(res);
- }
- {
- if (true) {
- return first;
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public char unaryOperator() throws ParseException {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case MINUS:
- jj_consume_token(MINUS);
- {
- if (true) {
- return '-';
- }
+ default:
+ jj_la1[141] = jj_gen;
+ break label_98;
+ }
+ jj_consume_token(S);
}
break;
- case PLUS:
- jj_consume_token(PLUS);
- {
- if (true) {
- return '+';
- }
- }
+ default:
+ jj_la1[142] = jj_gen;
+ ;
+ }
+ prev = nonVariableTerm(prev);
+ }
+ break;
+ case VARIABLE:
+ variable = jj_consume_token(VARIABLE);
+ first = LexicalUnitImpl.createVariable(token.beginLine, token.beginColumn,
+ prev, variable.image);
+ break;
+ default:
+ jj_la1[143] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ default:
+ jj_la1[144] = jj_gen;
+ ;
+ }
+ VariableNode arg = new VariableNode(name, first, false);
+ {if (true) return arg;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public ArrayList<LexicalUnitImpl> argValuelist() throws ParseException {
+ ArrayList<LexicalUnitImpl> args = new ArrayList<LexicalUnitImpl>();
+ LexicalUnitImpl first = null;
+ LexicalUnitImpl next = null;
+ LexicalUnitImpl prev = null;
+ first = term(null);
+ args.add(first); prev = first;
+ label_99:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case MINUS:
+ case DOT:
+ case COLON:
+ case TO:
+ case THROUGH:
+ case FROM:
+ case STRING:
+ case IDENT:
+ case NUMBER:
+ case URL:
+ case VARIABLE:
+ case PERCENTAGE:
+ case PT:
+ case MM:
+ case CM:
+ case PC:
+ case IN:
+ case PX:
+ case EMS:
+ case LEM:
+ case REM:
+ case EXS:
+ case DEG:
+ case RAD:
+ case GRAD:
+ case MS:
+ case SECOND:
+ case HZ:
+ case KHZ:
+ case DIMEN:
+ case HASH:
+ case UNICODERANGE:
+ case FUNCTION:
+ ;
+ break;
+ default:
+ jj_la1[145] = jj_gen;
+ break label_99;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COLON:
+ jj_consume_token(COLON);
+ label_100:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
break;
+ default:
+ jj_la1[146] = jj_gen;
+ break label_100;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[147] = jj_gen;
+ ;
+ }
+ next = term(prev);
+ prev.setNextLexicalUnit(next); prev = next;
+ }
+ label_101:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ ;
+ break;
+ default:
+ jj_la1[148] = jj_gen;
+ break label_101;
+ }
+ jj_consume_token(COMMA);
+ label_102:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
default:
- jj_la1[227] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public LexicalUnitImpl term(LexicalUnitImpl prev)
- throws ParseException {
- LexicalUnitImpl result = null;
- Token n = null;
- char op = ' ';
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ jj_la1[149] = jj_gen;
+ break label_102;
+ }
+ jj_consume_token(S);
+ }
+ first = term(null);
+ args.add(first); prev = first;
+ label_103:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case PLUS:
case MINUS:
case DOT:
+ case COLON:
case TO:
case THROUGH:
case FROM:
@@ -5145,6 +3612,7 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
case IDENT:
case NUMBER:
case URL:
+ case VARIABLE:
case PERCENTAGE:
case PT:
case MM:
@@ -5167,395 +3635,2005 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
case HASH:
case UNICODERANGE:
case FUNCTION:
- result = nonVariableTerm(prev);
- break;
- case VARIABLE:
- result = variableTerm(prev);
- break;
+ ;
+ break;
default:
- jj_la1[228] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ jj_la1[150] = jj_gen;
+ break label_103;
}
- {
- if (true) {
- return result;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COLON:
+ jj_consume_token(COLON);
+ label_104:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[151] = jj_gen;
+ break label_104;
}
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[152] = jj_gen;
+ ;
+ }
+ next = term(prev);
+ prev.setNextLexicalUnit(next); prev = next;
+ }
+ }
+ {if (true) return args;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void includeDirective() throws ParseException {
+ String name;
+ ArrayList<LexicalUnitImpl> args=null;
+ jj_consume_token(INCLUDE_SYM);
+ label_105:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[153] = jj_gen;
+ break label_105;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ name = property();
+ break;
+ case VARIABLE:
+ name = variableName();
+ name = "$"+name;
+ break;
+ case FUNCTION:
+ name = functionName();
+ args = argValuelist();
+ jj_consume_token(RPARAN);
+ break;
+ default:
+ jj_la1[154] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ label_106:
+ while (true) {
+ jj_consume_token(SEMICOLON);
+ label_107:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[155] = jj_gen;
+ break label_107;
+ }
+ jj_consume_token(S);
}
- throw new Error("Missing return statement in function");
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[156] = jj_gen;
+ break label_106;
+ }
+ }
+ documentHandler.includeDirective(name, args);
+ break;
+ case LBRACE:
+ jj_consume_token(LBRACE);
+ label_108:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[157] = jj_gen;
+ break label_108;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.startIncludeContentBlock(name);
+ label_109:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case DEBUG_SYM:
+ case WARN_SYM:
+ case IDENT:
+ case HASH:
+ ;
+ break;
+ default:
+ jj_la1[158] = jj_gen;
+ break label_109;
+ }
+ styleRuleOrDeclarationOrNestedProperties();
+ }
+ jj_consume_token(RBRACE);
+ label_110:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[159] = jj_gen;
+ break label_110;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.endIncludeContentBlock();
+ break;
+ default:
+ jj_la1[160] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+ final public String interpolation() throws ParseException {
+ Token n;
+ n = jj_consume_token(INTERPOLATION);
+ {if (true) return n.image;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void listModifyDirective() throws ParseException {
+ String list = null;
+ String remove = null;
+ String separator = null;
+ String variable = null;
+ Token n = null;
+ Token type = null;
+ //refactor, remove those 3 LOOKAHEAD(5).
+ n = jj_consume_token(VARIABLE);
+ variable = n.image;
+ label_111:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[161] = jj_gen;
+ break label_111;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(COLON);
+ label_112:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[162] = jj_gen;
+ break label_112;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case APPEND:
+ type = jj_consume_token(APPEND);
+ break;
+ case REMOVE:
+ type = jj_consume_token(REMOVE);
+ break;
+ case CONTAINS:
+ type = jj_consume_token(CONTAINS);
+ break;
+ default:
+ jj_la1[163] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_113:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[164] = jj_gen;
+ break label_113;
+ }
+ jj_consume_token(S);
+ }
+ list = listModifyDirectiveArgs(0);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case RPARAN:
+ jj_consume_token(RPARAN);
+ break;
+ default:
+ jj_la1[165] = jj_gen;
+ ;
+ }
+ jj_consume_token(COMMA);
+ label_114:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[166] = jj_gen;
+ break label_114;
+ }
+ jj_consume_token(S);
+ }
+ remove = listModifyDirectiveArgs(1);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ jj_consume_token(COMMA);
+ label_115:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[167] = jj_gen;
+ break label_115;
+ }
+ jj_consume_token(S);
+ }
+ n = jj_consume_token(IDENT);
+ separator = n.image;
+ label_116:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[168] = jj_gen;
+ break label_116;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[169] = jj_gen;
+ ;
+ }
+ jj_consume_token(RPARAN);
+ switch (type.kind) {
+ case APPEND:
+ documentHandler.appendDirective(variable,list,remove,separator);
+ break;
+ case REMOVE:
+ documentHandler.removeDirective(variable,list,remove,separator);
+ break;
+ case CONTAINS:
+ if(variable == null){
+ variable = "$var_"+UUID.randomUUID();
+ }
+ documentHandler.containsDirective(variable,list,remove,separator);
+ break;
+ default:
+ break;
+ }
+ label_117:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[170] = jj_gen;
+ break label_117;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(SEMICOLON);
+ label_118:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[171] = jj_gen;
+ break label_118;
+ }
+ jj_consume_token(S);
+ }
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void appendDirective() throws ParseException {
+ String list = null;
+ String remove = null;
+ String separator = null;
+ String variable = null;
+ Token n = null;
+ n = jj_consume_token(VARIABLE);
+ variable = n.image;
+ label_119:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[172] = jj_gen;
+ break label_119;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(COLON);
+ label_120:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[173] = jj_gen;
+ break label_120;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(APPEND);
+ label_121:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[174] = jj_gen;
+ break label_121;
+ }
+ jj_consume_token(S);
+ }
+ list = listModifyDirectiveArgs(0);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case RPARAN:
+ jj_consume_token(RPARAN);
+ break;
+ default:
+ jj_la1[175] = jj_gen;
+ ;
+ }
+ jj_consume_token(COMMA);
+ label_122:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[176] = jj_gen;
+ break label_122;
+ }
+ jj_consume_token(S);
+ }
+ remove = listModifyDirectiveArgs(1);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ jj_consume_token(COMMA);
+ label_123:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[177] = jj_gen;
+ break label_123;
+ }
+ jj_consume_token(S);
+ }
+ n = jj_consume_token(IDENT);
+ separator = n.image;
+ label_124:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[178] = jj_gen;
+ break label_124;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[179] = jj_gen;
+ ;
}
+ jj_consume_token(RPARAN);
+ documentHandler.appendDirective(variable,list,remove,separator);
+ }
- final public LexicalUnitImpl variableTerm(LexicalUnitImpl prev)
- throws ParseException {
- LexicalUnitImpl result = null;
- String varName = "";
- varName = variableName();
- result = LexicalUnitImpl.createVariable(token.beginLine,
- token.beginColumn, prev, varName);
- {
- if (true) {
- return result;
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void removeDirective() throws ParseException {
+ String list = null;
+ String remove = null;
+ String separator = null;
+ String variable = null;
+ Token n = null;
+ n = jj_consume_token(VARIABLE);
+ variable = n.image;
+ label_125:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[180] = jj_gen;
+ break label_125;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(COLON);
+ label_126:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[181] = jj_gen;
+ break label_126;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(REMOVE);
+ label_127:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[182] = jj_gen;
+ break label_127;
+ }
+ jj_consume_token(S);
+ }
+ list = listModifyDirectiveArgs(0);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case RPARAN:
+ jj_consume_token(RPARAN);
+ break;
+ default:
+ jj_la1[183] = jj_gen;
+ ;
+ }
+ jj_consume_token(COMMA);
+ label_128:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[184] = jj_gen;
+ break label_128;
+ }
+ jj_consume_token(S);
+ }
+ remove = listModifyDirectiveArgs(1);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ jj_consume_token(COMMA);
+ label_129:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[185] = jj_gen;
+ break label_129;
+ }
+ jj_consume_token(S);
+ }
+ n = jj_consume_token(IDENT);
+ separator = n.image;
+ label_130:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[186] = jj_gen;
+ break label_130;
}
- throw new Error("Missing return statement in function");
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[187] = jj_gen;
+ ;
}
+ jj_consume_token(RPARAN);
+ documentHandler.removeDirective(variable,list,remove,separator);
+ }
- final public LexicalUnitImpl nonVariableTerm(LexicalUnitImpl prev)
- throws ParseException {
- LexicalUnitImpl result = null;
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public String containsDirective() throws ParseException {
+ String list = null;
+ String remove = null;
+ String separator = null;
+ String variable = null;
Token n = null;
- char op = ' ';
- String varName;
- String s = "";
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case MINUS:
- case NUMBER:
- case PERCENTAGE:
- case PT:
- case MM:
- case CM:
- case PC:
- case IN:
- case PX:
- case EMS:
- case LEM:
- case REM:
- case EXS:
- case DEG:
- case RAD:
- case GRAD:
- case MS:
- case SECOND:
- case HZ:
- case KHZ:
- case DIMEN:
- case FUNCTION:
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case MINUS:
- op = unaryOperator();
- break;
- default:
- jj_la1[229] = jj_gen;
- ;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case NUMBER:
- n = jj_consume_token(NUMBER);
- result = LexicalUnitImpl.createNumber(n.beginLine,
- n.beginColumn, prev, number(op, n, 0));
- break;
- case PERCENTAGE:
- n = jj_consume_token(PERCENTAGE);
- result = LexicalUnitImpl.createPercentage(n.beginLine,
- n.beginColumn, prev, number(op, n, 1));
- break;
- case PT:
- n = jj_consume_token(PT);
- result = LexicalUnitImpl.createPT(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case CM:
- n = jj_consume_token(CM);
- result = LexicalUnitImpl.createCM(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case MM:
- n = jj_consume_token(MM);
- result = LexicalUnitImpl.createMM(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case PC:
- n = jj_consume_token(PC);
- result = LexicalUnitImpl.createPC(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case IN:
- n = jj_consume_token(IN);
- result = LexicalUnitImpl.createIN(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case PX:
- n = jj_consume_token(PX);
- result = LexicalUnitImpl.createPX(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case EMS:
- n = jj_consume_token(EMS);
- result = LexicalUnitImpl.createEMS(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case LEM:
- n = jj_consume_token(LEM);
- result = LexicalUnitImpl.createLEM(n.beginLine, n.beginColumn,
- prev, number(op, n, 3));
- break;
- case REM:
- n = jj_consume_token(REM);
- result = LexicalUnitImpl.createREM(n.beginLine, n.beginColumn,
- prev, number(op, n, 3));
- break;
- case EXS:
- n = jj_consume_token(EXS);
- result = LexicalUnitImpl.createEXS(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case DEG:
- n = jj_consume_token(DEG);
- result = LexicalUnitImpl.createDEG(n.beginLine, n.beginColumn,
- prev, number(op, n, 3));
- break;
- case RAD:
- n = jj_consume_token(RAD);
- result = LexicalUnitImpl.createRAD(n.beginLine, n.beginColumn,
- prev, number(op, n, 3));
- break;
- case GRAD:
- n = jj_consume_token(GRAD);
- result = LexicalUnitImpl.createGRAD(n.beginLine, n.beginColumn,
- prev, number(op, n, 3));
- break;
- case SECOND:
- n = jj_consume_token(SECOND);
- result = LexicalUnitImpl.createS(n.beginLine, n.beginColumn,
- prev, number(op, n, 1));
- break;
- case MS:
- n = jj_consume_token(MS);
- result = LexicalUnitImpl.createMS(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case HZ:
- n = jj_consume_token(HZ);
- result = LexicalUnitImpl.createHZ(n.beginLine, n.beginColumn,
- prev, number(op, n, 2));
- break;
- case KHZ:
- n = jj_consume_token(KHZ);
- result = LexicalUnitImpl.createKHZ(n.beginLine, n.beginColumn,
- prev, number(op, n, 3));
- break;
- case DIMEN:
- n = jj_consume_token(DIMEN);
- s = n.image;
- int i = 0;
- while (i < s.length()
- && (Character.isDigit(s.charAt(i)) || (s.charAt(i) == '.'))) {
- i++;
- }
- result = LexicalUnitImpl.createDimen(n.beginLine,
- n.beginColumn, prev, Float.valueOf(s.substring(0, i))
- .floatValue(), s.substring(i));
- break;
- case FUNCTION:
- result = function(op, prev);
- break;
- default:
- jj_la1[230] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- break;
- case DOT:
- case TO:
- case THROUGH:
- case FROM:
- case STRING:
- case IDENT:
- case URL:
- case HASH:
- case UNICODERANGE:
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case STRING:
- n = jj_consume_token(STRING);
- result = LexicalUnitImpl.createString(n.beginLine,
- n.beginColumn, prev,
- convertStringIndex(n.image, 1, n.image.length() - 1));
- break;
- case DOT:
- case TO:
- case THROUGH:
- case FROM:
- case IDENT:
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case DOT:
- jj_consume_token(DOT);
- s += ".";
- break;
- default:
- jj_la1[231] = jj_gen;
- ;
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IDENT:
- n = jj_consume_token(IDENT);
- break;
- case TO:
- n = jj_consume_token(TO);
- break;
- case THROUGH:
- n = jj_consume_token(THROUGH);
- break;
- case FROM:
- n = jj_consume_token(FROM);
- break;
- default:
- jj_la1[232] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case VARIABLE:
+ n = jj_consume_token(VARIABLE);
+ variable = n.image;
+ label_131:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[188] = jj_gen;
+ break label_131;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(COLON);
+ label_132:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[189] = jj_gen;
+ break label_132;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[190] = jj_gen;
+ ;
+ }
+ jj_consume_token(CONTAINS);
+ label_133:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[191] = jj_gen;
+ break label_133;
+ }
+ jj_consume_token(S);
+ }
+ list = listModifyDirectiveArgs(0);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case RPARAN:
+ jj_consume_token(RPARAN);
+ break;
+ default:
+ jj_la1[192] = jj_gen;
+ ;
+ }
+ jj_consume_token(COMMA);
+ label_134:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[193] = jj_gen;
+ break label_134;
+ }
+ jj_consume_token(S);
+ }
+ remove = listModifyDirectiveArgs(1);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ jj_consume_token(COMMA);
+ label_135:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[194] = jj_gen;
+ break label_135;
+ }
+ jj_consume_token(S);
+ }
+ n = jj_consume_token(IDENT);
+ separator = n.image;
+ label_136:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[195] = jj_gen;
+ break label_136;
+ }
+ jj_consume_token(S);
+ }
+ break;
+ default:
+ jj_la1[196] = jj_gen;
+ ;
+ }
+ jj_consume_token(RPARAN);
+ /*
+ *if it is not in the form like "$contains : contains($items, .v-button);"
+ *for example in @if, like "@if (contains(a b c, b))", then create a temp
+ *variable for contains(a b c, b);
+ */
+ if(variable == null){
+ variable = "$var_"+UUID.randomUUID();
+ }
+ documentHandler.containsDirective(variable,list,remove,separator);
+ {if (true) return variable;}
+ throw new Error("Missing return statement in function");
+ }
+
+ String listModifyDirectiveArgs(int nest) throws ParseException {
+ String list = "";
+ int nesting = nest;
+ Token t = null;
+
+ while(true)
+ {
+ t = getToken(1);
+ String s = t.image;
+ if(t.kind == VARIABLE||t.kind == IDENT)
+ {
+ list += s;
+ }else if(s.toLowerCase().equals("auto")||s.toLowerCase().equals("space")||s.toLowerCase().equals("comma"))
+ {
+ int i = 2;
+ Token temp = getToken(i);
+ boolean isLast = true;
+ while(temp.kind != SEMICOLON)
+ {
+ if(temp.kind != RPARAN || temp.kind != S)
+ {
+ isLast = false;
+ }
+ i++;
+ temp = getToken(i);
+ }
+
+ if(isLast)
+ {
+ return list;
+ }
}
- s += convertIdent(n.image);
- if ("inherit".equals(s)) {
- result = LexicalUnitImpl.createInherit(n.beginLine,
- n.beginColumn, prev);
- } else {
- result = LexicalUnitImpl.createIdent(n.beginLine,
- n.beginColumn, prev, convertIdent(n.image));
+ else if(t.kind == STRING)
+ {
+ list += s.substring(1,s.length()).substring(0,s.length()-2);
+
+ }else if(t.kind == LPARAN)
+ {
+ nesting++;
+ if(nesting > nest+1)
+ {
+ throw new CSSParseException("Only one ( ) pair per parameter allowed", getLocator());
+ }
+ }else if(t.kind == RPARAN)
+ {
+ nesting--;
+ if(nesting == 0)
+ {
+ return list;
+ }
+ } else if(t.kind == COMMA)
+ {
+ if(nesting == nest)
+ {
+ return list;
+ }else
+ {
+ list += ",";
+ }
+
+ }else if(t.kind == S)
+ {
+ list += " ";
+ } else if(t.kind == LBRACE)
+ {
+ throw new CSSParseException("Invalid token,'{' found", getLocator());
}
- /*
- * / Auto correction code used in the CSS Validator but must not
- * be used by a conformant CSS2 parser. Common error : H1 {
- * color : black background : white }
- *
- * Token t = getToken(1); Token semicolon = new Token();
- * semicolon.kind = SEMICOLON; semicolon.image = ";"; if (t.kind
- * == COLON) { // @@SEEME. (generate a warning?) // @@SEEME if
- * expression is a single ident, generate an error ?
- * rejectToken(semicolon);
- *
- * result = prev; } /
- */
+ getNextToken();
+ }
+ }
+
+ final public Node returnDirective() throws ParseException {
+ String raw;
+ raw = skipStatement();
+ {if (true) return null;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void debuggingDirective() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case DEBUG_SYM:
+ debugDirective();
+ break;
+ case WARN_SYM:
+ warnDirective();
+ break;
+ default:
+ jj_la1[197] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ }
+
+ final public void debugDirective() throws ParseException {
+ jj_consume_token(DEBUG_SYM);
+ String content = skipStatementUntilSemiColon();
+ // TODO should evaluate the content expression, call documentHandler.debugDirective() etc.
+ System.out.println(content);
+ label_137:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[198] = jj_gen;
+ break label_137;
+ }
+ jj_consume_token(S);
+ }
+ }
+
+ final public void warnDirective() throws ParseException {
+ jj_consume_token(WARN_SYM);
+ String content = skipStatementUntilSemiColon();
+ // TODO should evaluate the content expression, call documentHandler.warnDirective() etc.
+ System.err.println(content);
+ label_138:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[199] = jj_gen;
+ break label_138;
+ }
+ jj_consume_token(S);
+ }
+ }
+
+ final public Node forDirective() throws ParseException {
+ String var;
+ String from;
+ String to;
+ boolean exclusive;
+ String body;
+ Token tok;
+ var = variableName();
+ int[] toThrough = {TO, THROUGH};
+ from = skipStatementUntil(toThrough);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case TO:
+ tok = jj_consume_token(TO);
+ exclusive = true;
+ break;
+ case THROUGH:
+ tok = jj_consume_token(THROUGH);
+ exclusive = false;
+ break;
+ default:
+ jj_la1[200] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ to = skipStatementUntilLeftBrace();
+ label_139:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[201] = jj_gen;
+ break label_139;
+ }
+ jj_consume_token(S);
+ }
+ body = skipStatement();
+ {if (true) return documentHandler.forDirective(var, from, to, exclusive, body);}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public Node whileDirective() throws ParseException {
+ String condition;
+ String body;
+ condition = skipStatementUntilLeftBrace();
+ body = skipStatement();
+ {if (true) return documentHandler.whileDirective(condition, body);}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public void extendDirective() throws ParseException {
+ ArrayList<String> list;
+ jj_consume_token(EXTEND_SYM);
+ label_140:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[202] = jj_gen;
+ break label_140;
+ }
+ jj_consume_token(S);
+ }
+ list = selectorList();
+ label_141:
+ while (true) {
+ jj_consume_token(SEMICOLON);
+ label_142:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[203] = jj_gen;
+ break label_142;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[204] = jj_gen;
+ break label_141;
+ }
+ }
+ documentHandler.extendDirective(list);
+ }
+
+ final public void contentDirective() throws ParseException {
+ jj_consume_token(CONTENT_SYM);
+ label_143:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[205] = jj_gen;
+ break label_143;
+ }
+ jj_consume_token(S);
+ }
+ label_144:
+ while (true) {
+ jj_consume_token(SEMICOLON);
+ label_145:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[206] = jj_gen;
+ break label_145;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[207] = jj_gen;
+ break label_144;
+ }
+ }
+ documentHandler.contentDirective();
+ }
+
+ Node importDirective() throws ParseException {
+ return null;
+ }
+
+ Node charsetDirective() throws ParseException {
+ return null;
+ }
+
+ Node mozDocumentDirective() throws ParseException {
+ return null;
+ }
+
+ Node supportsDirective() throws ParseException {
+ return null;
+ }
+
+ final public void nestedProperties() throws ParseException {
+ String name;
+LexicalUnit exp;
+ name = property();
+ jj_consume_token(COLON);
+ label_146:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[208] = jj_gen;
+ break label_146;
+ }
+ jj_consume_token(S);
+ }
+ jj_consume_token(LBRACE);
+ label_147:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[209] = jj_gen;
+ break label_147;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.startNestedProperties(name);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[210] = jj_gen;
+ ;
+ }
+ label_148:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[211] = jj_gen;
+ break label_148;
+ }
+ jj_consume_token(SEMICOLON);
+ label_149:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[212] = jj_gen;
+ break label_149;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[213] = jj_gen;
+ ;
+ }
+ }
+ jj_consume_token(RBRACE);
+ documentHandler.endNestedProperties(name);
+ label_150:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[214] = jj_gen;
+ break label_150;
+ }
+ jj_consume_token(S);
+ }
+ }
- break;
- case HASH:
- result = hexcolor(prev);
- break;
- case URL:
- result = url(prev);
- break;
- case UNICODERANGE:
- result = unicode(prev);
- break;
- default:
- jj_la1[233] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void styleRuleOrDeclarationOrNestedProperties() throws ParseException {
+ try {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case DEBUG_SYM:
+ case WARN_SYM:
+ debuggingDirective();
+ break;
+ default:
+ jj_la1[215] = jj_gen;
+ if (jj_2_6(2147483647)) {
+ styleRule();
+ } else if (jj_2_7(3)) {
+ declarationOrNestedProperties();
+ } else {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case IDENT:
+ case HASH:
+ styleRule();
break;
- default:
- jj_la1[234] = jj_gen;
+ default:
+ jj_la1[216] = jj_gen;
jj_consume_token(-1);
throw new ParseException();
+ }
+ }
+ }
+ } catch (JumpException e) {
+ skipAfterExpression();
+ // reportWarningSkipText(getLocator(), skipAfterExpression());
+
+ } catch (ParseException e) {
+ if (errorHandler != null) {
+ if (e.currentToken != null) {
+ LocatorImpl li = new LocatorImpl(this,
+ e.currentToken.next.beginLine,
+ e.currentToken.next.beginColumn-1);
+ reportError(li, e);
+ } else {
+ reportError(getLocator(), e);
+ }
+ skipAfterExpression();
+ /*
+ LocatorImpl loc = (LocatorImpl) getLocator();
+ loc.column--;
+ reportWarningSkipText(loc, skipAfterExpression());
+ */
+ } else {
+ skipAfterExpression();
+ }
+ }
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void declarationOrNestedProperties() throws ParseException {
+ boolean important = false;
+ String name;
+ LexicalUnitImpl exp;
+ Token save;
+ String comment = null;
+ try {
+ name = property();
+ save = token;
+ jj_consume_token(COLON);
+ label_151:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[217] = jj_gen;
+ break label_151;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case MINUS:
+ case DOT:
+ case TO:
+ case THROUGH:
+ case FROM:
+ case STRING:
+ case IDENT:
+ case NUMBER:
+ case URL:
+ case VARIABLE:
+ case PERCENTAGE:
+ case PT:
+ case MM:
+ case CM:
+ case PC:
+ case IN:
+ case PX:
+ case EMS:
+ case LEM:
+ case REM:
+ case EXS:
+ case DEG:
+ case RAD:
+ case GRAD:
+ case MS:
+ case SECOND:
+ case HZ:
+ case KHZ:
+ case DIMEN:
+ case HASH:
+ case UNICODERANGE:
+ case FUNCTION:
+ exp = expr();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IMPORTANT_SYM:
+ important = prio();
+ break;
+ default:
+ jj_la1[218] = jj_gen;
+ ;
+ }
+ Token next = getToken(1);
+ if(next.kind == SEMICOLON || next.kind == RBRACE){
+ while(next.kind == SEMICOLON){
+ skipStatement();
+ next = getToken(1);
+ }
+ if(token.specialToken!=null){
+ documentHandler.property(name, exp, important, token.specialToken.image);
+ }else{
+ documentHandler.property(name, exp, important, null);
+ }
+ }
+ break;
+ case LBRACE:
+ jj_consume_token(LBRACE);
+ label_152:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[219] = jj_gen;
+ break label_152;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.startNestedProperties(name);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[220] = jj_gen;
+ ;
}
- label_156: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
+ label_153:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[221] = jj_gen;
+ break label_153;
+ }
+ jj_consume_token(SEMICOLON);
+ label_154:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case S:
- ;
- break;
+ ;
+ break;
default:
- jj_la1[235] = jj_gen;
- break label_156;
+ jj_la1[222] = jj_gen;
+ break label_154;
}
jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[223] = jj_gen;
+ ;
+ }
}
- {
- if (true) {
- return result;
- }
- }
- throw new Error("Missing return statement in function");
+ jj_consume_token(RBRACE);
+ label_155:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[224] = jj_gen;
+ break label_155;
+ }
+ jj_consume_token(S);
+ }
+ documentHandler.endNestedProperties(name);
+ break;
+ default:
+ jj_la1[225] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ } catch (JumpException e) {
+ skipAfterExpression();
+ // reportWarningSkipText(getLocator(), skipAfterExpression());
+
+ } catch (NumberFormatException e) {
+ if (errorHandler != null) {
+ errorHandler.error(new CSSParseException("Invalid number "
+ + e.getMessage(),
+ getLocator(),
+ e));
+ }
+ reportWarningSkipText(getLocator(), skipAfterExpression());
+ } catch (ParseException e) {
+ if (errorHandler != null) {
+ if (e.currentToken != null) {
+ LocatorImpl li = new LocatorImpl(this,
+ e.currentToken.next.beginLine,
+ e.currentToken.next.beginColumn-1);
+ reportError(li, e);
+ } else {
+ reportError(getLocator(), e);
+ }
+ skipAfterExpression();
+ /*
+ LocatorImpl loc = (LocatorImpl) getLocator();
+ loc.column--;
+ reportWarningSkipText(loc, skipAfterExpression());
+ */
+ } else {
+ skipAfterExpression();
+ }
}
+ }
- /**
- * Handle all CSS2 functions.
- *
- * @exception ParseException
- * exception during the parse
- */
- final public LexicalUnitImpl function(char operator, LexicalUnitImpl prev)
- throws ParseException {
- Token n;
- LexicalUnit params = null;
- n = jj_consume_token(FUNCTION);
- label_157: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[236] = jj_gen;
- break label_157;
- }
- jj_consume_token(S);
- }
- String fname = convertIdent(n.image);
- if ("alpha(".equals(fname)) {
- String body = skipStatementUntilSemiColon();
- {
- if (true) {
- return LexicalUnitImpl.createIdent(n.beginLine,
- n.beginColumn, null, "alpha(" + body);
- }
- }
- } else if ("expression(".equals(fname)) {
- String body = skipStatementUntilSemiColon();
- {
- if (true) {
- return LexicalUnitImpl.createIdent(n.beginLine,
- n.beginColumn, null, "expression(" + body);
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public void declaration() throws ParseException {
+ boolean important = false;
+ String name;
+ LexicalUnit exp;
+ Token save;
+ try {
+ name = property();
+ save = token;
+ jj_consume_token(COLON);
+ label_156:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[226] = jj_gen;
+ break label_156;
+ }
+ jj_consume_token(S);
+ }
+ exp = expr();
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IMPORTANT_SYM:
+ important = prio();
+ break;
+ default:
+ jj_la1[227] = jj_gen;
+ ;
+ }
+ documentHandler.property(name, exp, important);
+ } catch (JumpException e) {
+ skipAfterExpression();
+ // reportWarningSkipText(getLocator(), skipAfterExpression());
+
+ } catch (NumberFormatException e) {
+ if (errorHandler != null) {
+ errorHandler.error(new CSSParseException("Invalid number "
+ + e.getMessage(),
+ getLocator(),
+ e));
+ }
+ reportWarningSkipText(getLocator(), skipAfterExpression());
+ } catch (ParseException e) {
+ if (errorHandler != null) {
+ if (e.currentToken != null) {
+ LocatorImpl li = new LocatorImpl(this,
+ e.currentToken.next.beginLine,
+ e.currentToken.next.beginColumn-1);
+ reportError(li, e);
+ } else {
+ reportError(getLocator(), e);
+ }
+ skipAfterExpression();
+ /*
+ LocatorImpl loc = (LocatorImpl) getLocator();
+ loc.column--;
+ reportWarningSkipText(loc, skipAfterExpression());
+ */
+ } else {
+ skipAfterExpression();
+ }
+ }
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public boolean prio() throws ParseException {
+ jj_consume_token(IMPORTANT_SYM);
+ label_157:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[228] = jj_gen;
+ break label_157;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return true;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public boolean guarded() throws ParseException {
+ jj_consume_token(GUARDED_SYM);
+ label_158:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[229] = jj_gen;
+ break label_158;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return true;}
+ throw new Error("Missing return statement in function");
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public LexicalUnitImpl operator(LexicalUnitImpl prev) throws ParseException {
+ Token n;
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case COMMA:
+ /* (comments copied from basic_arithmetics.scss)
+ *supports:
+ * 1. standard arithmetic operations (+, -, *, /, %)
+ * 2. / is treated as css operator, unless one of its operands is variable or there is another binary arithmetic operator
+ *limits:
+ * 1. cannot mix arithmetic and css operations, e.g. "margin: 1px + 3px 2px" will fail
+ * 2. space between add and minus operator and their following operand is mandatory. e.g. "1 + 2" is valid, "1+2" is not
+ * 3. parenthesis is not supported now.
+ */
+ n = jj_consume_token(COMMA);
+ label_159:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[230] = jj_gen;
+ break label_159;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return LexicalUnitImpl.createComma(n.beginLine,
+ n.beginColumn,
+ prev);}
+ break;
+ case DIV:
+ n = jj_consume_token(DIV);
+ label_160:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[231] = jj_gen;
+ break label_160;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return LexicalUnitImpl.createSlash(n.beginLine,
+ n.beginColumn,
+ prev);}
+ break;
+ case ANY:
+ n = jj_consume_token(ANY);
+ label_161:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[232] = jj_gen;
+ break label_161;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return LexicalUnitImpl.createMultiply(n.beginLine,
+ n.beginColumn,
+ prev);}
+ break;
+ case MOD:
+ n = jj_consume_token(MOD);
+ label_162:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[233] = jj_gen;
+ break label_162;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return LexicalUnitImpl.createModulo(n.beginLine,
+ n.beginColumn,
+ prev);}
+ break;
+ case PLUS:
+ n = jj_consume_token(PLUS);
+ label_163:
+ while (true) {
+ jj_consume_token(S);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[234] = jj_gen;
+ break label_163;
+ }
+ }
+ {if (true) return LexicalUnitImpl.createAdd(n.beginLine,
+ n.beginColumn,
+ prev);}
+ break;
+ case MINUS:
+ n = jj_consume_token(MINUS);
+ label_164:
+ while (true) {
+ jj_consume_token(S);
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[235] = jj_gen;
+ break label_164;
+ }
+ }
+ {if (true) return LexicalUnitImpl.createMinus(n.beginLine,
+ n.beginColumn,
+ prev);}
+ break;
+ default:
+ jj_la1[236] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public LexicalUnitImpl expr() throws ParseException {
+ LexicalUnitImpl first, res;
+ char op;
+ first = term(null);
+ res = first;
+ label_165:
+ while (true) {
+ if (jj_2_8(2)) {
+ ;
+ } else {
+ break label_165;
+ }
+ if (jj_2_9(2)) {
+ res = operator(res);
+ } else {
+ ;
+ }
+ res = term(res);
+ }
+ {if (true) return first;}
+ throw new Error("Missing return statement in function");
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public char unaryOperator() throws ParseException {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case MINUS:
+ jj_consume_token(MINUS);
+ {if (true) return '-';}
+ break;
+ case PLUS:
+ jj_consume_token(PLUS);
+ {if (true) return '+';}
+ break;
+ default:
+ jj_la1[237] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public LexicalUnitImpl term(LexicalUnitImpl prev) throws ParseException {
+ LexicalUnitImpl result = null;
+ Token n = null;
+ char op = ' ';
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case MINUS:
+ case DOT:
+ case TO:
+ case THROUGH:
+ case FROM:
+ case STRING:
+ case IDENT:
+ case NUMBER:
+ case URL:
+ case PERCENTAGE:
+ case PT:
+ case MM:
+ case CM:
+ case PC:
+ case IN:
+ case PX:
+ case EMS:
+ case LEM:
+ case REM:
+ case EXS:
+ case DEG:
+ case RAD:
+ case GRAD:
+ case MS:
+ case SECOND:
+ case HZ:
+ case KHZ:
+ case DIMEN:
+ case HASH:
+ case UNICODERANGE:
+ case FUNCTION:
+ result = nonVariableTerm(prev);
+ break;
+ case VARIABLE:
+ result = variableTerm(prev);
+ break;
+ default:
+ jj_la1[238] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ {if (true) return result;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public LexicalUnitImpl variableTerm(LexicalUnitImpl prev) throws ParseException {
+ LexicalUnitImpl result = null;
+ String varName = "";
+ varName = variableName();
+ result = LexicalUnitImpl.createVariable(token.beginLine, token.beginColumn,
+ prev, varName); {if (true) return result;}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public LexicalUnitImpl nonVariableTerm(LexicalUnitImpl prev) throws ParseException {
+LexicalUnitImpl result = null;
+ Token n = null;
+ char op = ' ';
+ String varName;
+ String s = "";
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case MINUS:
+ case NUMBER:
+ case PERCENTAGE:
+ case PT:
+ case MM:
+ case CM:
+ case PC:
+ case IN:
+ case PX:
+ case EMS:
+ case LEM:
+ case REM:
+ case EXS:
+ case DEG:
+ case RAD:
+ case GRAD:
+ case MS:
+ case SECOND:
+ case HZ:
+ case KHZ:
+ case DIMEN:
+ case FUNCTION:
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case MINUS:
+ op = unaryOperator();
+ break;
+ default:
+ jj_la1[239] = jj_gen;
+ ;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case NUMBER:
+ n = jj_consume_token(NUMBER);
+ result = LexicalUnitImpl.createNumber(n.beginLine, n.beginColumn,
+ prev, number(op, n, 0));
+ break;
+ case PERCENTAGE:
+ n = jj_consume_token(PERCENTAGE);
+ result = LexicalUnitImpl.createPercentage(n.beginLine, n.beginColumn,
+ prev, number(op, n, 1));
+ break;
+ case PT:
+ n = jj_consume_token(PT);
+ result = LexicalUnitImpl.createPT(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case CM:
+ n = jj_consume_token(CM);
+ result = LexicalUnitImpl.createCM(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case MM:
+ n = jj_consume_token(MM);
+ result = LexicalUnitImpl.createMM(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case PC:
+ n = jj_consume_token(PC);
+ result = LexicalUnitImpl.createPC(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case IN:
+ n = jj_consume_token(IN);
+ result = LexicalUnitImpl.createIN(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case PX:
+ n = jj_consume_token(PX);
+ result = LexicalUnitImpl.createPX(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case EMS:
+ n = jj_consume_token(EMS);
+ result = LexicalUnitImpl.createEMS(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case LEM:
+ n = jj_consume_token(LEM);
+ result = LexicalUnitImpl.createLEM(n.beginLine, n.beginColumn,
+ prev, number(op, n, 3));
+ break;
+ case REM:
+ n = jj_consume_token(REM);
+ result = LexicalUnitImpl.createREM(n.beginLine, n.beginColumn,
+ prev, number(op, n, 3));
+ break;
+ case EXS:
+ n = jj_consume_token(EXS);
+ result = LexicalUnitImpl.createEXS(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case DEG:
+ n = jj_consume_token(DEG);
+ result = LexicalUnitImpl.createDEG(n.beginLine, n.beginColumn,
+ prev, number(op, n, 3));
+ break;
+ case RAD:
+ n = jj_consume_token(RAD);
+ result = LexicalUnitImpl.createRAD(n.beginLine, n.beginColumn,
+ prev, number(op, n, 3));
+ break;
+ case GRAD:
+ n = jj_consume_token(GRAD);
+ result = LexicalUnitImpl.createGRAD(n.beginLine, n.beginColumn,
+ prev, number(op, n, 3));
+ break;
+ case SECOND:
+ n = jj_consume_token(SECOND);
+ result = LexicalUnitImpl.createS(n.beginLine, n.beginColumn,
+ prev, number(op, n, 1));
+ break;
+ case MS:
+ n = jj_consume_token(MS);
+ result = LexicalUnitImpl.createMS(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case HZ:
+ n = jj_consume_token(HZ);
+ result = LexicalUnitImpl.createHZ(n.beginLine, n.beginColumn,
+ prev, number(op, n, 2));
+ break;
+ case KHZ:
+ n = jj_consume_token(KHZ);
+ result = LexicalUnitImpl.createKHZ(n.beginLine, n.beginColumn,
+ prev, number(op, n, 3));
+ break;
+ case DIMEN:
+ n = jj_consume_token(DIMEN);
+ s = n.image;
+ int i = 0;
+ while (i < s.length()
+ && (Character.isDigit(s.charAt(i)) || (s.charAt(i) == '.'))) {
+ i++;
}
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case PLUS:
- case MINUS:
+ result = LexicalUnitImpl.createDimen(n.beginLine, n.beginColumn, prev,
+ Float.valueOf(s.substring(0, i)).floatValue(),
+ s.substring(i));
+ break;
+ case FUNCTION:
+ result = function(op, prev);
+ break;
+ default:
+ jj_la1[240] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ case DOT:
+ case TO:
+ case THROUGH:
+ case FROM:
+ case STRING:
+ case IDENT:
+ case URL:
+ case HASH:
+ case UNICODERANGE:
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case STRING:
+ n = jj_consume_token(STRING);
+ result =
+ LexicalUnitImpl.createString(n.beginLine, n.beginColumn, prev,
+ convertStringIndex(n.image, 1,
+ n.image.length() -1));
+ break;
+ case DOT:
+ case TO:
+ case THROUGH:
+ case FROM:
+ case IDENT:
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
case DOT:
+ jj_consume_token(DOT);
+ s+=".";
+ break;
+ default:
+ jj_la1[241] = jj_gen;
+ ;
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IDENT:
+ n = jj_consume_token(IDENT);
+ break;
case TO:
+ n = jj_consume_token(TO);
+ break;
case THROUGH:
+ n = jj_consume_token(THROUGH);
+ break;
case FROM:
- case STRING:
- case IDENT:
- case NUMBER:
- case URL:
- case VARIABLE:
- case PERCENTAGE:
- case PT:
- case MM:
- case CM:
- case PC:
- case IN:
- case PX:
- case EMS:
- case LEM:
- case REM:
- case EXS:
- case DEG:
- case RAD:
- case GRAD:
- case MS:
- case SECOND:
- case HZ:
- case KHZ:
- case DIMEN:
- case HASH:
- case UNICODERANGE:
- case FUNCTION:
- params = expr();
- break;
+ n = jj_consume_token(FROM);
+ break;
default:
- jj_la1[237] = jj_gen;
- ;
- }
- jj_consume_token(RPARAN);
+ jj_la1[242] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ s += convertIdent(n.image);
+ if ("inherit".equals(s)) {
+ result = LexicalUnitImpl.createInherit(n.beginLine, n.beginColumn,
+ prev);
+ } else {
+ result = LexicalUnitImpl.createIdent(n.beginLine, n.beginColumn,
+ prev, convertIdent(n.image));
+ }
+
+ /* /
+ Auto correction code used in the CSS Validator but must not
+ be used by a conformant CSS2 parser.
+ * Common error :
+ * H1 {
+ * color : black
+ * background : white
+ * }
+ *
+ Token t = getToken(1);
+ Token semicolon = new Token();
+ semicolon.kind = SEMICOLON;
+ semicolon.image = ";";
+ if (t.kind == COLON) {
+ // @@SEEME. (generate a warning?)
+ // @@SEEME if expression is a single ident,
+ generate an error ?
+ rejectToken(semicolon);
+
+ result = prev;
+ }
+ / */
+
+ break;
+ case HASH:
+ result = hexcolor(prev);
+ break;
+ case URL:
+ result = url(prev);
+ break;
+ case UNICODERANGE:
+ result = unicode(prev);
+ break;
+ default:
+ jj_la1[243] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ break;
+ default:
+ jj_la1[244] = jj_gen;
+ jj_consume_token(-1);
+ throw new ParseException();
+ }
+ label_166:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[245] = jj_gen;
+ break label_166;
+ }
+ jj_consume_token(S);
+ }
+ {if (true) return result;}
+ throw new Error("Missing return statement in function");
+ }
+
+/**
+ * Handle all CSS2 functions.
+ * @exception ParseException exception during the parse
+ */
+ final public LexicalUnitImpl function(char operator, LexicalUnitImpl prev) throws ParseException {
+ Token n;
+ LexicalUnit params = null;
+ n = jj_consume_token(FUNCTION);
+ label_167:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[246] = jj_gen;
+ break label_167;
+ }
+ jj_consume_token(S);
+ }
+ String fname = convertIdent(n.image);
+ if("alpha(".equals(fname)){
+ String body = skipStatementUntilSemiColon();
+ {if (true) return LexicalUnitImpl.createIdent(n.beginLine, n.beginColumn,
+ null, "alpha("+body);}
+ }else if("expression(".equals(fname)){
+ String body = skipStatementUntilSemiColon();
+ {if (true) return LexicalUnitImpl.createIdent(n.beginLine, n.beginColumn,
+ null, "expression("+body);}
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case PLUS:
+ case MINUS:
+ case DOT:
+ case TO:
+ case THROUGH:
+ case FROM:
+ case STRING:
+ case IDENT:
+ case NUMBER:
+ case URL:
+ case VARIABLE:
+ case PERCENTAGE:
+ case PT:
+ case MM:
+ case CM:
+ case PC:
+ case IN:
+ case PX:
+ case EMS:
+ case LEM:
+ case REM:
+ case EXS:
+ case DEG:
+ case RAD:
+ case GRAD:
+ case MS:
+ case SECOND:
+ case HZ:
+ case KHZ:
+ case DIMEN:
+ case HASH:
+ case UNICODERANGE:
+ case FUNCTION:
+ params = expr();
+ break;
+ default:
+ jj_la1[247] = jj_gen;
+ ;
+ }
+ jj_consume_token(RPARAN);
if (operator != ' ') {
- {
- if (true) {
- throw new CSSParseException(
- "invalid operator before a function.", getLocator());
- }
- }
+ {if (true) throw new CSSParseException("invalid operator before a function.",
+ getLocator());}
}
String f = convertIdent(n.image);
LexicalUnitImpl l = (LexicalUnitImpl) params;
@@ -5565,38 +5643,32 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
int i = 0;
while (loop && l != null && i < 5) {
switch (i) {
- case 0:
- case 2:
- case 4:
- if ((l.getLexicalUnitType() != LexicalUnit.SAC_INTEGER)
+ case 0:
+ case 2:
+ case 4:
+ if ((l.getLexicalUnitType() != LexicalUnit.SAC_INTEGER)
&& (l.getLexicalUnitType() != LexicalUnit.SAC_PERCENTAGE)) {
- loop = false;
- }
- break;
- case 1:
- case 3:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
- loop = false;
- }
- break;
- default: {
- if (true) {
- throw new ParseException("implementation error");
- }
- }
+ loop = false;
+ }
+ break;
+ case 1:
+ case 3:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
+ loop = false;
+ }
+ break;
+ default:
+ {if (true) throw new ParseException("implementation error");}
}
if (loop) {
- l = l.getNextLexicalUnit();
- i++;
+ l = (LexicalUnitImpl) l.getNextLexicalUnit();
+ i ++;
}
}
if ((i == 5) && loop && (l == null)) {
- {
- if (true) {
- return LexicalUnitImpl.createRGBColor(n.beginLine,
- n.beginColumn, prev, params);
- }
- }
+ {if (true) return LexicalUnitImpl.createRGBColor(n.beginLine,
+ n.beginColumn,
+ prev, params);}
} else {
if (errorHandler != null) {
String errorText;
@@ -5604,63 +5676,54 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
if (i < 5) {
if (params == null) {
loc = new LocatorImpl(this, n.beginLine,
- n.beginColumn - 1);
+ n.beginColumn-1);
errorText = "not enough parameters.";
} else if (l == null) {
loc = new LocatorImpl(this, n.beginLine,
- n.beginColumn - 1);
+ n.beginColumn-1);
errorText = "not enough parameters: "
- + params.toString();
+ + params.toString();
} else {
loc = new LocatorImpl(this, l.getLineNumber(),
- l.getColumnNumber());
- errorText = "invalid parameter: " + l.toString();
+ l.getColumnNumber());
+ errorText = "invalid parameter: "
+ + l.toString();
}
} else {
loc = new LocatorImpl(this, l.getLineNumber(),
- l.getColumnNumber());
- errorText = "too many parameters: " + l.toString();
+ l.getColumnNumber());
+ errorText = "too many parameters: "
+ + l.toString();
}
errorHandler.error(new CSSParseException(errorText, loc));
}
- {
- if (true) {
- throw new JumpException();
- }
- }
+ {if (true) throw new JumpException();}
}
} else if ("counter".equals(f)) {
int i = 0;
while (loop && l != null && i < 3) {
switch (i) {
- case 0:
- case 2:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_IDENT) {
- loop = false;
- }
- break;
- case 1:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
- loop = false;
- }
- break;
- default: {
- if (true) {
- throw new ParseException("implementation error");
- }
- }
+ case 0:
+ case 2:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_IDENT) {
+ loop = false;
+ }
+ break;
+ case 1:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
+ loop = false;
+ }
+ break;
+ default:
+ {if (true) throw new ParseException("implementation error");}
}
- l = l.getNextLexicalUnit();
- i++;
+ l = (LexicalUnitImpl) l.getNextLexicalUnit();
+ i ++;
}
if (((i == 1) || (i == 3)) && loop && (l == null)) {
- {
- if (true) {
- return LexicalUnitImpl.createCounter(n.beginLine,
- n.beginColumn, prev, params);
- }
- }
+ {if (true) return LexicalUnitImpl.createCounter(n.beginLine, n.beginColumn,
+ prev, params);}
}
} else if ("counters(".equals(f)) {
@@ -5668,2703 +5731,2047 @@ public class Parser implements org.w3c.css.sac.Parser, ParserConstants {
int i = 0;
while (loop && l != null && i < 5) {
switch (i) {
- case 0:
- case 4:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_IDENT) {
- loop = false;
- }
- break;
- case 2:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_STRING_VALUE) {
- loop = false;
- }
- break;
- case 1:
- case 3:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
- loop = false;
- }
- break;
- default: {
- if (true) {
- throw new ParseException("implementation error");
- }
- }
+ case 0:
+ case 4:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_IDENT) {
+ loop = false;
+ }
+ break;
+ case 2:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_STRING_VALUE) {
+ loop = false;
+ }
+ break;
+ case 1:
+ case 3:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
+ loop = false;
+ }
+ break;
+ default:
+ {if (true) throw new ParseException("implementation error");}
}
- l = l.getNextLexicalUnit();
- i++;
+ l = (LexicalUnitImpl) l.getNextLexicalUnit();
+ i ++;
}
if (((i == 3) || (i == 5)) && loop && (l == null)) {
- {
- if (true) {
- return LexicalUnitImpl.createCounters(n.beginLine,
- n.beginColumn, prev, params);
- }
- }
+ {if (true) return LexicalUnitImpl.createCounters(n.beginLine, n.beginColumn,
+ prev, params);}
}
} else if ("attr(".equals(f)) {
- if ((l != null) && (l.getNextLexicalUnit() == null)
- && (l.getLexicalUnitType() == LexicalUnit.SAC_IDENT)) {
- {
- if (true) {
- return LexicalUnitImpl.createAttr(l.getLineNumber(),
- l.getColumnNumber(), prev, l.getStringValue());
- }
- }
+ if ((l != null)
+ && (l.getNextLexicalUnit() == null)
+ && (l.getLexicalUnitType() == LexicalUnit.SAC_IDENT)) {
+ {if (true) return LexicalUnitImpl.createAttr(l.getLineNumber(),
+ l.getColumnNumber(),
+ prev, l.getStringValue());}
}
} else if ("rect(".equals(f)) {
int i = 0;
while (loop && l != null && i < 7) {
switch (i) {
- case 0:
- case 2:
- case 4:
- case 6:
- switch (l.getLexicalUnitType()) {
- case LexicalUnit.SAC_INTEGER:
- if (l.getIntegerValue() != 0) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ switch (l.getLexicalUnitType()) {
+ case LexicalUnit.SAC_INTEGER:
+ if (l.getIntegerValue() != 0) {
+ loop = false;
+ }
+ break;
+ case LexicalUnit.SAC_IDENT:
+ if (!l.getStringValue().equals("auto")) {
+ loop = false;
+ }
+ break;
+ case LexicalUnit.SAC_EM:
+ case LexicalUnit.SAC_EX:
+ case LexicalUnit.SAC_PIXEL:
+ case LexicalUnit.SAC_CENTIMETER:
+ case LexicalUnit.SAC_MILLIMETER:
+ case LexicalUnit.SAC_INCH:
+ case LexicalUnit.SAC_POINT:
+ case LexicalUnit.SAC_PICA:
+ // nothing
+ break;
+ default:
loop = false;
}
break;
- case LexicalUnit.SAC_IDENT:
- if (!l.getStringValue().equals("auto")) {
+ case 1:
+ case 3:
+ case 5:
+ if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
loop = false;
}
break;
- case LexicalUnit.SAC_EM:
- case LexicalUnit.SAC_EX:
- case LexicalUnit.SAC_PIXEL:
- case LexicalUnit.SAC_CENTIMETER:
- case LexicalUnit.SAC_MILLIMETER:
- case LexicalUnit.SAC_INCH:
- case LexicalUnit.SAC_POINT:
- case LexicalUnit.SAC_PICA:
- // nothing
- break;
default:
- loop = false;
- }
- break;
- case 1:
- case 3:
- case 5:
- if (l.getLexicalUnitType() != LexicalUnit.SAC_OPERATOR_COMMA) {
- loop = false;
- }
- break;
- default: {
- if (true) {
- throw new ParseException("implementation error");
- }
+ {if (true) throw new ParseException("implementation error");}
}
- }
- l = l.getNextLexicalUnit();
- i++;
+ l = (LexicalUnitImpl) l.getNextLexicalUnit();
+ i ++;
}
if ((i == 7) && loop && (l == null)) {
- {
- if (true) {
- return LexicalUnitImpl.createRect(n.beginLine,
- n.beginColumn, prev, params);
- }
- }
- }
- }
- {
- if (true) {
- return LexicalUnitImpl.createFunction(n.beginLine,
- n.beginColumn, prev, f.substring(0, f.length() - 1),
- params);
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public LexicalUnitImpl unicode(LexicalUnitImpl prev)
- throws ParseException {
- Token n;
- n = jj_consume_token(UNICODERANGE);
- LexicalUnitImpl params = null;
- String s = n.image.substring(2);
- int index = s.indexOf('-');
- if (index == -1) {
- params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
- params, Integer.parseInt(s, 16));
- } else {
- String s1 = s.substring(0, index);
- String s2 = s.substring(index);
-
- params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
- params, Integer.parseInt(s1, 16));
- params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
- params, Integer.parseInt(s2, 16));
- }
-
- {
- if (true) {
- return LexicalUnitImpl.createUnicodeRange(n.beginLine,
- n.beginColumn, prev, params);
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- final public LexicalUnitImpl url(LexicalUnitImpl prev)
- throws ParseException {
- Token n;
- n = jj_consume_token(URL);
- String urlname = n.image.substring(4, n.image.length() - 1).trim();
- {
- if (true) {
- return LexicalUnitImpl.createURL(n.beginLine, n.beginColumn,
- prev, urlname);
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- /**
- * @exception ParseException
- * exception during the parse
- */
- final public LexicalUnitImpl hexcolor(LexicalUnitImpl prev)
- throws ParseException {
- Token n;
- n = jj_consume_token(HASH);
- int r;
- LexicalUnitImpl first, params = null;
- String s = n.image.substring(1);
-
- if (s.length() != 3 && s.length() != 6) {
- first = null;
- {
- if (true) {
- throw new CSSParseException(
- "invalid hexadecimal notation for RGB: " + s,
- getLocator());
- }
- }
- }
- {
- if (true) {
- return LexicalUnitImpl.createIdent(n.beginLine, n.beginColumn,
- prev, n.image);
- }
- }
- throw new Error("Missing return statement in function");
- }
+ {if (true) return LexicalUnitImpl.createRect(n.beginLine, n.beginColumn,
+ prev, params);}
+ }
+ }
+ {if (true) return LexicalUnitImpl.createFunction(n.beginLine, n.beginColumn, prev,
+ f.substring(0,
+ f.length() -1),
+ params);}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public LexicalUnitImpl unicode(LexicalUnitImpl prev) throws ParseException {
+ Token n;
+ n = jj_consume_token(UNICODERANGE);
+ LexicalUnitImpl params = null;
+ String s = n.image.substring(2);
+ int index = s.indexOf('-');
+ if (index == -1) {
+ params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
+ params, Integer.parseInt(s, 16));
+ } else {
+ String s1 = s.substring(0, index);
+ String s2 = s.substring(index);
+
+ params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
+ params, Integer.parseInt(s1, 16));
+ params = LexicalUnitImpl.createInteger(n.beginLine, n.beginColumn,
+ params, Integer.parseInt(s2, 16));
+ }
+
+ {if (true) return LexicalUnitImpl.createUnicodeRange(n.beginLine, n.beginColumn,
+ prev, params);}
+ throw new Error("Missing return statement in function");
+ }
+
+ final public LexicalUnitImpl url(LexicalUnitImpl prev) throws ParseException {
+ Token n;
+ n = jj_consume_token(URL);
+ String urlname = n.image.substring(4, n.image.length()-1).trim();
+ {if (true) return LexicalUnitImpl.createURL(n.beginLine, n.beginColumn, prev, urlname);}
+ throw new Error("Missing return statement in function");
+ }
- float number(char operator, Token n, int lengthUnit) throws ParseException {
- String image = n.image;
- float f = 0;
-
- if (lengthUnit != 0) {
- image = image.substring(0, image.length() - lengthUnit);
- }
- f = Float.valueOf(image).floatValue();
- return (operator == '-') ? -f : f;
- }
-
- String skipStatementUntilSemiColon() throws ParseException {
- int[] semicolon = { SEMICOLON };
- return skipStatementUntil(semicolon);
- }
-
- String skipStatementUntilLeftBrace() throws ParseException {
- int[] lBrace = { LBRACE };
- return skipStatementUntil(lBrace);
- }
-
- String skipStatementUntilRightParan() throws ParseException {
- int[] rParan = { RPARAN };
- return skipStatementUntil(rParan);
- }
-
- String skipStatementUntil(int[] symbols) throws ParseException {
- StringBuffer s = new StringBuffer();
- boolean stop = false;
- Token tok;
- while (!stop) {
- tok = getToken(1);
- if (tok.kind == EOF) {
- return null;
- }
- for (int sym : symbols) {
- if (tok.kind == sym) {
- stop = true;
- break;
- }
- }
- if (!stop) {
- if (tok.image != null) {
- s.append(tok.image);
- }
- getNextToken();
- }
- }
- return s.toString().trim();
- }
-
- String skipStatement() throws ParseException {
- StringBuffer s = new StringBuffer();
- Token tok = getToken(0);
- if (tok.image != null) {
- s.append(tok.image);
- }
- while (true) {
- tok = getToken(1);
- if (tok.kind == EOF) {
- return null;
- }
- s.append(tok.image);
- if (tok.kind == LBRACE) {
- getNextToken();
- s.append(skip_to_matching_brace());
- getNextToken();
- tok = getToken(1);
- break;
- } else if (tok.kind == RBRACE) {
- getNextToken();
- tok = getToken(1);
- break;
- } else if (tok.kind == SEMICOLON) {
- getNextToken();
- tok = getToken(1);
- break;
- }
- getNextToken();
- }
-
- // skip white space
- while (true) {
- if (tok.kind != S) {
- break;
- }
- tok = getNextToken();
- tok = getToken(1);
- }
-
- return s.toString().trim();
- }
-
- String skip_to_matching_brace() throws ParseException {
- StringBuffer s = new StringBuffer();
- Token tok;
- int nesting = 1;
- while (true) {
- tok = getToken(1);
- if (tok.kind == EOF) {
- break;
- }
- s.append(tok.image);
- if (tok.kind == LBRACE) {
- nesting++;
- } else if (tok.kind == RBRACE) {
- nesting--;
- if (nesting == 0) {
- break;
- }
+/**
+ * @exception ParseException exception during the parse
+ */
+ final public LexicalUnitImpl hexcolor(LexicalUnitImpl prev) throws ParseException {
+ Token n;
+ n = jj_consume_token(HASH);
+ int r;
+ LexicalUnitImpl first, params = null;
+ String s = n.image.substring(1);
+
+ if(s.length()!=3 && s.length()!=6) {
+ first = null;
+ {if (true) throw new CSSParseException("invalid hexadecimal notation for RGB: " + s,
+ getLocator());}
+ }
+ {if (true) return LexicalUnitImpl.createIdent(n.beginLine, n.beginColumn,
+ prev, n.image);}
+ throw new Error("Missing return statement in function");
+ }
+
+ float number(char operator, Token n, int lengthUnit) throws ParseException {
+ String image = n.image;
+ float f = 0;
+
+ if (lengthUnit != 0) {
+ image = image.substring(0, image.length() - lengthUnit);
+ }
+ f = Float.valueOf(image).floatValue();
+ return (operator == '-')? -f: f;
+ }
+
+ String skipStatementUntilSemiColon() throws ParseException {
+ int[] semicolon = {SEMICOLON};
+ return skipStatementUntil(semicolon);
+ }
+
+ String skipStatementUntilLeftBrace() throws ParseException {
+ int[] lBrace = {LBRACE};
+ return skipStatementUntil(lBrace);
+ }
+
+ String skipStatementUntilRightParan() throws ParseException {
+ int[] rParan = {RPARAN};
+ return skipStatementUntil(rParan);
+ }
+
+ String skipStatementUntil(int[] symbols) throws ParseException {
+ StringBuffer s = new StringBuffer();
+ boolean stop = false;
+ Token tok;
+ while(!stop){
+ tok = getToken(1);
+ if(tok.kind == EOF) {
+ return null;
+ }
+ for(int sym : symbols){
+ if(tok.kind == sym){
+ stop = true;
+ break;
+ }
+ }
+ if(!stop){
+ if (tok.image != null) {
+ s.append(tok.image);
}
getNextToken();
}
- return s.toString();
- }
-
- String convertStringIndex(String s, int start, int len)
- throws ParseException {
- StringBuffer buf = new StringBuffer(len);
- int index = start;
-
- while (index < len) {
- char c = s.charAt(index);
- if (c == '\u005c\u005c') {
- if (++index < len) {
- c = s.charAt(index);
- switch (c) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case 'a':
- case 'b':
- case 'c':
- case 'd':
- case 'e':
- case 'f':
- case 'A':
- case 'B':
- case 'C':
- case 'D':
- case 'E':
- case 'F':
- buf.append('\u005c\u005c');
- while (index < len) {
- buf.append(s.charAt(index++));
- }
- break;
- case '\u005cn':
- case '\u005cf':
- break;
- case '\u005cr':
- if (index + 1 < len) {
- if (s.charAt(index + 1) == '\u005cn') {
- index++;
- }
- }
- break;
- default:
- buf.append(c);
- }
- } else {
- throw new CSSParseException("invalid string " + s,
- getLocator());
- }
- } else {
- buf.append(c);
- }
- index++;
- }
-
- return buf.toString();
- }
-
- String convertIdent(String s) throws ParseException {
- return convertStringIndex(s, 0, s.length());
}
+ return s.toString().trim();
+ }
- String convertString(String s) throws ParseException {
- return convertStringIndex(s, 0, s.length());
+ String skipStatement() throws ParseException {
+ StringBuffer s = new StringBuffer();
+ Token tok = getToken(0);
+ if (tok.image != null) {
+ s.append(tok.image);
}
-
- void comments() throws ParseException {
- if (token.specialToken != null) {
- Token tmp_t = token.specialToken;
- while (tmp_t.specialToken != null) {
- tmp_t = tmp_t.specialToken;
- }
- while (tmp_t != null) {
- documentHandler.comment(tmp_t.image);
- tmp_t = tmp_t.next;
- }
+ while (true) {
+ tok = getToken(1);
+ if (tok.kind == EOF) {
+ return null;
}
- }
-
- void rejectToken(Token t) throws ParseException {
- Token fakeToken = new Token();
- t.next = token;
- fakeToken.next = t;
- token = fakeToken;
- }
-
- String skipAfterExpression() throws ParseException {
- Token t = getToken(1);
- StringBuffer s = new StringBuffer();
- s.append(getToken(0).image);
-
- while ((t.kind != RBRACE) && (t.kind != SEMICOLON) && (t.kind != EOF)) {
- s.append(t.image);
+ s.append(tok.image);
+ if (tok.kind == LBRACE) {
getNextToken();
- t = getToken(1);
- }
-
- return s.toString();
- }
-
- /**
- * The following functions are useful for a DOM CSS implementation only and
- * are not part of the general CSS2 parser.
- */
- final public void _parseRule() throws ParseException {
- String ret = null;
- label_158: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[238] = jj_gen;
- break label_158;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case IMPORT_SYM:
- importDeclaration();
- break;
- case DEBUG_SYM:
- case WARN_SYM:
- debuggingDirective();
- break;
- case PLUS:
- case PRECEDES:
- case SIBLING:
- case LBRACKET:
- case ANY:
- case PARENT:
- case DOT:
- case COLON:
- case INTERPOLATION:
- case IDENT:
- case HASH:
- styleRule();
- break;
- case MEDIA_SYM:
- media();
+ s.append(skip_to_matching_brace());
+ getNextToken();
+ tok = getToken(1);
break;
- case PAGE_SYM:
- page();
+ } else if (tok.kind == RBRACE) {
+ getNextToken();
+ tok = getToken(1);
break;
- case FONT_FACE_SYM:
- fontFace();
+ } else if (tok.kind == SEMICOLON) {
+ getNextToken();
+ tok = getToken(1);
break;
- default:
- jj_la1[239] = jj_gen;
- ret = skipStatement();
- if ((ret == null) || (ret.length() == 0)) {
- {
- if (true) {
- return;
- }
- }
- }
- if (ret.charAt(0) == '@') {
- documentHandler.unrecognizedRule(ret);
- } else {
- {
- if (true) {
- throw new CSSParseException("unrecognize rule: " + ret,
- getLocator());
- }
- }
- }
}
+ getNextToken();
}
- final public void _parseImportRule() throws ParseException {
- label_159: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[240] = jj_gen;
- break label_159;
- }
- jj_consume_token(S);
+ // skip white space
+ while (true) {
+ if (tok.kind != S) {
+ break;
}
- importDeclaration();
+ tok = getNextToken();
+ tok = getToken(1);
}
- final public void _parseMediaRule() throws ParseException {
- label_160: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[241] = jj_gen;
- break label_160;
- }
- jj_consume_token(S);
- }
- media();
- }
+ return s.toString().trim();
+ }
- final public void _parseDeclarationBlock() throws ParseException {
- label_161: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
- break;
- default:
- jj_la1[242] = jj_gen;
- break label_161;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
+ String skip_to_matching_brace() throws ParseException {
+ StringBuffer s = new StringBuffer();
+ Token tok;
+ int nesting = 1;
+ while (true) {
+ tok = getToken(1);
+ if (tok.kind == EOF) {
break;
- default:
- jj_la1[243] = jj_gen;
- ;
}
- label_162: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case SEMICOLON:
- ;
- break;
- default:
- jj_la1[244] = jj_gen;
- break label_162;
- }
- jj_consume_token(SEMICOLON);
- label_163: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
+ s.append(tok.image);
+ if (tok.kind == LBRACE) {
+ nesting++;
+ } else if (tok.kind == RBRACE) {
+ nesting--;
+ if (nesting == 0) {
+ break;
+ }
+ }
+ getNextToken();
+ }
+ return s.toString();
+ }
+
+ String convertStringIndex(String s, int start, int len) throws ParseException {
+ StringBuffer buf = new StringBuffer(len);
+ int index = start;
+
+ while (index < len) {
+ char c = s.charAt(index);
+ if (c == '\u005c\u005c') {
+ if (++index < len) {
+ c = s.charAt(index);
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+ buf.append('\u005c\u005c');
+ while (index < len) {
+ buf.append(s.charAt(index++));
+ }
break;
- default:
- jj_la1[245] = jj_gen;
- break label_163;
- }
- jj_consume_token(S);
- }
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case INTERPOLATION:
- case IDENT:
- declaration();
- break;
- default:
- jj_la1[246] = jj_gen;
- ;
- }
- }
- }
-
- final public ArrayList<String> _parseSelectors() throws ParseException {
- ArrayList<String> p = null;
- try {
- label_164: while (true) {
- switch ((jj_ntk == -1) ? jj_ntk() : jj_ntk) {
- case S:
- ;
+ case '\u005cn':
+ case '\u005cf':
break;
- default:
- jj_la1[247] = jj_gen;
- break label_164;
- }
- jj_consume_token(S);
- }
- p = selectorList();
- {
- if (true) {
- return p;
- }
- }
- } catch (ThrowedParseException e) {
- {
- if (true) {
- throw (ParseException) e.e.fillInStackTrace();
- }
- }
- }
- throw new Error("Missing return statement in function");
- }
-
- private boolean jj_2_1(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_1();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(0, xla);
- }
- }
-
- private boolean jj_2_2(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_2();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(1, xla);
- }
- }
-
- private boolean jj_2_3(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_3();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(2, xla);
- }
- }
-
- private boolean jj_2_4(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_4();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(3, xla);
- }
- }
-
- private boolean jj_2_5(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_5();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(4, xla);
- }
- }
-
- private boolean jj_2_6(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_6();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(5, xla);
- }
- }
-
- private boolean jj_2_7(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_7();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(6, xla);
- }
- }
-
- private boolean jj_2_8(int xla) {
- jj_la = xla;
- jj_lastpos = jj_scanpos = token;
- try {
- return !jj_3_8();
- } catch (LookaheadSuccess ls) {
- return true;
- } finally {
- jj_save(7, xla);
- }
- }
-
- private boolean jj_3R_173() {
- if (jj_3R_194()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_251() {
- if (jj_scan_token(PLUS)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_241() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_250()) {
- jj_scanpos = xsp;
- if (jj_3R_251()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_250() {
- if (jj_scan_token(MINUS)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_246() {
- if (jj_scan_token(UNICODERANGE)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3_8() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_173()) {
- jj_scanpos = xsp;
- }
- if (jj_3R_174()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_176() {
- if (jj_3R_174()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3_8()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_199() {
- if (jj_3R_198()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_198() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(20)) {
- jj_scanpos = xsp;
- if (jj_scan_token(24)) {
- jj_scanpos = xsp;
- if (jj_scan_token(25)) {
- return true;
- }
- }
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_165() {
- if (jj_3R_175()) {
- return true;
- }
- if (jj_scan_token(COLON)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- if (jj_3R_176()) {
- return true;
- }
- xsp = jj_scanpos;
- if (jj_3R_177()) {
- jj_scanpos = xsp;
- }
- if (jj_3R_178()) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_178()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_180() {
- if (jj_scan_token(S)) {
- return true;
- }
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_199()) {
- jj_scanpos = xsp;
- }
- return false;
- }
-
- private boolean jj_3R_236() {
- if (jj_scan_token(COMMA)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_179() {
- if (jj_3R_198()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_166() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_179()) {
- jj_scanpos = xsp;
- if (jj_3R_180()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_194() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_235()) {
- jj_scanpos = xsp;
- if (jj_3R_236()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_235() {
- if (jj_scan_token(DIV)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_197() {
- if (jj_scan_token(GUARDED_SYM)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_186() {
- if (jj_scan_token(VARIABLE)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- if (jj_scan_token(COLON)) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_168() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_186()) {
- jj_scanpos = xsp;
- }
- if (jj_scan_token(CONTAINS)) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- if (true) {
- jj_la = 0;
- jj_scanpos = jj_lastpos;
- return false;
- }
- return false;
- }
-
- private boolean jj_3R_201() {
- if (jj_scan_token(HASH)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_273() {
- if (jj_scan_token(IDENT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_274() {
- if (jj_scan_token(FUNCTION)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- if (true) {
- jj_la = 0;
- jj_scanpos = jj_lastpos;
- return false;
- }
- return false;
- }
-
- private boolean jj_3R_272() {
- if (jj_scan_token(COLON)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_203() {
- if (jj_scan_token(COLON)) {
- return true;
- }
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_272()) {
- jj_scanpos = xsp;
- }
- xsp = jj_scanpos;
- if (jj_3R_273()) {
- jj_scanpos = xsp;
- if (jj_3R_274()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3_7() {
- if (jj_3R_172()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_293() {
- if (jj_scan_token(STRING)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_291() {
- if (jj_scan_token(STARMATCH)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_292() {
- if (jj_scan_token(IDENT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_290() {
- if (jj_scan_token(DOLLARMATCH)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_289() {
- if (jj_scan_token(CARETMATCH)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_288() {
- if (jj_scan_token(DASHMATCH)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_287() {
- if (jj_scan_token(INCLUDES)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_254() {
- if (jj_scan_token(INTERPOLATION)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_286() {
- if (jj_scan_token(EQ)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_193() {
- if (jj_scan_token(LBRACE)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_279() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_286()) {
- jj_scanpos = xsp;
- if (jj_3R_287()) {
- jj_scanpos = xsp;
- if (jj_3R_288()) {
- jj_scanpos = xsp;
- if (jj_3R_289()) {
- jj_scanpos = xsp;
- if (jj_3R_290()) {
- jj_scanpos = xsp;
- if (jj_3R_291()) {
- return true;
- }
+ case '\u005cr':
+ if (index + 1 < len) {
+ if (s.charAt(index + 1) == '\u005cn') {
+ index ++;
}
}
+ break;
+ default:
+ buf.append(c);
}
+ } else {
+ throw new CSSParseException("invalid string " + s, getLocator());
}
+ } else {
+ buf.append(c);
}
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- xsp = jj_scanpos;
- if (jj_3R_292()) {
- jj_scanpos = xsp;
- if (jj_3R_293()) {
- return true;
- }
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_204() {
- if (jj_scan_token(LBRACKET)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- if (jj_scan_token(IDENT)) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- xsp = jj_scanpos;
- if (jj_3R_279()) {
- jj_scanpos = xsp;
- }
- if (jj_scan_token(RBRACKET)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_285() {
- if (jj_scan_token(INTERPOLATION)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_192() {
- if (jj_3R_176()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_240() {
- if (jj_scan_token(PARENT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_239() {
- if (jj_scan_token(ANY)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3_6() {
- if (jj_3R_171()) {
- return true;
- }
- if (jj_scan_token(LBRACE)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_172() {
- if (jj_3R_191()) {
- return true;
- }
- if (jj_scan_token(COLON)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- xsp = jj_scanpos;
- if (jj_3R_192()) {
- jj_scanpos = xsp;
- if (jj_3R_193()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_249() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_253()) {
- jj_scanpos = xsp;
- if (jj_3R_254()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_253() {
- if (jj_scan_token(IDENT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_200() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_238()) {
- jj_scanpos = xsp;
- if (jj_3R_239()) {
- jj_scanpos = xsp;
- if (jj_3R_240()) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean jj_3R_238() {
- Token xsp;
- if (jj_3R_249()) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_249()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_169() {
- if (jj_scan_token(COMMA)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_267() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_284()) {
- jj_scanpos = xsp;
- if (jj_3R_285()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_284() {
- if (jj_scan_token(IDENT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_283() {
- if (jj_3R_203()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3_5() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_169()) {
- jj_scanpos = xsp;
- }
- if (jj_3R_170()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_202() {
- if (jj_scan_token(DOT)) {
- return true;
- }
- Token xsp;
- if (jj_3R_267()) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_267()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_281() {
- if (jj_3R_202()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_276() {
- if (jj_3R_202()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_278() {
- if (jj_3R_203()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_266() {
- if (jj_3R_203()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_269() {
- if (jj_3R_202()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_271() {
- if (jj_3R_203()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_252() {
- if (jj_3R_176()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_282() {
- if (jj_3R_204()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_259() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_280()) {
- jj_scanpos = xsp;
- if (jj_3R_281()) {
- jj_scanpos = xsp;
- if (jj_3R_282()) {
- jj_scanpos = xsp;
- if (jj_3R_283()) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private boolean jj_3R_280() {
- if (jj_3R_201()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_258() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_275()) {
- jj_scanpos = xsp;
- if (jj_3R_276()) {
- jj_scanpos = xsp;
- if (jj_3R_277()) {
- jj_scanpos = xsp;
- if (jj_3R_278()) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private boolean jj_3R_275() {
- if (jj_3R_201()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_263() {
- if (jj_3R_203()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_257() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_268()) {
- jj_scanpos = xsp;
- if (jj_3R_269()) {
- jj_scanpos = xsp;
- if (jj_3R_270()) {
- jj_scanpos = xsp;
- if (jj_3R_271()) {
- return true;
- }
- }
- }
- }
- return false;
- }
-
- private boolean jj_3R_268() {
- if (jj_3R_201()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_277() {
- if (jj_3R_204()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_265() {
- if (jj_3R_204()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_270() {
- if (jj_3R_204()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_256() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_264()) {
- jj_scanpos = xsp;
- if (jj_3R_265()) {
- jj_scanpos = xsp;
- if (jj_3R_266()) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean jj_3R_261() {
- if (jj_3R_202()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_264() {
- if (jj_3R_202()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_242() {
- if (jj_scan_token(FUNCTION)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- xsp = jj_scanpos;
- if (jj_3R_252()) {
- jj_scanpos = xsp;
- }
- if (jj_scan_token(RPARAN)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_231() {
- if (jj_3R_246()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_230() {
- if (jj_3R_245()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_185() {
- if (jj_3R_204()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_259()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_229() {
- if (jj_3R_244()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_184() {
- if (jj_3R_203()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_258()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_262() {
- if (jj_3R_204()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_183() {
- if (jj_3R_202()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_257()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_182() {
- if (jj_3R_201()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_256()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
+ index++;
}
- private boolean jj_3R_255() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_260()) {
- jj_scanpos = xsp;
- if (jj_3R_261()) {
- jj_scanpos = xsp;
- if (jj_3R_262()) {
- jj_scanpos = xsp;
- if (jj_3R_263()) {
- return true;
- }
- }
- }
- }
- return false;
- }
+ return buf.toString();
+ }
- private boolean jj_3R_260() {
- if (jj_3R_201()) {
- return true;
- }
- return false;
- }
+ String convertIdent(String s) throws ParseException {
+ return convertStringIndex(s, 0, s.length());
+ }
- private boolean jj_3R_181() {
- if (jj_3R_200()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_255()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_167() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_181()) {
- jj_scanpos = xsp;
- if (jj_3R_182()) {
- jj_scanpos = xsp;
- if (jj_3R_183()) {
- jj_scanpos = xsp;
- if (jj_3R_184()) {
- jj_scanpos = xsp;
- if (jj_3R_185()) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
+ String convertString(String s) throws ParseException {
+ return convertStringIndex(s, 0, s.length());
+ }
- private boolean jj_3R_233() {
- if (jj_3R_198()) {
- return true;
+ void comments() throws ParseException {
+ if (token.specialToken != null){
+ Token tmp_t = token.specialToken;
+ while (tmp_t.specialToken != null) tmp_t = tmp_t.specialToken;
+ while (tmp_t != null) {
+ documentHandler.comment(tmp_t.image);
+ tmp_t = tmp_t.next;
}
- if (jj_3R_167()) {
- return true;
- }
- return false;
}
+ }
- private boolean jj_3R_243() {
- if (jj_scan_token(DOT)) {
- return true;
- }
- return false;
- }
+ void rejectToken(Token t) throws ParseException {
+ Token fakeToken = new Token();
+ t.next = token;
+ fakeToken.next = t;
+ token = fakeToken;
+ }
- private boolean jj_3R_228() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_243()) {
- jj_scanpos = xsp;
- }
- xsp = jj_scanpos;
- if (jj_scan_token(72)) {
- jj_scanpos = xsp;
- if (jj_scan_token(50)) {
- jj_scanpos = xsp;
- if (jj_scan_token(51)) {
- jj_scanpos = xsp;
- if (jj_scan_token(53)) {
- return true;
- }
- }
- }
- }
- return false;
- }
+ String skipAfterExpression() throws ParseException {
+ Token t = getToken(1);
+ StringBuffer s = new StringBuffer();
+ s.append(getToken(0).image);
- private boolean jj_3R_227() {
- if (jj_scan_token(STRING)) {
- return true;
- }
- return false;
+ while ((t.kind != RBRACE) && (t.kind != SEMICOLON) && (t.kind != EOF)) {
+ s.append(t.image);
+ getNextToken();
+ t = getToken(1);
}
- private boolean jj_3R_226() {
- if (jj_3R_242()) {
- return true;
- }
- return false;
- }
+ return s.toString();
+ }
- private boolean jj_3R_188() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_227()) {
- jj_scanpos = xsp;
- if (jj_3R_228()) {
- jj_scanpos = xsp;
- if (jj_3R_229()) {
- jj_scanpos = xsp;
- if (jj_3R_230()) {
- jj_scanpos = xsp;
- if (jj_3R_231()) {
- return true;
- }
+/**
+ * The following functions are useful for a DOM CSS implementation only and are
+ * not part of the general CSS2 parser.
+ */
+ final public void _parseRule() throws ParseException {
+ String ret = null;
+ label_168:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[248] = jj_gen;
+ break label_168;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case IMPORT_SYM:
+ importDeclaration();
+ break;
+ case DEBUG_SYM:
+ case WARN_SYM:
+ debuggingDirective();
+ break;
+ case PLUS:
+ case PRECEDES:
+ case SIBLING:
+ case LBRACKET:
+ case ANY:
+ case PARENT:
+ case DOT:
+ case COLON:
+ case INTERPOLATION:
+ case IDENT:
+ case HASH:
+ styleRule();
+ break;
+ case MEDIA_SYM:
+ media();
+ break;
+ case PAGE_SYM:
+ page();
+ break;
+ case FONT_FACE_SYM:
+ fontFace();
+ break;
+ default:
+ jj_la1[249] = jj_gen;
+ ret = skipStatement();
+ if ((ret == null) || (ret.length() == 0)) {
+ {if (true) return;}
}
- }
- }
- }
- return false;
- }
-
- private boolean jj_3_2() {
- if (jj_3R_166()) {
- return true;
- }
- if (jj_3R_167()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_190() {
- if (jj_scan_token(COMMA)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- if (jj_3R_189()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_232() {
- if (jj_3R_167()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_225() {
- if (jj_scan_token(DIMEN)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_224() {
- if (jj_scan_token(KHZ)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_189() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_232()) {
- jj_scanpos = xsp;
- if (jj_3R_233()) {
- return true;
- }
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3_2()) {
- jj_scanpos = xsp;
- break;
- }
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_223() {
- if (jj_scan_token(HZ)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_222() {
- if (jj_scan_token(MS)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_221() {
- if (jj_scan_token(SECOND)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_220() {
- if (jj_scan_token(GRAD)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3_1() {
- if (jj_3R_165()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_219() {
- if (jj_scan_token(RAD)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_171() {
- if (jj_3R_189()) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_190()) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_218() {
- if (jj_scan_token(DEG)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_217() {
- if (jj_scan_token(EXS)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_216() {
- if (jj_scan_token(REM)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3_4() {
- if (jj_3R_168()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_215() {
- if (jj_scan_token(LEM)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_214() {
- if (jj_scan_token(EMS)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_213() {
- if (jj_scan_token(PX)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_212() {
- if (jj_scan_token(IN)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_211() {
- if (jj_scan_token(PC)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_210() {
- if (jj_scan_token(MM)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_209() {
- if (jj_scan_token(CM)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_248() {
- if (jj_scan_token(INTERPOLATION)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_208() {
- if (jj_scan_token(PT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_207() {
- if (jj_scan_token(PERCENTAGE)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_196() {
- if (jj_3R_237()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3_3() {
- if (jj_3R_165()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_206() {
- if (jj_scan_token(NUMBER)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_205() {
- if (jj_3R_241()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_187() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_205()) {
- jj_scanpos = xsp;
- }
- xsp = jj_scanpos;
- if (jj_3R_206()) {
- jj_scanpos = xsp;
- if (jj_3R_207()) {
- jj_scanpos = xsp;
- if (jj_3R_208()) {
- jj_scanpos = xsp;
- if (jj_3R_209()) {
- jj_scanpos = xsp;
- if (jj_3R_210()) {
- jj_scanpos = xsp;
- if (jj_3R_211()) {
- jj_scanpos = xsp;
- if (jj_3R_212()) {
- jj_scanpos = xsp;
- if (jj_3R_213()) {
- jj_scanpos = xsp;
- if (jj_3R_214()) {
- jj_scanpos = xsp;
- if (jj_3R_215()) {
- jj_scanpos = xsp;
- if (jj_3R_216()) {
- jj_scanpos = xsp;
- if (jj_3R_217()) {
- jj_scanpos = xsp;
- if (jj_3R_218()) {
- jj_scanpos = xsp;
- if (jj_3R_219()) {
- jj_scanpos = xsp;
- if (jj_3R_220()) {
- jj_scanpos = xsp;
- if (jj_3R_221()) {
- jj_scanpos = xsp;
- if (jj_3R_222()) {
- jj_scanpos = xsp;
- if (jj_3R_223()) {
- jj_scanpos = xsp;
- if (jj_3R_224()) {
- jj_scanpos = xsp;
- if (jj_3R_225()) {
- jj_scanpos = xsp;
- if (jj_3R_226()) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
+ if (ret.charAt(0) == '@') {
+ documentHandler.unrecognizedRule(ret);
+ } else {
+ {if (true) throw new CSSParseException("unrecognize rule: " + ret,
+ getLocator());}
}
- }
- }
- }
- return false;
- }
-
- private boolean jj_3R_170() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_187()) {
- jj_scanpos = xsp;
- if (jj_3R_188()) {
- return true;
- }
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_178() {
- if (jj_scan_token(SEMICOLON)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_244() {
- if (jj_scan_token(HASH)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_175() {
- if (jj_scan_token(VARIABLE)) {
- return true;
- }
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
-
- private boolean jj_3R_237() {
- if (jj_3R_175()) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_234() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_247()) {
- jj_scanpos = xsp;
- if (jj_3R_248()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean jj_3R_247() {
- if (jj_scan_token(IDENT)) {
- return true;
- }
- return false;
- }
-
- private boolean jj_3R_245() {
- if (jj_scan_token(URL)) {
- return true;
- }
- return false;
}
+ }
+
+ final public void _parseImportRule() throws ParseException {
+ label_169:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[250] = jj_gen;
+ break label_169;
+ }
+ jj_consume_token(S);
+ }
+ importDeclaration();
+ }
+
+ final public void _parseMediaRule() throws ParseException {
+ label_170:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[251] = jj_gen;
+ break label_170;
+ }
+ jj_consume_token(S);
+ }
+ media();
+ }
+
+ final public void _parseDeclarationBlock() throws ParseException {
+ label_171:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[252] = jj_gen;
+ break label_171;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[253] = jj_gen;
+ ;
+ }
+ label_172:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case SEMICOLON:
+ ;
+ break;
+ default:
+ jj_la1[254] = jj_gen;
+ break label_172;
+ }
+ jj_consume_token(SEMICOLON);
+ label_173:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[255] = jj_gen;
+ break label_173;
+ }
+ jj_consume_token(S);
+ }
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case INTERPOLATION:
+ case IDENT:
+ declaration();
+ break;
+ default:
+ jj_la1[256] = jj_gen;
+ ;
+ }
+ }
+ }
+
+ final public ArrayList<String> _parseSelectors() throws ParseException {
+ ArrayList<String> p = null;
+ try {
+ label_174:
+ while (true) {
+ switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+ case S:
+ ;
+ break;
+ default:
+ jj_la1[257] = jj_gen;
+ break label_174;
+ }
+ jj_consume_token(S);
+ }
+ p = selectorList();
+ {if (true) return p;}
+ } catch (ThrowedParseException e) {
+ {if (true) throw (ParseException) e.e.fillInStackTrace();}
+ }
+ throw new Error("Missing return statement in function");
+ }
+
+ private boolean jj_2_1(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_1(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(0, xla); }
+ }
+
+ private boolean jj_2_2(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_2(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(1, xla); }
+ }
+
+ private boolean jj_2_3(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_3(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(2, xla); }
+ }
+
+ private boolean jj_2_4(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_4(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(3, xla); }
+ }
+
+ private boolean jj_2_5(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_5(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(4, xla); }
+ }
+
+ private boolean jj_2_6(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_6(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(5, xla); }
+ }
+
+ private boolean jj_2_7(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_7(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(6, xla); }
+ }
+
+ private boolean jj_2_8(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_8(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(7, xla); }
+ }
+
+ private boolean jj_2_9(int xla) {
+ jj_la = xla; jj_lastpos = jj_scanpos = token;
+ try { return !jj_3_9(); }
+ catch(LookaheadSuccess ls) { return true; }
+ finally { jj_save(8, xla); }
+ }
+
+ private boolean jj_3R_209() {
+ if (jj_scan_token(MOD)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_208() {
+ if (jj_scan_token(ANY)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_207() {
+ if (jj_scan_token(DIV)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_206() {
+ if (jj_scan_token(COMMA)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_184() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_206()) {
+ jj_scanpos = xsp;
+ if (jj_3R_207()) {
+ jj_scanpos = xsp;
+ if (jj_3R_208()) {
+ jj_scanpos = xsp;
+ if (jj_3R_209()) {
+ jj_scanpos = xsp;
+ if (jj_3R_210()) {
+ jj_scanpos = xsp;
+ if (jj_3R_211()) return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_214() {
+ if (jj_3R_213()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_213() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_scan_token(20)) {
+ jj_scanpos = xsp;
+ if (jj_scan_token(24)) {
+ jj_scanpos = xsp;
+ if (jj_scan_token(25)) return true;
+ }
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_175() {
+ if (jj_3R_185()) return true;
+ if (jj_scan_token(COLON)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ if (jj_3R_186()) return true;
+ xsp = jj_scanpos;
+ if (jj_3R_187()) jj_scanpos = xsp;
+ if (jj_3R_188()) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_188()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_212() {
+ if (jj_scan_token(GUARDED_SYM)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_190() {
+ if (jj_scan_token(S)) return true;
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_214()) jj_scanpos = xsp;
+ return false;
+ }
+
+ private boolean jj_3R_189() {
+ if (jj_3R_213()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_176() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_189()) {
+ jj_scanpos = xsp;
+ if (jj_3R_190()) return true;
+ }
+ return false;
+ }
+
+ private boolean jj_3R_196() {
+ if (jj_scan_token(VARIABLE)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ if (jj_scan_token(COLON)) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_178() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_196()) jj_scanpos = xsp;
+ if (jj_scan_token(CONTAINS)) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ if (true) { jj_la = 0; jj_scanpos = jj_lastpos; return false;}
+ return false;
+ }
+
+ private boolean jj_3R_216() {
+ if (jj_scan_token(HASH)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_286() {
+ if (jj_scan_token(IDENT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_287() {
+ if (jj_scan_token(FUNCTION)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ if (true) { jj_la = 0; jj_scanpos = jj_lastpos; return false;}
+ return false;
+ }
+
+ private boolean jj_3R_285() {
+ if (jj_scan_token(COLON)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_218() {
+ if (jj_scan_token(COLON)) return true;
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_285()) jj_scanpos = xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_286()) {
+ jj_scanpos = xsp;
+ if (jj_3R_287()) return true;
+ }
+ return false;
+ }
+
+ private boolean jj_3_7() {
+ if (jj_3R_182()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_203() {
+ if (jj_scan_token(LBRACE)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_306() {
+ if (jj_scan_token(STRING)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_304() {
+ if (jj_scan_token(STARMATCH)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_305() {
+ if (jj_scan_token(IDENT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_303() {
+ if (jj_scan_token(DOLLARMATCH)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_302() {
+ if (jj_scan_token(CARETMATCH)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_301() {
+ if (jj_scan_token(DASHMATCH)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_300() {
+ if (jj_scan_token(INCLUDES)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_267() {
+ if (jj_scan_token(INTERPOLATION)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_299() {
+ if (jj_scan_token(EQ)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_202() {
+ if (jj_3R_186()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_292() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_299()) {
+ jj_scanpos = xsp;
+ if (jj_3R_300()) {
+ jj_scanpos = xsp;
+ if (jj_3R_301()) {
+ jj_scanpos = xsp;
+ if (jj_3R_302()) {
+ jj_scanpos = xsp;
+ if (jj_3R_303()) {
+ jj_scanpos = xsp;
+ if (jj_3R_304()) return true;
+ }
+ }
+ }
+ }
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ xsp = jj_scanpos;
+ if (jj_3R_305()) {
+ jj_scanpos = xsp;
+ if (jj_3R_306()) return true;
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3_6() {
+ if (jj_3R_181()) return true;
+ if (jj_scan_token(LBRACE)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_219() {
+ if (jj_scan_token(LBRACKET)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ if (jj_scan_token(IDENT)) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ xsp = jj_scanpos;
+ if (jj_3R_292()) jj_scanpos = xsp;
+ if (jj_scan_token(RBRACKET)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_182() {
+ if (jj_3R_201()) return true;
+ if (jj_scan_token(COLON)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ xsp = jj_scanpos;
+ if (jj_3R_202()) {
+ jj_scanpos = xsp;
+ if (jj_3R_203()) return true;
+ }
+ return false;
+ }
+
+ private boolean jj_3R_298() {
+ if (jj_scan_token(INTERPOLATION)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_253() {
+ if (jj_scan_token(PARENT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_265() {
+ if (jj_3R_186()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_252() {
+ if (jj_scan_token(ANY)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_262() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_266()) {
+ jj_scanpos = xsp;
+ if (jj_3R_267()) return true;
+ }
+ return false;
+ }
+
+ private boolean jj_3R_266() {
+ if (jj_scan_token(IDENT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_215() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_251()) {
+ jj_scanpos = xsp;
+ if (jj_3R_252()) {
+ jj_scanpos = xsp;
+ if (jj_3R_253()) return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_251() {
+ Token xsp;
+ if (jj_3R_262()) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_262()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_179() {
+ if (jj_scan_token(COMMA)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_255() {
+ if (jj_scan_token(FUNCTION)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ xsp = jj_scanpos;
+ if (jj_3R_265()) jj_scanpos = xsp;
+ if (jj_scan_token(RPARAN)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_297() {
+ if (jj_scan_token(IDENT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_280() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_297()) {
+ jj_scanpos = xsp;
+ if (jj_3R_298()) return true;
+ }
+ return false;
+ }
+
+ private boolean jj_3R_246() {
+ if (jj_3R_259()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_296() {
+ if (jj_3R_218()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_245() {
+ if (jj_3R_258()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_244() {
+ if (jj_3R_257()) return true;
+ return false;
+ }
+
+ private boolean jj_3_5() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_179()) jj_scanpos = xsp;
+ if (jj_3R_180()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_217() {
+ if (jj_scan_token(DOT)) return true;
+ Token xsp;
+ if (jj_3R_280()) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_280()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_294() {
+ if (jj_3R_217()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_289() {
+ if (jj_3R_217()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_291() {
+ if (jj_3R_218()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_279() {
+ if (jj_3R_218()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_282() {
+ if (jj_3R_217()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_284() {
+ if (jj_3R_218()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_295() {
+ if (jj_3R_219()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_272() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_293()) {
+ jj_scanpos = xsp;
+ if (jj_3R_294()) {
+ jj_scanpos = xsp;
+ if (jj_3R_295()) {
+ jj_scanpos = xsp;
+ if (jj_3R_296()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_293() {
+ if (jj_3R_216()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_271() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_288()) {
+ jj_scanpos = xsp;
+ if (jj_3R_289()) {
+ jj_scanpos = xsp;
+ if (jj_3R_290()) {
+ jj_scanpos = xsp;
+ if (jj_3R_291()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_288() {
+ if (jj_3R_216()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_276() {
+ if (jj_3R_218()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_270() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_281()) {
+ jj_scanpos = xsp;
+ if (jj_3R_282()) {
+ jj_scanpos = xsp;
+ if (jj_3R_283()) {
+ jj_scanpos = xsp;
+ if (jj_3R_284()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_281() {
+ if (jj_3R_216()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_290() {
+ if (jj_3R_219()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_278() {
+ if (jj_3R_219()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_283() {
+ if (jj_3R_219()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_269() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_277()) {
+ jj_scanpos = xsp;
+ if (jj_3R_278()) {
+ jj_scanpos = xsp;
+ if (jj_3R_279()) return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_274() {
+ if (jj_3R_217()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_277() {
+ if (jj_3R_217()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_256() {
+ if (jj_scan_token(DOT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_243() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_256()) jj_scanpos = xsp;
+ xsp = jj_scanpos;
+ if (jj_scan_token(74)) {
+ jj_scanpos = xsp;
+ if (jj_scan_token(51)) {
+ jj_scanpos = xsp;
+ if (jj_scan_token(52)) {
+ jj_scanpos = xsp;
+ if (jj_scan_token(54)) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_195() {
+ if (jj_3R_219()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_272()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_242() {
+ if (jj_scan_token(STRING)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_241() {
+ if (jj_3R_255()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_194() {
+ if (jj_3R_218()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_271()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_198() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_242()) {
+ jj_scanpos = xsp;
+ if (jj_3R_243()) {
+ jj_scanpos = xsp;
+ if (jj_3R_244()) {
+ jj_scanpos = xsp;
+ if (jj_3R_245()) {
+ jj_scanpos = xsp;
+ if (jj_3R_246()) return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_275() {
+ if (jj_3R_219()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_193() {
+ if (jj_3R_217()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_270()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_192() {
+ if (jj_3R_216()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_269()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_268() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_273()) {
+ jj_scanpos = xsp;
+ if (jj_3R_274()) {
+ jj_scanpos = xsp;
+ if (jj_3R_275()) {
+ jj_scanpos = xsp;
+ if (jj_3R_276()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_273() {
+ if (jj_3R_216()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_191() {
+ if (jj_3R_215()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_268()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_177() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_191()) {
+ jj_scanpos = xsp;
+ if (jj_3R_192()) {
+ jj_scanpos = xsp;
+ if (jj_3R_193()) {
+ jj_scanpos = xsp;
+ if (jj_3R_194()) {
+ jj_scanpos = xsp;
+ if (jj_3R_195()) return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_240() {
+ if (jj_scan_token(DIMEN)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_248() {
+ if (jj_3R_213()) return true;
+ if (jj_3R_177()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_239() {
+ if (jj_scan_token(KHZ)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_238() {
+ if (jj_scan_token(HZ)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_237() {
+ if (jj_scan_token(MS)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_236() {
+ if (jj_scan_token(SECOND)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_235() {
+ if (jj_scan_token(GRAD)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_234() {
+ if (jj_scan_token(RAD)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_233() {
+ if (jj_scan_token(DEG)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_232() {
+ if (jj_scan_token(EXS)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_231() {
+ if (jj_scan_token(REM)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_230() {
+ if (jj_scan_token(LEM)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_229() {
+ if (jj_scan_token(EMS)) return true;
+ return false;
+ }
+
+ private boolean jj_3_2() {
+ if (jj_3R_176()) return true;
+ if (jj_3R_177()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_228() {
+ if (jj_scan_token(PX)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_227() {
+ if (jj_scan_token(IN)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_200() {
+ if (jj_scan_token(COMMA)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ if (jj_3R_199()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_247() {
+ if (jj_3R_177()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_226() {
+ if (jj_scan_token(PC)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_225() {
+ if (jj_scan_token(MM)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_199() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_247()) {
+ jj_scanpos = xsp;
+ if (jj_3R_248()) return true;
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3_2()) { jj_scanpos = xsp; break; }
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_224() {
+ if (jj_scan_token(CM)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_223() {
+ if (jj_scan_token(PT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_222() {
+ if (jj_scan_token(PERCENTAGE)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_205() {
+ if (jj_3R_250()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_221() {
+ if (jj_scan_token(NUMBER)) return true;
+ return false;
+ }
+
+ private boolean jj_3_1() {
+ if (jj_3R_175()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_220() {
+ if (jj_3R_254()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_181() {
+ if (jj_3R_199()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_200()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_197() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_220()) jj_scanpos = xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_221()) {
+ jj_scanpos = xsp;
+ if (jj_3R_222()) {
+ jj_scanpos = xsp;
+ if (jj_3R_223()) {
+ jj_scanpos = xsp;
+ if (jj_3R_224()) {
+ jj_scanpos = xsp;
+ if (jj_3R_225()) {
+ jj_scanpos = xsp;
+ if (jj_3R_226()) {
+ jj_scanpos = xsp;
+ if (jj_3R_227()) {
+ jj_scanpos = xsp;
+ if (jj_3R_228()) {
+ jj_scanpos = xsp;
+ if (jj_3R_229()) {
+ jj_scanpos = xsp;
+ if (jj_3R_230()) {
+ jj_scanpos = xsp;
+ if (jj_3R_231()) {
+ jj_scanpos = xsp;
+ if (jj_3R_232()) {
+ jj_scanpos = xsp;
+ if (jj_3R_233()) {
+ jj_scanpos = xsp;
+ if (jj_3R_234()) {
+ jj_scanpos = xsp;
+ if (jj_3R_235()) {
+ jj_scanpos = xsp;
+ if (jj_3R_236()) {
+ jj_scanpos = xsp;
+ if (jj_3R_237()) {
+ jj_scanpos = xsp;
+ if (jj_3R_238()) {
+ jj_scanpos = xsp;
+ if (jj_3R_239()) {
+ jj_scanpos = xsp;
+ if (jj_3R_240()) {
+ jj_scanpos = xsp;
+ if (jj_3R_241()) return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_180() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_197()) {
+ jj_scanpos = xsp;
+ if (jj_3R_198()) return true;
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_257() {
+ if (jj_scan_token(HASH)) return true;
+ return false;
+ }
+
+ private boolean jj_3_4() {
+ if (jj_3R_178()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_250() {
+ if (jj_3R_185()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_258() {
+ if (jj_scan_token(URL)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_204() {
+ if (jj_3R_180()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_183() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_204()) {
+ jj_scanpos = xsp;
+ if (jj_3R_205()) return true;
+ }
+ return false;
+ }
- private boolean jj_3R_191() {
- Token xsp;
- if (jj_3R_234()) {
- return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_234()) {
- jj_scanpos = xsp;
- break;
- }
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_scan_token(1)) {
- jj_scanpos = xsp;
- break;
- }
- }
- return false;
- }
+ private boolean jj_3R_261() {
+ if (jj_scan_token(INTERPOLATION)) return true;
+ return false;
+ }
- private boolean jj_3R_177() {
- if (jj_3R_197()) {
- return true;
- }
- return false;
- }
+ private boolean jj_3_9() {
+ if (jj_3R_184()) return true;
+ return false;
+ }
- private boolean jj_3R_195() {
- if (jj_3R_170()) {
- return true;
- }
- return false;
- }
+ private boolean jj_3_3() {
+ if (jj_3R_175()) return true;
+ return false;
+ }
- private boolean jj_3R_174() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_195()) {
- jj_scanpos = xsp;
- if (jj_3R_196()) {
- return true;
- }
- }
- return false;
- }
-
- /** Generated Token Manager. */
- public ParserTokenManager token_source;
- /** Current token. */
- public Token token;
- /** Next token. */
- public Token jj_nt;
- private int jj_ntk;
- private Token jj_scanpos, jj_lastpos;
- private int jj_la;
- private int jj_gen;
- final private int[] jj_la1 = new int[248];
- static private int[] jj_la1_0;
- static private int[] jj_la1_1;
- static private int[] jj_la1_2;
- static private int[] jj_la1_3;
- static {
- jj_la1_init_0();
- jj_la1_init_1();
- jj_la1_init_2();
- jj_la1_init_3();
- }
-
- private static void jj_la1_init_0() {
- jj_la1_0 = new int[] { 0x0, 0xc02, 0xc02, 0x0, 0xc00, 0x2, 0x2, 0x2,
- 0xd3100000, 0x0, 0xc00, 0x2, 0xc00, 0x2, 0x0, 0x2, 0x2, 0x2,
- 0x0, 0x0, 0x2, 0x2, 0x0, 0x2, 0x0, 0x2, 0x2, 0xd3100000,
- 0xd3100000, 0x2, 0x2, 0x2, 0xd3f45400, 0xd3f45400, 0x2, 0x2,
- 0x2, 0x0, 0x0, 0x2, 0x0, 0x800000, 0x2, 0x0, 0x2, 0x2, 0x2,
- 0x2, 0x0, 0x800000, 0x2, 0x0, 0x2, 0xe45400, 0x3100000,
- 0x3100002, 0x3100000, 0x2, 0x2, 0x480002, 0x480002, 0x2, 0x0,
- 0x0, 0x2, 0x2, 0x2, 0x2, 0xd3100000, 0xd3100000, 0x2, 0x400000,
- 0x2, 0xd3100000, 0x2, 0x10000000, 0x10000000, 0x10000000,
- 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000,
- 0x10000000, 0x10000000, 0xd0000000, 0x0, 0x0, 0x0, 0x0,
- 0xc0000000, 0x2, 0x2, 0xfc000, 0x2, 0x0, 0x2, 0xfc000, 0x0,
- 0x2, 0x0, 0x2, 0x0, 0x2, 0x800000, 0x0, 0xd3100000, 0x0,
- 0x4d380002, 0x2, 0xd3100000, 0x2, 0x0, 0x2, 0x4d380002, 0x0,
- 0x2, 0xd3100000, 0x2, 0x4d380002, 0x2, 0x2, 0x2, 0x0, 0x2,
- 0xd3100000, 0x2, 0x2, 0x400000, 0x2, 0x2, 0x2, 0x2, 0x0, 0x2,
- 0xd3100000, 0xd3100000, 0x2, 0x400000, 0x2, 0x2, 0x2, 0x400000,
- 0x0, 0x0, 0x300000, 0x2, 0x0, 0x400000, 0x2, 0x300000, 0x2,
- 0x0, 0x2, 0x0, 0x2, 0x800000, 0x2, 0x2, 0x0, 0x2, 0x0, 0x2,
- 0x2, 0x2, 0x400000, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0x2, 0x2,
- 0x2, 0x400000, 0x2, 0x2, 0x2, 0x0, 0x2, 0x2, 0x2, 0x400000,
- 0x2, 0x2, 0x0, 0x2, 0x0, 0x2, 0x2, 0x2, 0x400000, 0x0, 0x2,
- 0x2, 0x0, 0x2, 0x2, 0x2, 0x800000, 0x2, 0x2, 0x0, 0x800000,
- 0x2, 0x0, 0x2, 0x0, 0xd3100000, 0x2, 0x0, 0x2, 0x0, 0x800000,
- 0x2, 0x0, 0x2, 0x301000, 0x2, 0x0, 0x2, 0x2, 0x2, 0x2,
- 0x8400000, 0x8400000, 0x300000, 0x300000, 0x300000, 0x0, 0x0,
- 0x0, 0x0, 0x300000, 0x2, 0x2, 0x300000, 0x2, 0xd3100000, 0x2,
- 0x2, 0x2, 0x0, 0x800000, 0x2, 0x0, 0x2, };
- }
-
- private static void jj_la1_init_1() {
- jj_la1_1 = new int[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0xacc00181, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100,
- 0x100, 0x0, 0x0, 0x240000, 0x0, 0x240000, 0x0, 0x0, 0xac800181,
- 0xac800181, 0x0, 0x0, 0x0, 0xc000381, 0xc000381, 0x0, 0x0, 0x0,
- 0x0, 0x80, 0x0, 0x100, 0x0, 0x0, 0x100, 0x0, 0x0, 0x0, 0x0,
- 0x100, 0x0, 0x0, 0x100, 0x0, 0x200, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x185, 0x185, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x0,
- 0xac800181, 0xac800181, 0x0, 0x0, 0x0, 0x181, 0x0, 0x81, 0x81,
- 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x181, 0x100,
- 0x100, 0x100, 0x100, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xa0000000, 0xc800181, 0x0,
- 0x7e, 0x0, 0xc800181, 0x0, 0x0, 0x0, 0x7e, 0x0, 0x0, 0xc800181,
- 0x0, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc800181, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x100, 0x0, 0xac800181, 0xac800181, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x2c0081, 0x0, 0x80, 0x0,
- 0x0, 0x2c0081, 0x0, 0x80, 0x0, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0xc000000, 0x0,
- 0x0, 0xc0000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
- 0x100, 0x0, 0xc000000, 0x181, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
- 0x100, 0x0, 0x2c0001, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x2c0001, 0x0, 0x0, 0x1, 0x2c0000, 0x2c0001, 0x2c0001,
- 0x0, 0x0, 0x2c0001, 0x0, 0xc000181, 0x0, 0x0, 0x0, 0x100, 0x0,
- 0x0, 0x100, 0x0, };
- }
-
- private static void jj_la1_init_2() {
- jj_la1_2 = new int[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100,
- 0x1000, 0x0, 0x0, 0x0, 0x0, 0x880, 0x0, 0x0, 0x0, 0x100, 0x100,
- 0x0, 0x0, 0x2000, 0x0, 0x2000, 0x0, 0x0, 0x1112, 0x1112, 0x0,
- 0x0, 0x0, 0x2b80, 0x2b80, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
- 0x100, 0x0, 0x0, 0x100, 0x0, 0x0, 0x0, 0x0, 0x100, 0x0, 0x0,
- 0x100, 0x0, 0x2a80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x380, 0x380, 0x0,
- 0x100, 0x100, 0x0, 0x0, 0x0, 0x0, 0x1112, 0x1112, 0x0, 0x0,
- 0x0, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x0, 0x0, 0x0,
- 0x0, 0x180, 0x0, 0x0, 0x0, 0x0, 0x100, 0x0, 0x40, 0x0, 0x0,
- 0x0, 0x102, 0x1000, 0x1300, 0x0, 0x1102, 0x0, 0x1, 0x0, 0x1300,
- 0x20, 0x0, 0x1102, 0x0, 0x1300, 0x0, 0x0, 0x0, 0x1100, 0x0,
- 0x1102, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x100, 0x0, 0x1102,
- 0x1102, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000, 0x1000,
- 0xfffffb80, 0x0, 0x0, 0x0, 0x0, 0xfffffb80, 0x0, 0x0, 0x0,
- 0x1100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1000, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x100, 0x0, 0x0, 0x100, 0x0, 0x0, 0x100, 0x0, 0x0, 0x0,
- 0x100, 0x0, 0x0, 0x100, 0x0, 0xfffffb80, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0xfffffb80, 0x0, 0xffffe200, 0x0,
- 0x100, 0x980, 0xffffeb80, 0x0, 0x0, 0xfffffb80, 0x0, 0x100,
- 0x0, 0x0, 0x0, 0x100, 0x0, 0x0, 0x100, 0x0, };
- }
-
- private static void jj_la1_init_3() {
- jj_la1_3 = new int[] { 0x8, 0x80, 0x80, 0x2, 0x80, 0x0, 0x0, 0x0, 0x75,
- 0x0, 0x80, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x45, 0x45, 0x0, 0x0, 0x0,
- 0xc401bf, 0xc401bf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0xc401be, 0x0, 0x0, 0x0, 0x0, 0x0, 0x400000, 0x400000, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x45, 0x45, 0x0, 0x0, 0x0, 0x1,
- 0x0, 0x1, 0x1, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x45, 0x0,
- 0x200000, 0x0, 0x45, 0x0, 0x0, 0x0, 0x200000, 0x0, 0x0, 0x45,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x45, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x400000, 0x0, 0x75, 0x75, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x440001, 0x0, 0x0, 0x0, 0x0, 0x440001,
- 0x0, 0x0, 0x0, 0x400000, 0x0, 0x0, 0x0, 0x0, 0x380000, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x1, 0x0, 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x440001, 0x0,
- 0x100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x440001, 0x0,
- 0x400000, 0x0, 0x0, 0x40001, 0x440001, 0x0, 0x0, 0x440001, 0x0,
- 0x37, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, };
- }
-
- final private JJCalls[] jj_2_rtns = new JJCalls[8];
- private boolean jj_rescan = false;
- private int jj_gc = 0;
-
- /** Constructor with user supplied CharStream. */
- public Parser(CharStream stream) {
- token_source = new ParserTokenManager(stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 248; i++) {
- jj_la1[i] = -1;
- }
- for (int i = 0; i < jj_2_rtns.length; i++) {
- jj_2_rtns[i] = new JJCalls();
- }
- }
+ private boolean jj_3R_264() {
+ if (jj_scan_token(PLUS)) return true;
+ return false;
+ }
- /** Reinitialise. */
- public void ReInit(CharStream stream) {
- token_source.ReInit(stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 248; i++) {
- jj_la1[i] = -1;
- }
- for (int i = 0; i < jj_2_rtns.length; i++) {
- jj_2_rtns[i] = new JJCalls();
- }
+ private boolean jj_3R_254() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_263()) {
+ jj_scanpos = xsp;
+ if (jj_3R_264()) return true;
}
+ return false;
+ }
- /** Constructor with generated Token Manager. */
- public Parser(ParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 248; i++) {
- jj_la1[i] = -1;
- }
- for (int i = 0; i < jj_2_rtns.length; i++) {
- jj_2_rtns[i] = new JJCalls();
- }
- }
+ private boolean jj_3R_263() {
+ if (jj_scan_token(MINUS)) return true;
+ return false;
+ }
- /** Reinitialise. */
- public void ReInit(ParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 248; i++) {
- jj_la1[i] = -1;
- }
+ private boolean jj_3R_259() {
+ if (jj_scan_token(UNICODERANGE)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_188() {
+ if (jj_scan_token(SEMICOLON)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3_8() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3_9()) jj_scanpos = xsp;
+ if (jj_3R_183()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_186() {
+ if (jj_3R_183()) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3_8()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_185() {
+ if (jj_scan_token(VARIABLE)) return true;
+ Token xsp;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_249() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_260()) {
+ jj_scanpos = xsp;
+ if (jj_3R_261()) return true;
+ }
+ return false;
+ }
+
+ private boolean jj_3R_260() {
+ if (jj_scan_token(IDENT)) return true;
+ return false;
+ }
+
+ private boolean jj_3R_201() {
+ Token xsp;
+ if (jj_3R_249()) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_249()) { jj_scanpos = xsp; break; }
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_211() {
+ if (jj_scan_token(MINUS)) return true;
+ Token xsp;
+ if (jj_scan_token(1)) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ private boolean jj_3R_187() {
+ if (jj_3R_212()) return true;
+ return false;
+ }
+
+ private boolean jj_3R_210() {
+ if (jj_scan_token(PLUS)) return true;
+ Token xsp;
+ if (jj_scan_token(1)) return true;
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_scan_token(1)) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ /** Generated Token Manager. */
+ public ParserTokenManager token_source;
+ /** Current token. */
+ public Token token;
+ /** Next token. */
+ public Token jj_nt;
+ private int jj_ntk;
+ private Token jj_scanpos, jj_lastpos;
+ private int jj_la;
+ private int jj_gen;
+ final private int[] jj_la1 = new int[258];
+ static private int[] jj_la1_0;
+ static private int[] jj_la1_1;
+ static private int[] jj_la1_2;
+ static private int[] jj_la1_3;
+ static {
+ jj_la1_init_0();
+ jj_la1_init_1();
+ jj_la1_init_2();
+ jj_la1_init_3();
+ }
+ private static void jj_la1_init_0() {
+ jj_la1_0 = new int[] {0x0,0xc02,0xc02,0x0,0xc00,0x2,0x2,0x2,0x53100000,0x0,0xc00,0x2,0xc00,0x2,0x0,0x2,0x2,0x2,0x0,0x0,0x2,0x2,0x0,0x2,0x0,0x2,0x2,0x53100000,0x53100000,0x2,0x2,0x2,0x53f45400,0x53f45400,0x2,0x2,0x2,0x0,0x0,0x2,0x0,0x800000,0x2,0x0,0x2,0x2,0x2,0x2,0x0,0x800000,0x2,0x0,0x2,0xe45400,0x3100000,0x3100002,0x3100000,0x2,0x2,0x480002,0x480002,0x2,0x0,0x0,0x2,0x2,0x2,0x2,0x53100000,0x53100000,0x2,0x400000,0x2,0x53100000,0x2,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x10000000,0x50000000,0x0,0x0,0x0,0x0,0x40000000,0x2,0x2,0xfc000,0x2,0x0,0x2,0xfc000,0x0,0x2,0x0,0x2,0x0,0x2,0x800000,0x0,0x53100000,0x0,0x4d380002,0x2,0x53100000,0x2,0x0,0x2,0x4d380002,0x0,0x2,0x53100000,0x2,0x4d380002,0x2,0x2,0x2,0x0,0x2,0x53100000,0x2,0x2,0x400000,0x2,0x2,0x2,0x2,0x0,0x2,0x53100000,0x53100000,0x2,0x400000,0x2,0x2,0x2,0x400000,0x0,0x0,0x300000,0x2,0x0,0x400000,0x2,0x300000,0x2,0x0,0x2,0x0,0x2,0x800000,0x2,0x53100000,0x2,0x801000,0x2,0x2,0x0,0x2,0x0,0x2,0x2,0x2,0x400000,0x2,0x2,0x2,0x2,0x2,0x0,0x2,0x2,0x2,0x400000,0x2,0x2,0x2,0x0,0x2,0x2,0x2,0x400000,0x2,0x2,0x0,0x2,0x0,0x2,0x2,0x2,0x400000,0x0,0x2,0x2,0x0,0x2,0x2,0x2,0x800000,0x2,0x2,0x800000,0x2,0x2,0x0,0x800000,0x2,0x0,0x2,0x0,0x53100000,0x2,0x0,0x2,0x0,0x800000,0x2,0x0,0x2,0x301000,0x2,0x0,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0x2,0xc8700000,0x300000,0x300000,0x300000,0x0,0x0,0x0,0x0,0x300000,0x2,0x2,0x300000,0x2,0x53100000,0x2,0x2,0x2,0x0,0x800000,0x2,0x0,0x2,};
+ }
+ private static void jj_la1_init_1() {
+ jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x59800303,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x200,0x0,0x0,0x480000,0x0,0x480000,0x0,0x0,0x59000303,0x59000303,0x0,0x0,0x0,0x18000703,0x18000703,0x0,0x0,0x0,0x0,0x100,0x0,0x200,0x0,0x0,0x200,0x0,0x0,0x0,0x0,0x200,0x0,0x0,0x200,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x30a,0x30a,0x0,0x200,0x200,0x0,0x0,0x0,0x0,0x59000303,0x59000303,0x0,0x0,0x0,0x303,0x0,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x102,0x303,0x200,0x200,0x200,0x200,0x201,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x0,0x0,0x0,0x0,0x0,0x0,0x40000000,0x19000303,0x0,0xfc,0x0,0x19000303,0x0,0x0,0x0,0xfc,0x0,0x0,0x19000303,0x0,0xfc,0x0,0x0,0x0,0x0,0x0,0x19000303,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x59000303,0x59000303,0x0,0x0,0x0,0x0,0x0,0x0,0x100,0x100,0x580102,0x0,0x100,0x0,0x0,0x580102,0x0,0x100,0x0,0x200,0x0,0x0,0x0,0x18000303,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x0,0x18000000,0x0,0x0,0x180000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x200,0x0,0x0,0x200,0x0,0x18000000,0x303,0x0,0x0,0x0,0x200,0x0,0x0,0x200,0x0,0x580002,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x580002,0x0,0x0,0x2,0x580000,0x580002,0x580002,0x0,0x0,0x580002,0x0,0x18000303,0x0,0x0,0x0,0x200,0x0,0x0,0x200,0x0,};
+ }
+ private static void jj_la1_init_2() {
+ jj_la1_2 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x401,0x4000,0x0,0x0,0x0,0x0,0x2200,0x0,0x0,0x0,0x400,0x400,0x0,0x0,0x8000,0x0,0x8000,0x0,0x0,0x4465,0x4465,0x0,0x0,0x0,0xae00,0xae00,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0xaa00,0x0,0x0,0x0,0x0,0x0,0xe00,0xe00,0x0,0x400,0x400,0x0,0x0,0x0,0x0,0x4465,0x4465,0x0,0x0,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400,0x400,0x400,0x400,0x400,0x400,0x0,0x0,0x0,0x0,0x600,0x0,0x0,0x0,0x0,0x400,0x0,0x100,0x0,0x0,0x1,0x424,0x4000,0x4c00,0x0,0x4424,0x0,0x2,0x0,0x4c00,0x80,0x0,0x4424,0x0,0x4c00,0x0,0x0,0x0,0x4400,0x0,0x4424,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400,0x0,0x4425,0x4425,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x4000,0xffffee00,0x0,0x0,0x0,0x0,0xffffee00,0x0,0x0,0x0,0x4400,0x0,0x0,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,0xffffee00,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffffee00,0x0,0xffff8800,0x0,0x400,0x2600,0xffffae00,0x0,0x0,0xffffee00,0x0,0x400,0x0,0x0,0x0,0x400,0x0,0x0,0x400,0x0,};
+ }
+ private static void jj_la1_init_3() {
+ jj_la1_3 = new int[] {0x20,0x200,0x200,0x8,0x200,0x0,0x0,0x0,0x1d4,0x0,0x200,0x0,0x200,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x114,0x0,0x0,0x0,0x31006fc,0x31006fc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x31006f8,0x0,0x0,0x0,0x0,0x0,0x1000000,0x1000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x114,0x0,0x0,0x0,0x4,0x0,0x4,0x4,0x0,0x0,0x4,0x4,0x4,0x4,0x4,0x4,0x4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x0,0x0,0x114,0x0,0x800000,0x0,0x114,0x0,0x0,0x0,0x800000,0x0,0x0,0x114,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x114,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1000000,0x0,0x1d4,0x1d4,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x0,0x0,0x0,0x1100007,0x0,0x0,0x0,0x1000000,0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x0,0xe00000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x400,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x1100007,0x0,0x1000003,0x0,0x0,0x100004,0x1100007,0x0,0x0,0x1100007,0x0,0xdc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,};
+ }
+ final private JJCalls[] jj_2_rtns = new JJCalls[9];
+ private boolean jj_rescan = false;
+ private int jj_gc = 0;
+
+ /** Constructor with user supplied CharStream. */
+ public Parser(CharStream stream) {
+ token_source = new ParserTokenManager(stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 258; i++) jj_la1[i] = -1;
+ for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+ }
+
+ /** Reinitialise. */
+ public void ReInit(CharStream stream) {
+ token_source.ReInit(stream);
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 258; i++) jj_la1[i] = -1;
+ for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+ }
+
+ /** Constructor with generated Token Manager. */
+ public Parser(ParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 258; i++) jj_la1[i] = -1;
+ for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+ }
+
+ /** Reinitialise. */
+ public void ReInit(ParserTokenManager tm) {
+ token_source = tm;
+ token = new Token();
+ jj_ntk = -1;
+ jj_gen = 0;
+ for (int i = 0; i < 258; i++) jj_la1[i] = -1;
+ for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
+ }
+
+ private Token jj_consume_token(int kind) throws ParseException {
+ Token oldToken;
+ if ((oldToken = token).next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ if (token.kind == kind) {
+ jj_gen++;
+ if (++jj_gc > 100) {
+ jj_gc = 0;
for (int i = 0; i < jj_2_rtns.length; i++) {
- jj_2_rtns[i] = new JJCalls();
- }
- }
-
- private Token jj_consume_token(int kind) throws ParseException {
- Token oldToken;
- if ((oldToken = token).next != null) {
- token = token.next;
- } else {
- token = token.next = token_source.getNextToken();
- }
- jj_ntk = -1;
- if (token.kind == kind) {
- jj_gen++;
- if (++jj_gc > 100) {
- jj_gc = 0;
- for (int i = 0; i < jj_2_rtns.length; i++) {
- JJCalls c = jj_2_rtns[i];
- while (c != null) {
- if (c.gen < jj_gen) {
- c.first = null;
- }
- c = c.next;
- }
- }
- }
- return token;
- }
- token = oldToken;
- jj_kind = kind;
- throw generateParseException();
- }
-
- static private final class LookaheadSuccess extends java.lang.Error {
- }
-
- final private LookaheadSuccess jj_ls = new LookaheadSuccess();
-
- private boolean jj_scan_token(int kind) {
- if (jj_scanpos == jj_lastpos) {
- jj_la--;
- if (jj_scanpos.next == null) {
- jj_lastpos = jj_scanpos = jj_scanpos.next = token_source
- .getNextToken();
- } else {
- jj_lastpos = jj_scanpos = jj_scanpos.next;
- }
- } else {
- jj_scanpos = jj_scanpos.next;
- }
- if (jj_rescan) {
- int i = 0;
- Token tok = token;
- while (tok != null && tok != jj_scanpos) {
- i++;
- tok = tok.next;
- }
- if (tok != null) {
- jj_add_error_token(kind, i);
- }
- }
- if (jj_scanpos.kind != kind) {
- return true;
- }
- if (jj_la == 0 && jj_scanpos == jj_lastpos) {
- throw jj_ls;
- }
- return false;
- }
-
- /** Get the next Token. */
- final public Token getNextToken() {
- if (token.next != null) {
- token = token.next;
- } else {
- token = token.next = token_source.getNextToken();
- }
- jj_ntk = -1;
- jj_gen++;
- return token;
- }
-
- /** Get the specific Token. */
- final public Token getToken(int index) {
- Token t = token;
- for (int i = 0; i < index; i++) {
- if (t.next != null) {
- t = t.next;
- } else {
- t = t.next = token_source.getNextToken();
- }
- }
- return t;
- }
-
- private int jj_ntk() {
- if ((jj_nt = token.next) == null) {
- return (jj_ntk = (token.next = token_source.getNextToken()).kind);
- } else {
- return (jj_ntk = jj_nt.kind);
- }
- }
-
- private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
- private int[] jj_expentry;
- private int jj_kind = -1;
- private int[] jj_lasttokens = new int[100];
- private int jj_endpos;
-
- private void jj_add_error_token(int kind, int pos) {
- if (pos >= 100) {
- return;
- }
- if (pos == jj_endpos + 1) {
- jj_lasttokens[jj_endpos++] = kind;
- } else if (jj_endpos != 0) {
- jj_expentry = new int[jj_endpos];
- for (int i = 0; i < jj_endpos; i++) {
- jj_expentry[i] = jj_lasttokens[i];
- }
- jj_entries_loop: for (java.util.Iterator<?> it = jj_expentries
- .iterator(); it.hasNext();) {
- int[] oldentry = (int[]) (it.next());
- if (oldentry.length == jj_expentry.length) {
- for (int i = 0; i < jj_expentry.length; i++) {
- if (oldentry[i] != jj_expentry[i]) {
- continue jj_entries_loop;
- }
- }
- jj_expentries.add(jj_expentry);
- break jj_entries_loop;
- }
- }
- if (pos != 0) {
- jj_lasttokens[(jj_endpos = pos) - 1] = kind;
- }
- }
- }
-
- /** Generate ParseException. */
- public ParseException generateParseException() {
- jj_expentries.clear();
- boolean[] la1tokens = new boolean[120];
- if (jj_kind >= 0) {
- la1tokens[jj_kind] = true;
- jj_kind = -1;
- }
- for (int i = 0; i < 248; i++) {
- if (jj_la1[i] == jj_gen) {
- for (int j = 0; j < 32; j++) {
- if ((jj_la1_0[i] & (1 << j)) != 0) {
- la1tokens[j] = true;
- }
- if ((jj_la1_1[i] & (1 << j)) != 0) {
- la1tokens[32 + j] = true;
- }
- if ((jj_la1_2[i] & (1 << j)) != 0) {
- la1tokens[64 + j] = true;
- }
- if ((jj_la1_3[i] & (1 << j)) != 0) {
- la1tokens[96 + j] = true;
- }
- }
- }
- }
- for (int i = 0; i < 120; i++) {
- if (la1tokens[i]) {
- jj_expentry = new int[1];
- jj_expentry[0] = i;
- jj_expentries.add(jj_expentry);
- }
- }
- jj_endpos = 0;
- jj_rescan_token();
- jj_add_error_token(0, 0);
- int[][] exptokseq = new int[jj_expentries.size()][];
- for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = jj_expentries.get(i);
- }
- return new ParseException(token, exptokseq, tokenImage);
- }
-
- /** Enable tracing. */
- final public void enable_tracing() {
- }
-
- /** Disable tracing. */
- final public void disable_tracing() {
- }
-
- private void jj_rescan_token() {
- jj_rescan = true;
- for (int i = 0; i < 8; i++) {
- try {
- JJCalls p = jj_2_rtns[i];
- do {
- if (p.gen > jj_gen) {
- jj_la = p.arg;
- jj_lastpos = jj_scanpos = p.first;
- switch (i) {
- case 0:
- jj_3_1();
- break;
- case 1:
- jj_3_2();
- break;
- case 2:
- jj_3_3();
- break;
- case 3:
- jj_3_4();
- break;
- case 4:
- jj_3_5();
- break;
- case 5:
- jj_3_6();
- break;
- case 6:
- jj_3_7();
- break;
- case 7:
- jj_3_8();
- break;
- }
- }
- p = p.next;
- } while (p != null);
- } catch (LookaheadSuccess ls) {
- }
- }
- jj_rescan = false;
- }
-
- private void jj_save(int index, int xla) {
- JJCalls p = jj_2_rtns[index];
- while (p.gen > jj_gen) {
- if (p.next == null) {
- p = p.next = new JJCalls();
- break;
- }
- p = p.next;
- }
- p.gen = jj_gen + xla - jj_la;
- p.first = token;
- p.arg = xla;
- }
-
- static final class JJCalls {
- int gen;
- Token first;
- int arg;
- JJCalls next;
- }
+ JJCalls c = jj_2_rtns[i];
+ while (c != null) {
+ if (c.gen < jj_gen) c.first = null;
+ c = c.next;
+ }
+ }
+ }
+ return token;
+ }
+ token = oldToken;
+ jj_kind = kind;
+ throw generateParseException();
+ }
+
+ static private final class LookaheadSuccess extends java.lang.Error { }
+ final private LookaheadSuccess jj_ls = new LookaheadSuccess();
+ private boolean jj_scan_token(int kind) {
+ if (jj_scanpos == jj_lastpos) {
+ jj_la--;
+ if (jj_scanpos.next == null) {
+ jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
+ } else {
+ jj_lastpos = jj_scanpos = jj_scanpos.next;
+ }
+ } else {
+ jj_scanpos = jj_scanpos.next;
+ }
+ if (jj_rescan) {
+ int i = 0; Token tok = token;
+ while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
+ if (tok != null) jj_add_error_token(kind, i);
+ }
+ if (jj_scanpos.kind != kind) return true;
+ if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
+ return false;
+ }
+
+
+/** Get the next Token. */
+ final public Token getNextToken() {
+ if (token.next != null) token = token.next;
+ else token = token.next = token_source.getNextToken();
+ jj_ntk = -1;
+ jj_gen++;
+ return token;
+ }
+
+/** Get the specific Token. */
+ final public Token getToken(int index) {
+ Token t = token;
+ for (int i = 0; i < index; i++) {
+ if (t.next != null) t = t.next;
+ else t = t.next = token_source.getNextToken();
+ }
+ return t;
+ }
+
+ private int jj_ntk() {
+ if ((jj_nt=token.next) == null)
+ return (jj_ntk = (token.next=token_source.getNextToken()).kind);
+ else
+ return (jj_ntk = jj_nt.kind);
+ }
+
+ private java.util.List<int[]> jj_expentries = new java.util.ArrayList<int[]>();
+ private int[] jj_expentry;
+ private int jj_kind = -1;
+ private int[] jj_lasttokens = new int[100];
+ private int jj_endpos;
+
+ private void jj_add_error_token(int kind, int pos) {
+ if (pos >= 100) return;
+ if (pos == jj_endpos + 1) {
+ jj_lasttokens[jj_endpos++] = kind;
+ } else if (jj_endpos != 0) {
+ jj_expentry = new int[jj_endpos];
+ for (int i = 0; i < jj_endpos; i++) {
+ jj_expentry[i] = jj_lasttokens[i];
+ }
+ jj_entries_loop: for (java.util.Iterator<?> it = jj_expentries.iterator(); it.hasNext();) {
+ int[] oldentry = (int[])(it.next());
+ if (oldentry.length == jj_expentry.length) {
+ for (int i = 0; i < jj_expentry.length; i++) {
+ if (oldentry[i] != jj_expentry[i]) {
+ continue jj_entries_loop;
+ }
+ }
+ jj_expentries.add(jj_expentry);
+ break jj_entries_loop;
+ }
+ }
+ if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
+ }
+ }
+
+ /** Generate ParseException. */
+ public ParseException generateParseException() {
+ jj_expentries.clear();
+ boolean[] la1tokens = new boolean[122];
+ if (jj_kind >= 0) {
+ la1tokens[jj_kind] = true;
+ jj_kind = -1;
+ }
+ for (int i = 0; i < 258; i++) {
+ if (jj_la1[i] == jj_gen) {
+ for (int j = 0; j < 32; j++) {
+ if ((jj_la1_0[i] & (1<<j)) != 0) {
+ la1tokens[j] = true;
+ }
+ if ((jj_la1_1[i] & (1<<j)) != 0) {
+ la1tokens[32+j] = true;
+ }
+ if ((jj_la1_2[i] & (1<<j)) != 0) {
+ la1tokens[64+j] = true;
+ }
+ if ((jj_la1_3[i] & (1<<j)) != 0) {
+ la1tokens[96+j] = true;
+ }
+ }
+ }
+ }
+ for (int i = 0; i < 122; i++) {
+ if (la1tokens[i]) {
+ jj_expentry = new int[1];
+ jj_expentry[0] = i;
+ jj_expentries.add(jj_expentry);
+ }
+ }
+ jj_endpos = 0;
+ jj_rescan_token();
+ jj_add_error_token(0, 0);
+ int[][] exptokseq = new int[jj_expentries.size()][];
+ for (int i = 0; i < jj_expentries.size(); i++) {
+ exptokseq[i] = jj_expentries.get(i);
+ }
+ return new ParseException(token, exptokseq, tokenImage);
+ }
+
+ /** Enable tracing. */
+ final public void enable_tracing() {
+ }
+
+ /** Disable tracing. */
+ final public void disable_tracing() {
+ }
+
+ private void jj_rescan_token() {
+ jj_rescan = true;
+ for (int i = 0; i < 9; i++) {
+ try {
+ JJCalls p = jj_2_rtns[i];
+ do {
+ if (p.gen > jj_gen) {
+ jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
+ switch (i) {
+ case 0: jj_3_1(); break;
+ case 1: jj_3_2(); break;
+ case 2: jj_3_3(); break;
+ case 3: jj_3_4(); break;
+ case 4: jj_3_5(); break;
+ case 5: jj_3_6(); break;
+ case 6: jj_3_7(); break;
+ case 7: jj_3_8(); break;
+ case 8: jj_3_9(); break;
+ }
+ }
+ p = p.next;
+ } while (p != null);
+ } catch(LookaheadSuccess ls) { }
+ }
+ jj_rescan = false;
+ }
+
+ private void jj_save(int index, int xla) {
+ JJCalls p = jj_2_rtns[index];
+ while (p.gen > jj_gen) {
+ if (p.next == null) { p = p.next = new JJCalls(); break; }
+ p = p.next;
+ }
+ p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
+ }
+
+ static final class JJCalls {
+ int gen;
+ Token first;
+ int arg;
+ JJCalls next;
+ }
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj
index 840a88e66e..7f86527015 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj
+++ b/theme-compiler/src/com/vaadin/sass/internal/parser/Parser.jj
@@ -534,6 +534,7 @@ TOKEN :
| < LBRACKET : "[" >
| < RBRACKET : "]" >
| < ANY : "*" >
+ | < MOD : "%" >
| < PARENT : "&" >
| < DOT : "." >
| < LPARAN : "(" >
@@ -603,6 +604,7 @@ TOKEN :
| <EXTEND_SYM : "@extend">
| <MOZ_DOCUMENT_SYM : "@-moz-document">
| <SUPPORTS_SYM : "@supports">
+ | <CONTENT_SYM : "@content">
}
< DEFAULT >
@@ -1531,7 +1533,7 @@ void controlDirective() :
void ifContentStatement() :
{}
{
- includeDirective() | media() | extendDirective() | styleRuleOrDeclarationOrNestedProperties()
+ contentDirective() | includeDirective() | media() | extendDirective() | styleRuleOrDeclarationOrNestedProperties()
| keyframes() | LOOKAHEAD(variable()) variable() | listModifyDirective()
}
@@ -1731,8 +1733,13 @@ void includeDirective() :
(<S>)*
(name = property()|name = variableName(){ name = "$"+name;}
|(name = functionName()
- args = argValuelist()) <RPARAN>)(";"(<S>)*)+
+ args = argValuelist()) <RPARAN>)
+ ((";"(<S>)*)+
{documentHandler.includeDirective(name, args);}
+ | <LBRACE> (<S>)* {documentHandler.startIncludeContentBlock(name);}
+ (styleRuleOrDeclarationOrNestedProperties())*
+ <RBRACE> (<S>)* {documentHandler.endIncludeContentBlock();}
+ )
}
String interpolation() :
@@ -1995,6 +2002,15 @@ void extendDirective() :
{documentHandler.extendDirective(list);}
}
+void contentDirective() :
+{}
+{
+ <CONTENT_SYM>
+ (<S>)*
+ (";"(<S>)*)+
+ {documentHandler.contentDirective();}
+}
+
JAVACODE
Node importDirective(){
return null;
@@ -2215,12 +2231,40 @@ boolean guarded() :
LexicalUnitImpl operator(LexicalUnitImpl prev) :
{Token n;}
{
-n="/" ( <S> )* { return LexicalUnitImpl.createSlash(n.beginLine,
- n.beginColumn,
- prev); }
-| n="," ( <S> )* { return LexicalUnitImpl.createComma(n.beginLine,
- n.beginColumn,
- prev); }
+/* (comments copied from basic_arithmetics.scss)
+*supports:
+* 1. standard arithmetic operations (+, -, *, /, %)
+* 2. / is treated as css operator, unless one of its operands is variable or there is another binary arithmetic operator
+*limits:
+* 1. cannot mix arithmetic and css operations, e.g. "margin: 1px + 3px 2px" will fail
+* 2. space between add and minus operator and their following operand is mandatory. e.g. "1 + 2" is valid, "1+2" is not
+* 3. parenthesis is not supported now.
+*/
+n="," ( <S> )* { return LexicalUnitImpl.createComma(n.beginLine,
+ n.beginColumn,
+ prev); }
+|n="/" ( <S> )* { return LexicalUnitImpl.createSlash(n.beginLine,
+ n.beginColumn,
+ prev); }
+| n="*" ( <S> )* { return LexicalUnitImpl.createMultiply(n.beginLine,
+ n.beginColumn,
+ prev); }
+| n="%" ( <S> )* { return LexicalUnitImpl.createModulo(n.beginLine,
+ n.beginColumn,
+ prev); }
+/*
+* for '+', since it can be either a binary operator or an unary operator,
+* which is ambiguous. To avoid this, the binary operator '+' always has
+* a space before the following term. so '2+3' is not a valid binary expression,
+* but '2 + 3' is. The same for '-' operator.
+*/
+
+| n="+" ( <S> )+{ return LexicalUnitImpl.createAdd(n.beginLine,
+ n.beginColumn,
+ prev); }
+| n="-" ( <S> )+{ return LexicalUnitImpl.createMinus(n.beginLine,
+ n.beginColumn,
+ prev); }
}
/**
@@ -2233,7 +2277,7 @@ LexicalUnitImpl expr() :
}
{
first=term(null){ res = first; }
- ( LOOKAHEAD(2) ( res=operator(res) )? res=term(res))*
+ ( LOOKAHEAD(2) ( LOOKAHEAD(2) res=operator(res) )? res=term(res))*
{ return first; }
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/ParserConstants.java b/theme-compiler/src/com/vaadin/sass/internal/parser/ParserConstants.java
index c55a13265f..90fe640f8b 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/parser/ParserConstants.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/parser/ParserConstants.java
@@ -1,289 +1,379 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
/* Generated By:JavaCC: Do not edit this line. ParserConstants.java */
package com.vaadin.sass.internal.parser;
+
/**
- * Token literal values and constants. Generated by
- * org.javacc.parser.OtherFilesGen#start()
+ * Token literal values and constants.
+ * Generated by org.javacc.parser.OtherFilesGen#start()
*/
public interface ParserConstants {
- /** End of File. */
- int EOF = 0;
- /** RegularExpression Id. */
- int S = 1;
- /** RegularExpression Id. */
- int FORMAL_COMMENT = 7;
- /** RegularExpression Id. */
- int MULTI_LINE_COMMENT = 8;
- /** RegularExpression Id. */
- int CDO = 10;
- /** RegularExpression Id. */
- int CDC = 11;
- /** RegularExpression Id. */
- int LBRACE = 12;
- /** RegularExpression Id. */
- int RBRACE = 13;
- /** RegularExpression Id. */
- int DASHMATCH = 14;
- /** RegularExpression Id. */
- int CARETMATCH = 15;
- /** RegularExpression Id. */
- int DOLLARMATCH = 16;
- /** RegularExpression Id. */
- int STARMATCH = 17;
- /** RegularExpression Id. */
- int INCLUDES = 18;
- /** RegularExpression Id. */
- int EQ = 19;
- /** RegularExpression Id. */
- int PLUS = 20;
- /** RegularExpression Id. */
- int MINUS = 21;
- /** RegularExpression Id. */
- int COMMA = 22;
- /** RegularExpression Id. */
- int SEMICOLON = 23;
- /** RegularExpression Id. */
- int PRECEDES = 24;
- /** RegularExpression Id. */
- int SIBLING = 25;
- /** RegularExpression Id. */
- int SUCCEEDS = 26;
- /** RegularExpression Id. */
- int DIV = 27;
- /** RegularExpression Id. */
- int LBRACKET = 28;
- /** RegularExpression Id. */
- int RBRACKET = 29;
- /** RegularExpression Id. */
- int ANY = 30;
- /** RegularExpression Id. */
- int PARENT = 31;
- /** RegularExpression Id. */
- int DOT = 32;
- /** RegularExpression Id. */
- int LPARAN = 33;
- /** RegularExpression Id. */
- int RPARAN = 34;
- /** RegularExpression Id. */
- int COMPARE = 35;
- /** RegularExpression Id. */
- int OR = 36;
- /** RegularExpression Id. */
- int AND = 37;
- /** RegularExpression Id. */
- int NOT_EQ = 38;
- /** RegularExpression Id. */
- int COLON = 39;
- /** RegularExpression Id. */
- int INTERPOLATION = 40;
- /** RegularExpression Id. */
- int NONASCII = 41;
- /** RegularExpression Id. */
- int H = 42;
- /** RegularExpression Id. */
- int UNICODE = 43;
- /** RegularExpression Id. */
- int ESCAPE = 44;
- /** RegularExpression Id. */
- int NMSTART = 45;
- /** RegularExpression Id. */
- int NMCHAR = 46;
- /** RegularExpression Id. */
- int STRINGCHAR = 47;
- /** RegularExpression Id. */
- int D = 48;
- /** RegularExpression Id. */
- int NAME = 49;
- /** RegularExpression Id. */
- int TO = 50;
- /** RegularExpression Id. */
- int THROUGH = 51;
- /** RegularExpression Id. */
- int EACH_IN = 52;
- /** RegularExpression Id. */
- int FROM = 53;
- /** RegularExpression Id. */
- int MIXIN_SYM = 54;
- /** RegularExpression Id. */
- int INCLUDE_SYM = 55;
- /** RegularExpression Id. */
- int FUNCTION_SYM = 56;
- /** RegularExpression Id. */
- int RETURN_SYM = 57;
- /** RegularExpression Id. */
- int DEBUG_SYM = 58;
- /** RegularExpression Id. */
- int WARN_SYM = 59;
- /** RegularExpression Id. */
- int FOR_SYM = 60;
- /** RegularExpression Id. */
- int EACH_SYM = 61;
- /** RegularExpression Id. */
- int WHILE_SYM = 62;
- /** RegularExpression Id. */
- int IF_SYM = 63;
- /** RegularExpression Id. */
- int ELSE_SYM = 64;
- /** RegularExpression Id. */
- int EXTEND_SYM = 65;
- /** RegularExpression Id. */
- int MOZ_DOCUMENT_SYM = 66;
- /** RegularExpression Id. */
- int SUPPORTS_SYM = 67;
- /** RegularExpression Id. */
- int MICROSOFT_RULE = 68;
- /** RegularExpression Id. */
- int IF = 69;
- /** RegularExpression Id. */
- int GUARDED_SYM = 70;
- /** RegularExpression Id. */
- int STRING = 71;
- /** RegularExpression Id. */
- int IDENT = 72;
- /** RegularExpression Id. */
- int NUMBER = 73;
- /** RegularExpression Id. */
- int _URL = 74;
- /** RegularExpression Id. */
- int URL = 75;
- /** RegularExpression Id. */
- int VARIABLE = 76;
- /** RegularExpression Id. */
- int PERCENTAGE = 77;
- /** RegularExpression Id. */
- int PT = 78;
- /** RegularExpression Id. */
- int MM = 79;
- /** RegularExpression Id. */
- int CM = 80;
- /** RegularExpression Id. */
- int PC = 81;
- /** RegularExpression Id. */
- int IN = 82;
- /** RegularExpression Id. */
- int PX = 83;
- /** RegularExpression Id. */
- int EMS = 84;
- /** RegularExpression Id. */
- int LEM = 85;
- /** RegularExpression Id. */
- int REM = 86;
- /** RegularExpression Id. */
- int EXS = 87;
- /** RegularExpression Id. */
- int DEG = 88;
- /** RegularExpression Id. */
- int RAD = 89;
- /** RegularExpression Id. */
- int GRAD = 90;
- /** RegularExpression Id. */
- int MS = 91;
- /** RegularExpression Id. */
- int SECOND = 92;
- /** RegularExpression Id. */
- int HZ = 93;
- /** RegularExpression Id. */
- int KHZ = 94;
- /** RegularExpression Id. */
- int DIMEN = 95;
- /** RegularExpression Id. */
- int HASH = 96;
- /** RegularExpression Id. */
- int IMPORT_SYM = 97;
- /** RegularExpression Id. */
- int MEDIA_SYM = 98;
- /** RegularExpression Id. */
- int CHARSET_SYM = 99;
- /** RegularExpression Id. */
- int PAGE_SYM = 100;
- /** RegularExpression Id. */
- int FONT_FACE_SYM = 101;
- /** RegularExpression Id. */
- int KEY_FRAME_SYM = 102;
- /** RegularExpression Id. */
- int ATKEYWORD = 103;
- /** RegularExpression Id. */
- int IMPORTANT_SYM = 104;
- /** RegularExpression Id. */
- int RANGE0 = 105;
- /** RegularExpression Id. */
- int RANGE1 = 106;
- /** RegularExpression Id. */
- int RANGE2 = 107;
- /** RegularExpression Id. */
- int RANGE3 = 108;
- /** RegularExpression Id. */
- int RANGE4 = 109;
- /** RegularExpression Id. */
- int RANGE5 = 110;
- /** RegularExpression Id. */
- int RANGE6 = 111;
- /** RegularExpression Id. */
- int RANGE = 112;
- /** RegularExpression Id. */
- int UNI = 113;
- /** RegularExpression Id. */
- int UNICODERANGE = 114;
- /** RegularExpression Id. */
- int REMOVE = 115;
- /** RegularExpression Id. */
- int APPEND = 116;
- /** RegularExpression Id. */
- int CONTAINS = 117;
- /** RegularExpression Id. */
- int FUNCTION = 118;
- /** RegularExpression Id. */
- int UNKNOWN = 119;
+ /** End of File. */
+ int EOF = 0;
+ /** RegularExpression Id. */
+ int S = 1;
+ /** RegularExpression Id. */
+ int FORMAL_COMMENT = 7;
+ /** RegularExpression Id. */
+ int MULTI_LINE_COMMENT = 8;
+ /** RegularExpression Id. */
+ int CDO = 10;
+ /** RegularExpression Id. */
+ int CDC = 11;
+ /** RegularExpression Id. */
+ int LBRACE = 12;
+ /** RegularExpression Id. */
+ int RBRACE = 13;
+ /** RegularExpression Id. */
+ int DASHMATCH = 14;
+ /** RegularExpression Id. */
+ int CARETMATCH = 15;
+ /** RegularExpression Id. */
+ int DOLLARMATCH = 16;
+ /** RegularExpression Id. */
+ int STARMATCH = 17;
+ /** RegularExpression Id. */
+ int INCLUDES = 18;
+ /** RegularExpression Id. */
+ int EQ = 19;
+ /** RegularExpression Id. */
+ int PLUS = 20;
+ /** RegularExpression Id. */
+ int MINUS = 21;
+ /** RegularExpression Id. */
+ int COMMA = 22;
+ /** RegularExpression Id. */
+ int SEMICOLON = 23;
+ /** RegularExpression Id. */
+ int PRECEDES = 24;
+ /** RegularExpression Id. */
+ int SIBLING = 25;
+ /** RegularExpression Id. */
+ int SUCCEEDS = 26;
+ /** RegularExpression Id. */
+ int DIV = 27;
+ /** RegularExpression Id. */
+ int LBRACKET = 28;
+ /** RegularExpression Id. */
+ int RBRACKET = 29;
+ /** RegularExpression Id. */
+ int ANY = 30;
+ /** RegularExpression Id. */
+ int MOD = 31;
+ /** RegularExpression Id. */
+ int PARENT = 32;
+ /** RegularExpression Id. */
+ int DOT = 33;
+ /** RegularExpression Id. */
+ int LPARAN = 34;
+ /** RegularExpression Id. */
+ int RPARAN = 35;
+ /** RegularExpression Id. */
+ int COMPARE = 36;
+ /** RegularExpression Id. */
+ int OR = 37;
+ /** RegularExpression Id. */
+ int AND = 38;
+ /** RegularExpression Id. */
+ int NOT_EQ = 39;
+ /** RegularExpression Id. */
+ int COLON = 40;
+ /** RegularExpression Id. */
+ int INTERPOLATION = 41;
+ /** RegularExpression Id. */
+ int NONASCII = 42;
+ /** RegularExpression Id. */
+ int H = 43;
+ /** RegularExpression Id. */
+ int UNICODE = 44;
+ /** RegularExpression Id. */
+ int ESCAPE = 45;
+ /** RegularExpression Id. */
+ int NMSTART = 46;
+ /** RegularExpression Id. */
+ int NMCHAR = 47;
+ /** RegularExpression Id. */
+ int STRINGCHAR = 48;
+ /** RegularExpression Id. */
+ int D = 49;
+ /** RegularExpression Id. */
+ int NAME = 50;
+ /** RegularExpression Id. */
+ int TO = 51;
+ /** RegularExpression Id. */
+ int THROUGH = 52;
+ /** RegularExpression Id. */
+ int EACH_IN = 53;
+ /** RegularExpression Id. */
+ int FROM = 54;
+ /** RegularExpression Id. */
+ int MIXIN_SYM = 55;
+ /** RegularExpression Id. */
+ int INCLUDE_SYM = 56;
+ /** RegularExpression Id. */
+ int FUNCTION_SYM = 57;
+ /** RegularExpression Id. */
+ int RETURN_SYM = 58;
+ /** RegularExpression Id. */
+ int DEBUG_SYM = 59;
+ /** RegularExpression Id. */
+ int WARN_SYM = 60;
+ /** RegularExpression Id. */
+ int FOR_SYM = 61;
+ /** RegularExpression Id. */
+ int EACH_SYM = 62;
+ /** RegularExpression Id. */
+ int WHILE_SYM = 63;
+ /** RegularExpression Id. */
+ int IF_SYM = 64;
+ /** RegularExpression Id. */
+ int ELSE_SYM = 65;
+ /** RegularExpression Id. */
+ int EXTEND_SYM = 66;
+ /** RegularExpression Id. */
+ int MOZ_DOCUMENT_SYM = 67;
+ /** RegularExpression Id. */
+ int SUPPORTS_SYM = 68;
+ /** RegularExpression Id. */
+ int CONTENT_SYM = 69;
+ /** RegularExpression Id. */
+ int MICROSOFT_RULE = 70;
+ /** RegularExpression Id. */
+ int IF = 71;
+ /** RegularExpression Id. */
+ int GUARDED_SYM = 72;
+ /** RegularExpression Id. */
+ int STRING = 73;
+ /** RegularExpression Id. */
+ int IDENT = 74;
+ /** RegularExpression Id. */
+ int NUMBER = 75;
+ /** RegularExpression Id. */
+ int _URL = 76;
+ /** RegularExpression Id. */
+ int URL = 77;
+ /** RegularExpression Id. */
+ int VARIABLE = 78;
+ /** RegularExpression Id. */
+ int PERCENTAGE = 79;
+ /** RegularExpression Id. */
+ int PT = 80;
+ /** RegularExpression Id. */
+ int MM = 81;
+ /** RegularExpression Id. */
+ int CM = 82;
+ /** RegularExpression Id. */
+ int PC = 83;
+ /** RegularExpression Id. */
+ int IN = 84;
+ /** RegularExpression Id. */
+ int PX = 85;
+ /** RegularExpression Id. */
+ int EMS = 86;
+ /** RegularExpression Id. */
+ int LEM = 87;
+ /** RegularExpression Id. */
+ int REM = 88;
+ /** RegularExpression Id. */
+ int EXS = 89;
+ /** RegularExpression Id. */
+ int DEG = 90;
+ /** RegularExpression Id. */
+ int RAD = 91;
+ /** RegularExpression Id. */
+ int GRAD = 92;
+ /** RegularExpression Id. */
+ int MS = 93;
+ /** RegularExpression Id. */
+ int SECOND = 94;
+ /** RegularExpression Id. */
+ int HZ = 95;
+ /** RegularExpression Id. */
+ int KHZ = 96;
+ /** RegularExpression Id. */
+ int DIMEN = 97;
+ /** RegularExpression Id. */
+ int HASH = 98;
+ /** RegularExpression Id. */
+ int IMPORT_SYM = 99;
+ /** RegularExpression Id. */
+ int MEDIA_SYM = 100;
+ /** RegularExpression Id. */
+ int CHARSET_SYM = 101;
+ /** RegularExpression Id. */
+ int PAGE_SYM = 102;
+ /** RegularExpression Id. */
+ int FONT_FACE_SYM = 103;
+ /** RegularExpression Id. */
+ int KEY_FRAME_SYM = 104;
+ /** RegularExpression Id. */
+ int ATKEYWORD = 105;
+ /** RegularExpression Id. */
+ int IMPORTANT_SYM = 106;
+ /** RegularExpression Id. */
+ int RANGE0 = 107;
+ /** RegularExpression Id. */
+ int RANGE1 = 108;
+ /** RegularExpression Id. */
+ int RANGE2 = 109;
+ /** RegularExpression Id. */
+ int RANGE3 = 110;
+ /** RegularExpression Id. */
+ int RANGE4 = 111;
+ /** RegularExpression Id. */
+ int RANGE5 = 112;
+ /** RegularExpression Id. */
+ int RANGE6 = 113;
+ /** RegularExpression Id. */
+ int RANGE = 114;
+ /** RegularExpression Id. */
+ int UNI = 115;
+ /** RegularExpression Id. */
+ int UNICODERANGE = 116;
+ /** RegularExpression Id. */
+ int REMOVE = 117;
+ /** RegularExpression Id. */
+ int APPEND = 118;
+ /** RegularExpression Id. */
+ int CONTAINS = 119;
+ /** RegularExpression Id. */
+ int FUNCTION = 120;
+ /** RegularExpression Id. */
+ int UNKNOWN = 121;
- /** Lexical state. */
- int DEFAULT = 0;
- /** Lexical state. */
- int IN_SINGLE_LINE_COMMENT = 1;
- /** Lexical state. */
- int IN_FORMAL_COMMENT = 2;
- /** Lexical state. */
- int IN_MULTI_LINE_COMMENT = 3;
+ /** Lexical state. */
+ int DEFAULT = 0;
+ /** Lexical state. */
+ int IN_SINGLE_LINE_COMMENT = 1;
+ /** Lexical state. */
+ int IN_FORMAL_COMMENT = 2;
+ /** Lexical state. */
+ int IN_MULTI_LINE_COMMENT = 3;
- /** Literal token values. */
- String[] tokenImage = { "<EOF>", "<S>", "\"//\"", "<token of kind 3>",
- "<token of kind 4>", "<token of kind 5>", "\"/*\"", "\"*/\"",
- "\"*/\"", "<token of kind 9>", "\"<!--\"", "\"-->\"", "\"{\"",
- "\"}\"", "\"|=\"", "\"^=\"", "\"$=\"", "\"*=\"", "\"~=\"", "\"=\"",
- "\"+\"", "\"-\"", "\",\"", "\";\"", "\">\"", "\"~\"", "\"<\"",
- "\"/\"", "\"[\"", "\"]\"", "\"*\"", "\"&\"", "\".\"", "\"(\"",
- "\")\"", "\"==\"", "\"||\"", "\"&&\"", "\"!=\"", "\":\"",
- "<INTERPOLATION>", "<NONASCII>", "<H>", "<UNICODE>", "<ESCAPE>",
- "<NMSTART>", "<NMCHAR>", "<STRINGCHAR>", "<D>", "<NAME>", "\"to\"",
- "\"through\"", "\"in\"", "\"from\"", "\"@mixin\"", "\"@include\"",
- "\"@function\"", "\"@return\"", "\"@debug\"", "\"@warn\"",
- "\"@for\"", "\"@each\"", "\"@while\"", "\"@if\"", "\"@else\"",
- "\"@extend\"", "\"@-moz-document\"", "\"@supports\"",
- "<MICROSOFT_RULE>", "\"if\"", "<GUARDED_SYM>", "<STRING>",
- "<IDENT>", "<NUMBER>", "<_URL>", "<URL>", "<VARIABLE>",
- "<PERCENTAGE>", "<PT>", "<MM>", "<CM>", "<PC>", "<IN>", "<PX>",
- "<EMS>", "<LEM>", "<REM>", "<EXS>", "<DEG>", "<RAD>", "<GRAD>",
- "<MS>", "<SECOND>", "<HZ>", "<KHZ>", "<DIMEN>", "<HASH>",
- "\"@import\"", "\"@media\"", "\"@charset\"", "\"@page\"",
- "\"@font-face\"", "<KEY_FRAME_SYM>", "<ATKEYWORD>",
- "<IMPORTANT_SYM>", "<RANGE0>", "<RANGE1>", "<RANGE2>", "<RANGE3>",
- "<RANGE4>", "<RANGE5>", "<RANGE6>", "<RANGE>", "<UNI>",
- "<UNICODERANGE>", "<REMOVE>", "<APPEND>", "<CONTAINS>",
- "<FUNCTION>", "<UNKNOWN>", };
+ /** Literal token values. */
+ String[] tokenImage = {
+ "<EOF>",
+ "<S>",
+ "\"//\"",
+ "<token of kind 3>",
+ "<token of kind 4>",
+ "<token of kind 5>",
+ "\"/*\"",
+ "\"*/\"",
+ "\"*/\"",
+ "<token of kind 9>",
+ "\"<!--\"",
+ "\"-->\"",
+ "\"{\"",
+ "\"}\"",
+ "\"|=\"",
+ "\"^=\"",
+ "\"$=\"",
+ "\"*=\"",
+ "\"~=\"",
+ "\"=\"",
+ "\"+\"",
+ "\"-\"",
+ "\",\"",
+ "\";\"",
+ "\">\"",
+ "\"~\"",
+ "\"<\"",
+ "\"/\"",
+ "\"[\"",
+ "\"]\"",
+ "\"*\"",
+ "\"%\"",
+ "\"&\"",
+ "\".\"",
+ "\"(\"",
+ "\")\"",
+ "\"==\"",
+ "\"||\"",
+ "\"&&\"",
+ "\"!=\"",
+ "\":\"",
+ "<INTERPOLATION>",
+ "<NONASCII>",
+ "<H>",
+ "<UNICODE>",
+ "<ESCAPE>",
+ "<NMSTART>",
+ "<NMCHAR>",
+ "<STRINGCHAR>",
+ "<D>",
+ "<NAME>",
+ "\"to\"",
+ "\"through\"",
+ "\"in\"",
+ "\"from\"",
+ "\"@mixin\"",
+ "\"@include\"",
+ "\"@function\"",
+ "\"@return\"",
+ "\"@debug\"",
+ "\"@warn\"",
+ "\"@for\"",
+ "\"@each\"",
+ "\"@while\"",
+ "\"@if\"",
+ "\"@else\"",
+ "\"@extend\"",
+ "\"@-moz-document\"",
+ "\"@supports\"",
+ "\"@content\"",
+ "<MICROSOFT_RULE>",
+ "\"if\"",
+ "<GUARDED_SYM>",
+ "<STRING>",
+ "<IDENT>",
+ "<NUMBER>",
+ "<_URL>",
+ "<URL>",
+ "<VARIABLE>",
+ "<PERCENTAGE>",
+ "<PT>",
+ "<MM>",
+ "<CM>",
+ "<PC>",
+ "<IN>",
+ "<PX>",
+ "<EMS>",
+ "<LEM>",
+ "<REM>",
+ "<EXS>",
+ "<DEG>",
+ "<RAD>",
+ "<GRAD>",
+ "<MS>",
+ "<SECOND>",
+ "<HZ>",
+ "<KHZ>",
+ "<DIMEN>",
+ "<HASH>",
+ "\"@import\"",
+ "\"@media\"",
+ "\"@charset\"",
+ "\"@page\"",
+ "\"@font-face\"",
+ "<KEY_FRAME_SYM>",
+ "<ATKEYWORD>",
+ "<IMPORTANT_SYM>",
+ "<RANGE0>",
+ "<RANGE1>",
+ "<RANGE2>",
+ "<RANGE3>",
+ "<RANGE4>",
+ "<RANGE5>",
+ "<RANGE6>",
+ "<RANGE>",
+ "<UNI>",
+ "<UNICODERANGE>",
+ "<REMOVE>",
+ "<APPEND>",
+ "<CONTAINS>",
+ "<FUNCTION>",
+ "<UNKNOWN>",
+ };
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/ParserTokenManager.java b/theme-compiler/src/com/vaadin/sass/internal/parser/ParserTokenManager.java
index 9ff123c808..6271673d5d 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/parser/ParserTokenManager.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/parser/ParserTokenManager.java
@@ -1,6030 +1,5060 @@
-/*
- * Copyright 2000-2013 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
/* Generated By:JavaCC: Do not edit this line. ParserTokenManager.java */
package com.vaadin.sass.internal.parser;
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.Map;
+import java.util.UUID;
+import org.w3c.css.sac.ConditionFactory;
+import org.w3c.css.sac.Condition;
+import org.w3c.css.sac.SelectorFactory;
+import org.w3c.css.sac.SelectorList;
+import org.w3c.css.sac.Selector;
+import org.w3c.css.sac.SimpleSelector;
+import org.w3c.css.sac.DocumentHandler;
+import org.w3c.css.sac.InputSource;
+import org.w3c.css.sac.ErrorHandler;
+import org.w3c.css.sac.CSSException;
+import org.w3c.css.sac.CSSParseException;
+import org.w3c.css.sac.Locator;
+import org.w3c.css.sac.LexicalUnit;
+import org.w3c.flute.parser.selectors.SelectorFactoryImpl;
+import org.w3c.flute.parser.selectors.ConditionFactoryImpl;
+import org.w3c.flute.util.Encoding;
+import com.vaadin.sass.internal.handler.*;
+import com.vaadin.sass.internal.tree.*;
/** Token Manager. */
-public class ParserTokenManager implements ParserConstants {
+public class ParserTokenManager implements ParserConstants
+{
- /** Debug output. */
- public java.io.PrintStream debugStream = System.out;
-
- /** Set debug output. */
- public void setDebugStream(java.io.PrintStream ds) {
- debugStream = ds;
- }
-
- private final int jjStopStringLiteralDfa_0(int pos, long active0,
- long active1) {
- switch (pos) {
- case 0:
- if ((active0 & 0x1c000000000000L) != 0L || (active1 & 0x20L) != 0L) {
- jjmatchedKind = 72;
- return 517;
- }
- if ((active0 & 0x4000000000L) != 0L) {
- return 518;
- }
- if ((active0 & 0x10000L) != 0L) {
- return 79;
- }
- if ((active0 & 0x200800L) != 0L) {
- return 42;
- }
- if ((active0 & 0x20000000000000L) != 0L) {
- jjmatchedKind = 72;
- return 33;
- }
- if ((active0 & 0x8000044L) != 0L) {
- return 3;
- }
- if ((active0 & 0xffc0000000000000L) != 0L
- || (active1 & 0x3e0000000fL) != 0L) {
- return 166;
- }
- if ((active0 & 0x100000000L) != 0L) {
- return 519;
- }
- return -1;
- case 1:
- if ((active1 & 0x4L) != 0L) {
- return 178;
- }
- if ((active0 & 0xffc0000000000000L) != 0L
- || (active1 & 0x3e0000000bL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 1;
- return 520;
- }
- if ((active0 & 0x40L) != 0L) {
- return 1;
- }
- if ((active0 & 0x28000000000000L) != 0L) {
- jjmatchedKind = 72;
- jjmatchedPos = 1;
- return 517;
- }
- if ((active0 & 0x14000000000000L) != 0L || (active1 & 0x20L) != 0L) {
- return 517;
- }
- return -1;
- case 2:
- if ((active0 & 0x7fc0000000000000L) != 0L
- || (active1 & 0x3e0000000bL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 2;
- return 520;
- }
- if ((active0 & 0x8000000000000000L) != 0L) {
- return 520;
- }
- if ((active0 & 0x28000000000000L) != 0L) {
- jjmatchedKind = 72;
- jjmatchedPos = 2;
- return 517;
- }
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 2;
- return 177;
- }
- return -1;
- case 3:
- if ((active0 & 0x6fc0000000000000L) != 0L
- || (active1 & 0x3e0000000bL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 3;
- return 520;
- }
- if ((active0 & 0x1000000000000000L) != 0L) {
- return 520;
- }
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 3;
- return 176;
- }
- if ((active0 & 0x20000000000000L) != 0L) {
- return 517;
- }
- if ((active0 & 0x8000000000000L) != 0L) {
- jjmatchedKind = 72;
- jjmatchedPos = 3;
- return 517;
- }
- return -1;
- case 4:
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 4;
- return 175;
- }
- if ((active0 & 0x8000000000000L) != 0L) {
- jjmatchedKind = 72;
- jjmatchedPos = 4;
- return 517;
- }
- if ((active0 & 0x2800000000000000L) != 0L
- || (active1 & 0x1000000001L) != 0L) {
- return 520;
- }
- if ((active0 & 0x47c0000000000000L) != 0L
- || (active1 & 0x2e0000000aL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 4;
- return 520;
- }
- return -1;
- case 5:
- if ((active0 & 0x4440000000000000L) != 0L
- || (active1 & 0x400000000L) != 0L) {
- return 520;
- }
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 5;
- return 174;
- }
- if ((active0 & 0x380000000000000L) != 0L
- || (active1 & 0x2a0000000aL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 5;
- return 520;
- }
- if ((active0 & 0x8000000000000L) != 0L) {
- jjmatchedKind = 72;
- jjmatchedPos = 5;
- return 517;
- }
- return -1;
- case 6:
- if ((active0 & 0x200000000000000L) != 0L
- || (active1 & 0x200000002L) != 0L) {
- return 520;
- }
- if ((active0 & 0x180000000000000L) != 0L
- || (active1 & 0x280000000cL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 6;
- return 520;
- }
- if ((active0 & 0x8000000000000L) != 0L) {
- return 517;
- }
- return -1;
- case 7:
- if ((active0 & 0x100000000000000L) != 0L
- || (active1 & 0x200000000cL) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 7;
- return 520;
- }
- if ((active0 & 0x80000000000000L) != 0L
- || (active1 & 0x800000000L) != 0L) {
- return 520;
- }
- return -1;
- case 8:
- if ((active1 & 0x2000000004L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 8;
- return 520;
- }
- if ((active0 & 0x100000000000000L) != 0L || (active1 & 0x8L) != 0L) {
- return 520;
- }
- return -1;
- case 9:
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 9;
- return 520;
- }
- if ((active1 & 0x2000000000L) != 0L) {
- return 520;
- }
- return -1;
- case 10:
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 10;
- return 520;
- }
- return -1;
- case 11:
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 11;
- return 520;
- }
- return -1;
- case 12:
- if ((active1 & 0x4L) != 0L) {
- jjmatchedKind = 103;
- jjmatchedPos = 12;
- return 520;
- }
- return -1;
- default:
- return -1;
- }
- }
-
- private final int jjStartNfa_0(int pos, long active0, long active1) {
- return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0, active1),
- pos + 1);
- }
-
- private int jjStopAtPos(int pos, int kind) {
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- return pos + 1;
- }
-
- private int jjMoveStringLiteralDfa0_0() {
- switch (curChar) {
- case 33:
- return jjMoveStringLiteralDfa1_0(0x4000000000L, 0x0L);
- case 36:
- return jjMoveStringLiteralDfa1_0(0x10000L, 0x0L);
- case 38:
- jjmatchedKind = 31;
- return jjMoveStringLiteralDfa1_0(0x2000000000L, 0x0L);
- case 40:
- return jjStopAtPos(0, 33);
- case 41:
- return jjStopAtPos(0, 34);
- case 42:
- jjmatchedKind = 30;
- return jjMoveStringLiteralDfa1_0(0x20000L, 0x0L);
- case 43:
- return jjStopAtPos(0, 20);
- case 44:
- return jjStopAtPos(0, 22);
- case 45:
- jjmatchedKind = 21;
- return jjMoveStringLiteralDfa1_0(0x800L, 0x0L);
- case 46:
- return jjStartNfaWithStates_0(0, 32, 519);
- case 47:
- jjmatchedKind = 27;
- return jjMoveStringLiteralDfa1_0(0x44L, 0x0L);
- case 58:
- return jjStopAtPos(0, 39);
- case 59:
- return jjStopAtPos(0, 23);
- case 60:
- jjmatchedKind = 26;
- return jjMoveStringLiteralDfa1_0(0x400L, 0x0L);
- case 61:
- jjmatchedKind = 19;
- return jjMoveStringLiteralDfa1_0(0x800000000L, 0x0L);
- case 62:
- return jjStopAtPos(0, 24);
- case 64:
- return jjMoveStringLiteralDfa1_0(0xffc0000000000000L, 0x3e0000000fL);
- case 91:
- return jjStopAtPos(0, 28);
- case 93:
- return jjStopAtPos(0, 29);
- case 94:
- return jjMoveStringLiteralDfa1_0(0x8000L, 0x0L);
- case 70:
- case 102:
- return jjMoveStringLiteralDfa1_0(0x20000000000000L, 0x0L);
- case 73:
- case 105:
- return jjMoveStringLiteralDfa1_0(0x10000000000000L, 0x20L);
- case 84:
- case 116:
- return jjMoveStringLiteralDfa1_0(0xc000000000000L, 0x0L);
- case 123:
- return jjStopAtPos(0, 12);
- case 124:
- return jjMoveStringLiteralDfa1_0(0x1000004000L, 0x0L);
- case 125:
- return jjStopAtPos(0, 13);
- case 126:
- jjmatchedKind = 25;
- return jjMoveStringLiteralDfa1_0(0x40000L, 0x0L);
- default:
- return jjMoveNfa_0(4, 0);
- }
- }
-
- private int jjMoveStringLiteralDfa1_0(long active0, long active1) {
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(0, active0, active1);
- return 1;
- }
- switch (curChar) {
- case 33:
- return jjMoveStringLiteralDfa2_0(active0, 0x400L, active1, 0L);
- case 38:
- if ((active0 & 0x2000000000L) != 0L) {
- return jjStopAtPos(1, 37);
- }
- break;
- case 42:
- if ((active0 & 0x40L) != 0L) {
- return jjStartNfaWithStates_0(1, 6, 1);
- }
- break;
- case 45:
- return jjMoveStringLiteralDfa2_0(active0, 0x800L, active1, 0x4L);
- case 47:
- if ((active0 & 0x4L) != 0L) {
- return jjStopAtPos(1, 2);
- }
- break;
- case 61:
- if ((active0 & 0x4000L) != 0L) {
- return jjStopAtPos(1, 14);
- } else if ((active0 & 0x8000L) != 0L) {
- return jjStopAtPos(1, 15);
- } else if ((active0 & 0x10000L) != 0L) {
- return jjStopAtPos(1, 16);
- } else if ((active0 & 0x20000L) != 0L) {
- return jjStopAtPos(1, 17);
- } else if ((active0 & 0x40000L) != 0L) {
- return jjStopAtPos(1, 18);
- } else if ((active0 & 0x800000000L) != 0L) {
- return jjStopAtPos(1, 35);
- } else if ((active0 & 0x4000000000L) != 0L) {
- return jjStopAtPos(1, 38);
- }
- break;
- case 67:
- case 99:
- return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x800000000L);
- case 68:
- case 100:
- return jjMoveStringLiteralDfa2_0(active0, 0x400000000000000L,
- active1, 0L);
- case 69:
- case 101:
- return jjMoveStringLiteralDfa2_0(active0, 0x2000000000000000L,
- active1, 0x3L);
- case 70:
- case 102:
- if ((active1 & 0x20L) != 0L) {
- return jjStartNfaWithStates_0(1, 69, 517);
- }
- return jjMoveStringLiteralDfa2_0(active0, 0x1100000000000000L,
- active1, 0x2000000000L);
- case 72:
- case 104:
- return jjMoveStringLiteralDfa2_0(active0, 0x8000000000000L,
- active1, 0L);
- case 73:
- case 105:
- return jjMoveStringLiteralDfa2_0(active0, 0x8080000000000000L,
- active1, 0x200000000L);
- case 77:
- case 109:
- return jjMoveStringLiteralDfa2_0(active0, 0x40000000000000L,
- active1, 0x400000000L);
- case 78:
- case 110:
- if ((active0 & 0x10000000000000L) != 0L) {
- return jjStartNfaWithStates_0(1, 52, 517);
- }
- break;
- case 79:
- case 111:
- if ((active0 & 0x4000000000000L) != 0L) {
- return jjStartNfaWithStates_0(1, 50, 517);
- }
- break;
- case 80:
- case 112:
- return jjMoveStringLiteralDfa2_0(active0, 0L, active1,
- 0x1000000000L);
- case 82:
- case 114:
- return jjMoveStringLiteralDfa2_0(active0, 0x220000000000000L,
- active1, 0L);
- case 83:
- case 115:
- return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x8L);
- case 87:
- case 119:
- return jjMoveStringLiteralDfa2_0(active0, 0x4800000000000000L,
- active1, 0L);
- case 124:
- if ((active0 & 0x1000000000L) != 0L) {
- return jjStopAtPos(1, 36);
- }
- break;
- default:
- break;
- }
- return jjStartNfa_0(0, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa2_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(0, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(1, active0, active1);
- return 2;
- }
- switch (curChar) {
- case 45:
- return jjMoveStringLiteralDfa3_0(active0, 0x400L, active1, 0L);
- case 62:
- if ((active0 & 0x800L) != 0L) {
- return jjStopAtPos(2, 11);
- }
- break;
- case 65:
- case 97:
- return jjMoveStringLiteralDfa3_0(active0, 0x2800000000000000L,
- active1, 0x1000000000L);
- case 69:
- case 101:
- return jjMoveStringLiteralDfa3_0(active0, 0x600000000000000L,
- active1, 0x400000000L);
- case 70:
- case 102:
- if ((active0 & 0x8000000000000000L) != 0L) {
- return jjStartNfaWithStates_0(2, 63, 520);
- }
- break;
- case 72:
- case 104:
- return jjMoveStringLiteralDfa3_0(active0, 0x4000000000000000L,
- active1, 0x800000000L);
- case 73:
- case 105:
- return jjMoveStringLiteralDfa3_0(active0, 0x40000000000000L,
- active1, 0L);
- case 76:
- case 108:
- return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x1L);
- case 77:
- case 109:
- return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x200000004L);
- case 78:
- case 110:
- return jjMoveStringLiteralDfa3_0(active0, 0x80000000000000L,
- active1, 0L);
- case 79:
- case 111:
- return jjMoveStringLiteralDfa3_0(active0, 0x1020000000000000L,
- active1, 0x2000000000L);
- case 82:
- case 114:
- return jjMoveStringLiteralDfa3_0(active0, 0x8000000000000L,
- active1, 0L);
- case 85:
- case 117:
- return jjMoveStringLiteralDfa3_0(active0, 0x100000000000000L,
- active1, 0x8L);
- case 88:
- case 120:
- return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x2L);
- default:
- break;
- }
- return jjStartNfa_0(1, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa3_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(1, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(2, active0, active1);
+ /** Debug output. */
+ public java.io.PrintStream debugStream = System.out;
+ /** Set debug output. */
+ public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
+private final int jjStopStringLiteralDfa_0(int pos, long active0, long active1)
+{
+ switch (pos)
+ {
+ case 0:
+ if ((active0 & 0x40000000000000L) != 0L)
+ {
+ jjmatchedKind = 74;
+ return 33;
+ }
+ if ((active0 & 0x8000000000L) != 0L)
+ return 517;
+ if ((active0 & 0x10000L) != 0L)
+ return 79;
+ if ((active0 & 0x200800L) != 0L)
+ return 42;
+ if ((active0 & 0x8000044L) != 0L)
return 3;
- }
- switch (curChar) {
- case 45:
- if ((active0 & 0x400L) != 0L) {
- return jjStopAtPos(3, 10);
- }
- break;
- case 65:
- case 97:
- return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x800000000L);
- case 66:
- case 98:
- return jjMoveStringLiteralDfa4_0(active0, 0x400000000000000L,
- active1, 0L);
- case 67:
- case 99:
- return jjMoveStringLiteralDfa4_0(active0, 0x2080000000000000L,
- active1, 0L);
- case 68:
- case 100:
- return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x400000000L);
- case 71:
- case 103:
- return jjMoveStringLiteralDfa4_0(active0, 0L, active1,
- 0x1000000000L);
- case 73:
- case 105:
- return jjMoveStringLiteralDfa4_0(active0, 0x4000000000000000L,
- active1, 0L);
- case 77:
- case 109:
- if ((active0 & 0x20000000000000L) != 0L) {
- return jjStartNfaWithStates_0(3, 53, 517);
- }
- break;
- case 78:
- case 110:
- return jjMoveStringLiteralDfa4_0(active0, 0x100000000000000L,
- active1, 0x2000000000L);
- case 79:
- case 111:
- return jjMoveStringLiteralDfa4_0(active0, 0x8000000000000L,
- active1, 0x4L);
- case 80:
- case 112:
- return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x200000008L);
- case 82:
- case 114:
- if ((active0 & 0x1000000000000000L) != 0L) {
- return jjStartNfaWithStates_0(3, 60, 520);
- }
- return jjMoveStringLiteralDfa4_0(active0, 0x800000000000000L,
- active1, 0L);
- case 83:
- case 115:
- return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x1L);
- case 84:
- case 116:
- return jjMoveStringLiteralDfa4_0(active0, 0x200000000000000L,
- active1, 0x2L);
- case 88:
- case 120:
- return jjMoveStringLiteralDfa4_0(active0, 0x40000000000000L,
- active1, 0L);
- default:
- break;
- }
- return jjStartNfa_0(2, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa4_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(2, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(3, active0, active1);
- return 4;
- }
- switch (curChar) {
- case 67:
- case 99:
- return jjMoveStringLiteralDfa5_0(active0, 0x100000000000000L,
- active1, 0L);
- case 69:
- case 101:
- if ((active1 & 0x1L) != 0L) {
- return jjStartNfaWithStates_0(4, 64, 520);
- } else if ((active1 & 0x1000000000L) != 0L) {
- return jjStartNfaWithStates_0(4, 100, 520);
- }
- return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x2L);
- case 72:
- case 104:
- if ((active0 & 0x2000000000000000L) != 0L) {
- return jjStartNfaWithStates_0(4, 61, 520);
- }
- break;
- case 73:
- case 105:
- return jjMoveStringLiteralDfa5_0(active0, 0x40000000000000L,
- active1, 0x400000000L);
- case 76:
- case 108:
- return jjMoveStringLiteralDfa5_0(active0, 0x4080000000000000L,
- active1, 0L);
- case 78:
- case 110:
- if ((active0 & 0x800000000000000L) != 0L) {
- return jjStartNfaWithStates_0(4, 59, 520);
- }
- break;
- case 79:
- case 111:
- return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x200000000L);
- case 80:
- case 112:
- return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x8L);
- case 82:
- case 114:
- return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x800000000L);
- case 84:
- case 116:
- return jjMoveStringLiteralDfa5_0(active0, 0L, active1,
- 0x2000000000L);
- case 85:
- case 117:
- return jjMoveStringLiteralDfa5_0(active0, 0x608000000000000L,
- active1, 0L);
- case 90:
- case 122:
- return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x4L);
- default:
- break;
- }
- return jjStartNfa_0(3, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa5_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(3, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(4, active0, active1);
- return 5;
- }
- switch (curChar) {
- case 45:
- return jjMoveStringLiteralDfa6_0(active0, 0L, active1,
- 0x2000000004L);
- case 65:
- case 97:
- if ((active1 & 0x400000000L) != 0L) {
- return jjStartNfaWithStates_0(5, 98, 520);
- }
- break;
- case 69:
- case 101:
- if ((active0 & 0x4000000000000000L) != 0L) {
- return jjStartNfaWithStates_0(5, 62, 520);
- }
- break;
- case 71:
- case 103:
- if ((active0 & 0x400000000000000L) != 0L) {
- return jjStartNfaWithStates_0(5, 58, 520);
- }
- return jjMoveStringLiteralDfa6_0(active0, 0x8000000000000L,
- active1, 0L);
- case 78:
- case 110:
- if ((active0 & 0x40000000000000L) != 0L) {
- return jjStartNfaWithStates_0(5, 54, 520);
- }
- return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x2L);
- case 79:
- case 111:
- return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x8L);
- case 82:
- case 114:
- return jjMoveStringLiteralDfa6_0(active0, 0x200000000000000L,
- active1, 0x200000000L);
- case 83:
- case 115:
- return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x800000000L);
- case 84:
- case 116:
- return jjMoveStringLiteralDfa6_0(active0, 0x100000000000000L,
- active1, 0L);
- case 85:
- case 117:
- return jjMoveStringLiteralDfa6_0(active0, 0x80000000000000L,
- active1, 0L);
- default:
- break;
- }
- return jjStartNfa_0(4, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa6_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(4, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(5, active0, active1);
- return 6;
- }
- switch (curChar) {
- case 68:
- case 100:
- if ((active1 & 0x2L) != 0L) {
- return jjStartNfaWithStates_0(6, 65, 520);
- }
- return jjMoveStringLiteralDfa7_0(active0, 0x80000000000000L,
- active1, 0x4L);
- case 69:
- case 101:
- return jjMoveStringLiteralDfa7_0(active0, 0L, active1, 0x800000000L);
- case 70:
- case 102:
- return jjMoveStringLiteralDfa7_0(active0, 0L, active1,
- 0x2000000000L);
- case 72:
- case 104:
- if ((active0 & 0x8000000000000L) != 0L) {
- return jjStartNfaWithStates_0(6, 51, 517);
- }
- break;
- case 73:
- case 105:
- return jjMoveStringLiteralDfa7_0(active0, 0x100000000000000L,
- active1, 0L);
- case 78:
- case 110:
- if ((active0 & 0x200000000000000L) != 0L) {
- return jjStartNfaWithStates_0(6, 57, 520);
- }
- break;
- case 82:
- case 114:
- return jjMoveStringLiteralDfa7_0(active0, 0L, active1, 0x8L);
- case 84:
- case 116:
- if ((active1 & 0x200000000L) != 0L) {
- return jjStartNfaWithStates_0(6, 97, 520);
- }
- break;
- default:
- break;
- }
- return jjStartNfa_0(5, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa7_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(5, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(6, active0, active1);
- return 7;
- }
- switch (curChar) {
- case 65:
- case 97:
- return jjMoveStringLiteralDfa8_0(active0, 0L, active1,
- 0x2000000000L);
- case 69:
- case 101:
- if ((active0 & 0x80000000000000L) != 0L) {
- return jjStartNfaWithStates_0(7, 55, 520);
- }
- break;
- case 79:
- case 111:
- return jjMoveStringLiteralDfa8_0(active0, 0x100000000000000L,
- active1, 0x4L);
- case 84:
- case 116:
- if ((active1 & 0x800000000L) != 0L) {
- return jjStartNfaWithStates_0(7, 99, 520);
- }
- return jjMoveStringLiteralDfa8_0(active0, 0L, active1, 0x8L);
- default:
- break;
- }
- return jjStartNfa_0(6, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa8_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(6, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(7, active0, active1);
- return 8;
- }
- switch (curChar) {
- case 67:
- case 99:
- return jjMoveStringLiteralDfa9_0(active0, 0L, active1,
- 0x2000000004L);
- case 78:
- case 110:
- if ((active0 & 0x100000000000000L) != 0L) {
- return jjStartNfaWithStates_0(8, 56, 520);
- }
- break;
- case 83:
- case 115:
- if ((active1 & 0x8L) != 0L) {
- return jjStartNfaWithStates_0(8, 67, 520);
- }
- break;
- default:
- break;
- }
- return jjStartNfa_0(7, active0, active1);
- }
-
- private int jjMoveStringLiteralDfa9_0(long old0, long active0, long old1,
- long active1) {
- if (((active0 &= old0) | (active1 &= old1)) == 0L) {
- return jjStartNfa_0(7, old0, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(8, 0L, active1);
- return 9;
- }
- switch (curChar) {
- case 69:
- case 101:
- if ((active1 & 0x2000000000L) != 0L) {
- return jjStartNfaWithStates_0(9, 101, 520);
- }
- break;
- case 85:
- case 117:
- return jjMoveStringLiteralDfa10_0(active1, 0x4L);
- default:
- break;
- }
- return jjStartNfa_0(8, 0L, active1);
- }
-
- private int jjMoveStringLiteralDfa10_0(long old1, long active1) {
- if (((active1 &= old1)) == 0L) {
- return jjStartNfa_0(8, 0L, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(9, 0L, active1);
- return 10;
- }
- switch (curChar) {
- case 77:
- case 109:
- return jjMoveStringLiteralDfa11_0(active1, 0x4L);
- default:
- break;
- }
- return jjStartNfa_0(9, 0L, active1);
- }
-
- private int jjMoveStringLiteralDfa11_0(long old1, long active1) {
- if (((active1 &= old1)) == 0L) {
- return jjStartNfa_0(9, 0L, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(10, 0L, active1);
- return 11;
- }
- switch (curChar) {
- case 69:
- case 101:
- return jjMoveStringLiteralDfa12_0(active1, 0x4L);
- default:
- break;
- }
- return jjStartNfa_0(10, 0L, active1);
- }
-
- private int jjMoveStringLiteralDfa12_0(long old1, long active1) {
- if (((active1 &= old1)) == 0L) {
- return jjStartNfa_0(10, 0L, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(11, 0L, active1);
- return 12;
- }
- switch (curChar) {
- case 78:
- case 110:
- return jjMoveStringLiteralDfa13_0(active1, 0x4L);
- default:
- break;
- }
- return jjStartNfa_0(11, 0L, active1);
- }
-
- private int jjMoveStringLiteralDfa13_0(long old1, long active1) {
- if (((active1 &= old1)) == 0L) {
- return jjStartNfa_0(11, 0L, old1);
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- jjStopStringLiteralDfa_0(12, 0L, active1);
- return 13;
- }
- switch (curChar) {
- case 84:
- case 116:
- if ((active1 & 0x4L) != 0L) {
- return jjStartNfaWithStates_0(13, 66, 520);
- }
- break;
- default:
- break;
- }
- return jjStartNfa_0(12, 0L, active1);
- }
-
- private int jjStartNfaWithStates_0(int pos, int kind, int state) {
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- return pos + 1;
- }
- return jjMoveNfa_0(state, pos + 1);
- }
-
- static final long[] jjbitVec0 = { 0x0L, 0x0L, 0xffffffffffffffffL,
- 0xffffffffffffffffL };
-
- private int jjMoveNfa_0(int startState, int curPos) {
- int startsAt = 0;
- jjnewStateCnt = 517;
- int i = 1;
- jjstateSet[0] = startState;
- int kind = 0x7fffffff;
- for (;;) {
- if (++jjround == 0x7fffffff) {
- ReInitRounds();
- }
- if (curChar < 64) {
- long l = 1L << curChar;
- do {
- switch (jjstateSet[--i]) {
- case 520:
- case 113:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 166:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 112;
- }
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 217;
- }
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 205;
- }
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 189;
- }
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 178;
- }
- break;
- case 174:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 4:
- if ((0x3ff000000000000L & l) != 0L) {
- if (kind > 73) {
- kind = 73;
- }
- jjCheckNAddStates(0, 81);
- } else if ((0x100003600L & l) != 0L) {
- if (kind > 1) {
- kind = 1;
- }
- jjCheckNAdd(0);
- } else if (curChar == 46) {
- jjCheckNAddStates(82, 101);
- } else if (curChar == 45) {
- jjAddStates(102, 103);
- } else if (curChar == 33) {
- jjCheckNAddStates(104, 107);
- } else if (curChar == 35) {
- jjCheckNAddTwoStates(100, 101);
- } else if (curChar == 36) {
- jjCheckNAddStates(108, 111);
- } else if (curChar == 39) {
- jjCheckNAddStates(112, 115);
- } else if (curChar == 34) {
- jjCheckNAddStates(116, 119);
- } else if (curChar == 47) {
- jjstateSet[jjnewStateCnt++] = 3;
- }
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 42;
- } else if (curChar == 35) {
- jjstateSet[jjnewStateCnt++] = 5;
- }
- break;
- case 518:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(251, 260);
- }
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(243, 250);
- }
- break;
- case 517:
- if ((0x3ff200000000000L & l) != 0L) {
- jjCheckNAddStates(120, 123);
- } else if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(231, 232);
- } else if (curChar == 40) {
- if (kind > 118) {
- kind = 118;
- }
- }
- if ((0x3ff200000000000L & l) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- }
- break;
- case 175:
- if ((0x3ff200000000000L & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- }
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 174;
- }
- break;
- case 33:
- if ((0x3ff200000000000L & l) != 0L) {
- jjCheckNAddStates(120, 123);
- } else if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(231, 232);
- } else if (curChar == 40) {
- if (kind > 118) {
- kind = 118;
- }
- }
- if ((0x3ff200000000000L & l) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- }
- break;
- case 176:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 519:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(124, 128);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(322, 325);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(319, 321);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(317, 318);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(314, 316);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(309, 313);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(305, 308);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(301, 304);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(298, 300);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(294, 297);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(290, 293);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(287, 289);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(284, 286);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(281, 283);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(278, 280);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(275, 277);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(272, 274);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(269, 271);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(267, 268);
- }
- if ((0x3ff000000000000L & l) != 0L) {
- if (kind > 73) {
- kind = 73;
- }
- jjCheckNAdd(266);
- }
- break;
- case 177:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 79:
- if (curChar == 45) {
- jjCheckNAdd(80);
- }
- break;
- case 0:
- if ((0x100003600L & l) == 0L) {
- break;
- }
- if (kind > 1) {
- kind = 1;
- }
- jjCheckNAdd(0);
- break;
- case 1:
- if (curChar == 42) {
- jjstateSet[jjnewStateCnt++] = 2;
- }
- break;
- case 2:
- if ((0xffff7fffffffffffL & l) != 0L && kind > 5) {
- kind = 5;
- }
- break;
- case 3:
- if (curChar == 42) {
- jjstateSet[jjnewStateCnt++] = 1;
- }
- break;
- case 6:
- if (curChar == 36) {
- jjCheckNAddStates(129, 132);
- }
- break;
- case 7:
- if (curChar == 45) {
- jjCheckNAdd(8);
- }
- break;
- case 9:
- if ((0x3ff200000000000L & l) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 12:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 13:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(136, 140);
- }
- break;
- case 14:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 15:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(141, 148);
- }
- break;
- case 16:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(149, 152);
- }
- break;
- case 17:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(153, 157);
- }
- break;
- case 18:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(158, 163);
- }
- break;
- case 19:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(164, 170);
- }
- break;
- case 22:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(171, 175);
- }
- break;
- case 23:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(176, 183);
- }
- break;
- case 24:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(184, 187);
- }
- break;
- case 25:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(188, 192);
- }
- break;
- case 26:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(193, 198);
- }
- break;
- case 27:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(199, 205);
- }
- break;
- case 28:
- if (curChar == 35) {
- jjstateSet[jjnewStateCnt++] = 5;
- }
- break;
- case 40:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 39;
- }
- break;
- case 43:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 42;
- }
- break;
- case 44:
- if (curChar == 34) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 45:
- if ((0xfffffffb00000200L & l) != 0L) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 46:
- if (curChar == 34 && kind > 71) {
- kind = 71;
- }
- break;
- case 48:
- if (curChar == 12) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 50:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 51:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(206, 211);
- }
- break;
- case 52:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 53:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(212, 220);
- }
- break;
- case 54:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(221, 225);
- }
- break;
- case 55:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(226, 231);
- }
- break;
- case 56:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(232, 238);
- }
- break;
- case 57:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(239, 246);
- }
- break;
- case 58:
- if (curChar == 13) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 59:
- if (curChar == 10) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 60:
- if (curChar == 13) {
- jjstateSet[jjnewStateCnt++] = 59;
- }
- break;
- case 61:
- if (curChar == 39) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 62:
- if ((0xffffff7f00000200L & l) != 0L) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 63:
- if (curChar == 39 && kind > 71) {
- kind = 71;
- }
- break;
- case 65:
- if (curChar == 12) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 67:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 68:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(247, 252);
- }
- break;
- case 69:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 70:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(253, 261);
- }
- break;
- case 71:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(262, 266);
- }
- break;
- case 72:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(267, 272);
- }
- break;
- case 73:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(273, 279);
- }
- break;
- case 74:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(280, 287);
- }
- break;
- case 75:
- if (curChar == 13) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 76:
- if (curChar == 10) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 77:
- if (curChar == 13) {
- jjstateSet[jjnewStateCnt++] = 76;
- }
- break;
- case 78:
- if (curChar == 36) {
- jjCheckNAddStates(108, 111);
- }
- break;
- case 81:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 83:
- if ((0xffffffff00000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 84:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(288, 291);
- break;
- case 85:
- if ((0x100003600L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 86:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(292, 298);
- break;
- case 87:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(299, 301);
- break;
- case 88:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(302, 305);
- break;
- case 89:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(306, 310);
- break;
- case 90:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(311, 316);
- break;
- case 93:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(317, 320);
- break;
- case 94:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(321, 327);
- break;
- case 95:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(328, 330);
- break;
- case 96:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(331, 334);
- break;
- case 97:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(335, 339);
- break;
- case 98:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(340, 345);
- break;
- case 99:
- if (curChar == 35) {
- jjCheckNAddTwoStates(100, 101);
- }
- break;
- case 100:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddTwoStates(100, 101);
- break;
- case 102:
- if ((0xffffffff00000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddTwoStates(100, 101);
- break;
- case 103:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(346, 349);
- break;
- case 104:
- if ((0x100003600L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddTwoStates(100, 101);
- break;
- case 105:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(350, 356);
- break;
- case 106:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(357, 359);
- break;
- case 107:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(360, 363);
- break;
- case 108:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(364, 368);
- break;
- case 109:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(369, 374);
- break;
- case 111:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 112;
- }
- break;
- case 115:
- if ((0xffffffff00000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 116:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(375, 378);
- break;
- case 117:
- if ((0x100003600L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 118:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(379, 385);
- break;
- case 119:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(386, 388);
- break;
- case 120:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(389, 392);
- break;
- case 121:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(393, 397);
- break;
- case 122:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(398, 403);
- break;
- case 125:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(404, 407);
- break;
- case 126:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(408, 414);
- break;
- case 127:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(415, 417);
- break;
- case 128:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(418, 421);
- break;
- case 129:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(422, 426);
- break;
- case 130:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(427, 432);
- break;
- case 132:
- if ((0x100003600L & l) != 0L) {
- jjAddStates(433, 434);
- }
- break;
- case 133:
- if (curChar == 40 && kind > 115) {
- kind = 115;
- }
- break;
- case 140:
- if ((0x100003600L & l) != 0L) {
- jjAddStates(435, 436);
- }
- break;
- case 141:
- if (curChar == 40 && kind > 116) {
- kind = 116;
- }
- break;
- case 148:
- if ((0x100003600L & l) != 0L) {
- jjAddStates(437, 438);
- }
- break;
- case 149:
- if (curChar == 40 && kind > 117) {
- kind = 117;
- }
- break;
- case 179:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 178;
- }
- break;
- case 188:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 187;
- }
- break;
- case 190:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 189;
- }
- break;
- case 199:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 198;
- }
- break;
- case 206:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 205;
- }
- break;
- case 215:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 214;
- }
- break;
- case 218:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 217;
- }
- break;
- case 220:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 222:
- if ((0xffffffff00000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 223:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(439, 442);
- break;
- case 224:
- if ((0x100003600L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 225:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(443, 449);
- break;
- case 226:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(450, 452);
- break;
- case 227:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(453, 456);
- break;
- case 228:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(457, 461);
- break;
- case 229:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(462, 467);
- break;
- case 230:
- if ((0x3ff200000000000L & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 231:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(231, 232);
- }
- break;
- case 232:
- if (curChar == 40 && kind > 118) {
- kind = 118;
- }
- break;
- case 234:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 235:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(468, 472);
- }
- break;
- case 236:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 237:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(473, 480);
- }
- break;
- case 238:
- case 452:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(481, 484);
- }
- break;
- case 239:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(485, 489);
- }
- break;
- case 240:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(490, 495);
- }
- break;
- case 241:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(496, 502);
- }
- break;
- case 242:
- if (curChar == 33) {
- jjCheckNAddStates(104, 107);
- }
- break;
- case 243:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(243, 250);
- }
- break;
- case 251:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(251, 260);
- }
- break;
- case 261:
- if (curChar == 45) {
- jjAddStates(102, 103);
- }
- break;
- case 265:
- if (curChar == 46) {
- jjCheckNAddStates(82, 101);
- }
- break;
- case 266:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 73) {
- kind = 73;
- }
- jjCheckNAdd(266);
- break;
- case 267:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(267, 268);
- }
- break;
- case 268:
- if (curChar == 37 && kind > 77) {
- kind = 77;
- }
- break;
- case 269:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(269, 271);
- }
- break;
- case 272:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(272, 274);
- }
- break;
- case 275:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(275, 277);
- }
- break;
- case 278:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(278, 280);
- }
- break;
- case 281:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(281, 283);
- }
- break;
- case 284:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(284, 286);
- }
- break;
- case 287:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(287, 289);
- }
- break;
- case 290:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(290, 293);
- }
- break;
- case 294:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(294, 297);
- }
- break;
- case 298:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(298, 300);
- }
- break;
- case 301:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(301, 304);
- }
- break;
- case 305:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(305, 308);
- }
- break;
- case 309:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(309, 313);
- }
- break;
- case 314:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(314, 316);
- }
- break;
- case 317:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(317, 318);
- }
- break;
- case 319:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(319, 321);
- }
- break;
- case 322:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(322, 325);
- }
- break;
- case 326:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(124, 128);
- }
- break;
- case 327:
- if (curChar == 45) {
- jjCheckNAdd(328);
- }
- break;
- case 329:
- if ((0x3ff200000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 331:
- if ((0xffffffff00000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 332:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(503, 506);
- break;
- case 333:
- if ((0x100003600L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 334:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(507, 513);
- break;
- case 335:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(514, 516);
- break;
- case 336:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(517, 520);
- break;
- case 337:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(521, 525);
- break;
- case 338:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(526, 531);
- break;
- case 341:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(532, 535);
- break;
- case 342:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(536, 542);
- break;
- case 343:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(543, 545);
- break;
- case 344:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(546, 549);
- break;
- case 345:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(550, 554);
- break;
- case 346:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(555, 560);
- break;
- case 348:
- if (curChar == 40) {
- jjCheckNAddStates(561, 566);
- }
- break;
- case 349:
- if ((0xfffffc7a00000000L & l) != 0L) {
- jjCheckNAddStates(567, 570);
- }
- break;
- case 350:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddTwoStates(350, 351);
- }
- break;
- case 351:
- if (curChar == 41 && kind > 75) {
- kind = 75;
- }
- break;
- case 353:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(567, 570);
- }
- break;
- case 354:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(571, 575);
- }
- break;
- case 355:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(567, 570);
- }
- break;
- case 356:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(576, 583);
- }
- break;
- case 357:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(584, 587);
- }
- break;
- case 358:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(588, 592);
- }
- break;
- case 359:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(593, 598);
- }
- break;
- case 360:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(599, 605);
- }
- break;
- case 361:
- if (curChar == 39) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 362:
- if ((0xffffff7f00000200L & l) != 0L) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 363:
- if (curChar == 39) {
- jjCheckNAddTwoStates(350, 351);
- }
- break;
- case 365:
- if (curChar == 12) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 367:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 368:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(610, 615);
- }
- break;
- case 369:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 370:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(616, 624);
- }
- break;
- case 371:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(625, 629);
- }
- break;
- case 372:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(630, 635);
- }
- break;
- case 373:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(636, 642);
- }
- break;
- case 374:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(643, 650);
- }
- break;
- case 375:
- if (curChar == 13) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 376:
- if (curChar == 10) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 377:
- if (curChar == 13) {
- jjstateSet[jjnewStateCnt++] = 376;
- }
- break;
- case 378:
- if (curChar == 34) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 379:
- if ((0xfffffffb00000200L & l) != 0L) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 380:
- if (curChar == 34) {
- jjCheckNAddTwoStates(350, 351);
- }
- break;
- case 382:
- if (curChar == 12) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 384:
- if ((0xffffffff00000000L & l) != 0L) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 385:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(655, 660);
- }
- break;
- case 386:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 387:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(661, 669);
- }
- break;
- case 388:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(670, 674);
- }
- break;
- case 389:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(675, 680);
- }
- break;
- case 390:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(681, 687);
- }
- break;
- case 391:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(688, 695);
- }
- break;
- case 392:
- if (curChar == 13) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 393:
- if (curChar == 10) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 394:
- if (curChar == 13) {
- jjstateSet[jjnewStateCnt++] = 393;
- }
- break;
- case 395:
- if ((0x100003600L & l) != 0L) {
- jjCheckNAddStates(696, 702);
- }
- break;
- case 398:
- if (curChar == 43) {
- jjAddStates(703, 704);
- }
- break;
- case 399:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 400;
- break;
- case 400:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(705, 708);
- break;
- case 401:
- if (curChar == 63 && kind > 114) {
- kind = 114;
- }
- break;
- case 402:
- case 417:
- case 421:
- case 424:
- case 427:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAdd(401);
- break;
- case 403:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddTwoStates(401, 402);
- break;
- case 404:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(709, 711);
- break;
- case 405:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjAddStates(712, 717);
- break;
- case 406:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 407;
- }
- break;
- case 407:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 408;
- }
- break;
- case 408:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAdd(409);
- }
- break;
- case 409:
- if ((0x3ff000000000000L & l) != 0L && kind > 114) {
- kind = 114;
- }
- break;
- case 410:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 411;
- }
- break;
- case 411:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 412;
- }
- break;
- case 412:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 413;
- }
- break;
- case 413:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAdd(401);
- break;
- case 414:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 415;
- }
- break;
- case 415:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 416;
- }
- break;
- case 416:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 417;
- break;
- case 418:
- if ((0x3ff000000000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 419;
- }
- break;
- case 419:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 420;
- break;
- case 420:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddTwoStates(401, 421);
- break;
- case 422:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 423;
- break;
- case 423:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(718, 720);
- break;
- case 425:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddTwoStates(401, 424);
- break;
- case 426:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(721, 724);
- break;
- case 428:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddTwoStates(401, 427);
- break;
- case 429:
- if (curChar != 63) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(725, 727);
- break;
- case 430:
- if (curChar == 43) {
- jjstateSet[jjnewStateCnt++] = 431;
- }
- break;
- case 431:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(432, 438);
- }
- break;
- case 432:
- if (curChar == 45) {
- jjstateSet[jjnewStateCnt++] = 433;
- }
- break;
- case 433:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 434;
- break;
- case 434:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(728, 731);
- break;
- case 435:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAdd(409);
- break;
- case 436:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddTwoStates(409, 435);
- break;
- case 437:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(732, 734);
- break;
- case 438:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(735, 739);
- }
- break;
- case 439:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAdd(432);
- }
- break;
- case 440:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(439, 432);
- }
- break;
- case 441:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(740, 742);
- }
- break;
- case 442:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(743, 746);
- }
- break;
- case 444:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(747, 750);
- break;
- case 445:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(751, 757);
- break;
- case 446:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(758, 760);
- break;
- case 447:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(761, 764);
- break;
- case 448:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(765, 769);
- break;
- case 449:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(770, 775);
- break;
- case 450:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(776, 780);
- }
- break;
- case 451:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(781, 788);
- }
- break;
- case 453:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(789, 793);
- }
- break;
- case 454:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(794, 799);
- }
- break;
- case 455:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(800, 806);
- }
- break;
- case 456:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 73) {
- kind = 73;
- }
- jjCheckNAddStates(0, 81);
- break;
- case 457:
- if ((0x3ff000000000000L & l) == 0L) {
- break;
- }
- if (kind > 73) {
- kind = 73;
- }
- jjCheckNAdd(457);
- break;
- case 458:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(458, 459);
- }
- break;
- case 459:
- if (curChar == 46) {
- jjCheckNAdd(266);
- }
- break;
- case 460:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(460, 268);
- }
- break;
- case 461:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(461, 462);
- }
- break;
- case 462:
- if (curChar == 46) {
- jjCheckNAdd(267);
- }
- break;
- case 463:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(463, 271);
- }
- break;
- case 464:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(464, 465);
- }
- break;
- case 465:
- if (curChar == 46) {
- jjCheckNAdd(269);
- }
- break;
- case 466:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(466, 274);
- }
- break;
- case 467:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(467, 468);
- }
- break;
- case 468:
- if (curChar == 46) {
- jjCheckNAdd(272);
- }
- break;
- case 469:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(469, 277);
- }
- break;
- case 470:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(470, 471);
- }
- break;
- case 471:
- if (curChar == 46) {
- jjCheckNAdd(275);
- }
- break;
- case 472:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(472, 280);
- }
- break;
- case 473:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(473, 474);
- }
- break;
- case 474:
- if (curChar == 46) {
- jjCheckNAdd(278);
- }
- break;
- case 475:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(475, 283);
- }
- break;
- case 476:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(476, 477);
- }
- break;
- case 477:
- if (curChar == 46) {
- jjCheckNAdd(281);
- }
- break;
- case 478:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(478, 286);
- }
- break;
- case 479:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(479, 480);
- }
- break;
- case 480:
- if (curChar == 46) {
- jjCheckNAdd(284);
- }
- break;
- case 481:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(481, 289);
- }
- break;
- case 482:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(482, 483);
- }
- break;
- case 483:
- if (curChar == 46) {
- jjCheckNAdd(287);
- }
- break;
- case 484:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(484, 293);
- }
- break;
- case 485:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(485, 486);
- }
- break;
- case 486:
- if (curChar == 46) {
- jjCheckNAdd(290);
- }
- break;
- case 487:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(487, 297);
- }
- break;
- case 488:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(488, 489);
- }
- break;
- case 489:
- if (curChar == 46) {
- jjCheckNAdd(294);
- }
- break;
- case 490:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(490, 300);
- }
- break;
- case 491:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(491, 492);
- }
- break;
- case 492:
- if (curChar == 46) {
- jjCheckNAdd(298);
- }
- break;
- case 493:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(493, 304);
- }
- break;
- case 494:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(494, 495);
- }
- break;
- case 495:
- if (curChar == 46) {
- jjCheckNAdd(301);
- }
- break;
- case 496:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(496, 308);
- }
- break;
- case 497:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(497, 498);
- }
- break;
- case 498:
- if (curChar == 46) {
- jjCheckNAdd(305);
- }
- break;
- case 499:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(499, 313);
- }
- break;
- case 500:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(500, 501);
- }
- break;
- case 501:
- if (curChar == 46) {
- jjCheckNAdd(309);
- }
- break;
- case 502:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(502, 316);
- }
- break;
- case 503:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(503, 504);
- }
- break;
- case 504:
- if (curChar == 46) {
- jjCheckNAdd(314);
- }
- break;
- case 505:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(505, 318);
- }
- break;
- case 506:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(506, 507);
- }
- break;
- case 507:
- if (curChar == 46) {
- jjCheckNAdd(317);
- }
- break;
- case 508:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(508, 321);
- }
- break;
- case 509:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(509, 510);
- }
- break;
- case 510:
- if (curChar == 46) {
- jjCheckNAdd(319);
- }
- break;
- case 511:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(511, 325);
- }
- break;
- case 512:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(512, 513);
- }
- break;
- case 513:
- if (curChar == 46) {
- jjCheckNAdd(322);
- }
- break;
- case 514:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddStates(807, 811);
- }
- break;
- case 515:
- if ((0x3ff000000000000L & l) != 0L) {
- jjCheckNAddTwoStates(515, 516);
- }
- break;
- case 516:
- if (curChar == 46) {
- jjCheckNAdd(326);
- }
- break;
- default:
- break;
- }
- } while (i != startsAt);
- } else if (curChar < 128) {
- long l = 1L << (curChar & 077);
- do {
- switch (jjstateSet[--i]) {
- case 520:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(115, 116);
- }
- break;
- case 166:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(115, 125);
- }
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 165;
- }
- break;
- case 174:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(115, 116);
- }
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 173;
- }
- break;
- case 4:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(812, 817);
- } else if (curChar == 92) {
- jjCheckNAddStates(818, 821);
- } else if (curChar == 64) {
- jjAddStates(822, 826);
- }
- if ((0x20000000200000L & l) != 0L) {
- jjAddStates(827, 829);
- } else if ((0x800000008L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 155;
- } else if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 145;
- } else if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 137;
- } else if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 33;
- } else if (curChar == 64) {
- jjAddStates(830, 833);
- }
- break;
- case 518:
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 259;
- } else if ((0x1000000010L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 249;
- }
- break;
- case 178:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- }
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 216;
- } else if ((0x80000000800000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 204;
- } else if ((0x800000008000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 188;
- }
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 177;
- }
- break;
- case 517:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- jjCheckNAddStates(120, 123);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(222, 223);
- }
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(234, 235);
- }
- break;
- case 175:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(115, 116);
- }
- break;
- case 33:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- jjCheckNAddStates(120, 123);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(222, 223);
- }
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(234, 235);
- }
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 32;
- }
- break;
- case 176:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(115, 116);
- }
- if ((0x400000004000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 175;
- }
- break;
- case 42:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- if ((0x7fffffe07fffffeL & l) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- }
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 41;
- }
- break;
- case 177:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(115, 116);
- }
- if ((0x8000000080000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 215;
- } else if ((0x800000008000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 176;
- }
- break;
- case 79:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- } else if (curChar == 92) {
- jjCheckNAddTwoStates(83, 93);
- }
- break;
- case 2:
- if (kind > 5) {
- kind = 5;
- }
- break;
- case 5:
- if (curChar == 123) {
- jjstateSet[jjnewStateCnt++] = 6;
- }
- break;
- case 8:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 9:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 10:
- if (curChar == 125 && kind > 40) {
- kind = 40;
- }
- break;
- case 11:
- if (curChar == 92) {
- jjCheckNAddTwoStates(12, 13);
- }
- break;
- case 12:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 13:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(136, 140);
- }
- break;
- case 15:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(141, 148);
- }
- break;
- case 16:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(149, 152);
- }
- break;
- case 17:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(153, 157);
- }
- break;
- case 18:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(158, 163);
- }
- break;
- case 19:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(164, 170);
- }
- break;
- case 21:
- if (curChar == 92) {
- jjCheckNAddTwoStates(12, 22);
- }
- break;
- case 22:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(171, 175);
- }
- break;
- case 23:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(176, 183);
- }
- break;
- case 24:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(184, 187);
- }
- break;
- case 25:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(188, 192);
- }
- break;
- case 26:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(193, 198);
- }
- break;
- case 27:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(199, 205);
- }
- break;
- case 29:
- if ((0x4000000040000L & l) != 0L && kind > 68) {
- kind = 68;
- }
- break;
- case 30:
- case 35:
- if ((0x2000000020L & l) != 0L) {
- jjCheckNAdd(29);
- }
- break;
- case 31:
- if ((0x10000000100000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 30;
- }
- break;
- case 32:
- if ((0x100000001000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 31;
- }
- break;
- case 34:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 33;
- }
- break;
- case 36:
- if ((0x10000000100000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 35;
- }
- break;
- case 37:
- if ((0x100000001000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 36;
- }
- break;
- case 38:
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 37;
- }
- break;
- case 39:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 38;
- }
- break;
- case 41:
- if ((0x8000000080000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 40;
- }
- break;
- case 45:
- case 50:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 47:
- if (curChar == 92) {
- jjAddStates(834, 837);
- }
- break;
- case 49:
- if (curChar == 92) {
- jjAddStates(838, 839);
- }
- break;
- case 51:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(206, 211);
- }
- break;
- case 53:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(212, 220);
- }
- break;
- case 54:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(221, 225);
- }
- break;
- case 55:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(226, 231);
- }
- break;
- case 56:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(232, 238);
- }
- break;
- case 57:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(239, 246);
- }
- break;
- case 62:
- case 67:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 64:
- if (curChar == 92) {
- jjAddStates(840, 843);
- }
- break;
- case 66:
- if (curChar == 92) {
- jjAddStates(844, 845);
- }
- break;
- case 68:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(247, 252);
- }
- break;
- case 70:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(253, 261);
- }
- break;
- case 71:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(262, 266);
- }
- break;
- case 72:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(267, 272);
- }
- break;
- case 73:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(273, 279);
- }
- break;
- case 74:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(280, 287);
- }
- break;
- case 80:
- if ((0x7fffffe07fffffeL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 81:
- if ((0x7fffffe87fffffeL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 82:
- if (curChar == 92) {
- jjCheckNAddTwoStates(83, 84);
- }
- break;
- case 83:
- if ((0x7fffffffffffffffL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 84:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(288, 291);
- break;
- case 86:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(292, 298);
- break;
- case 87:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(299, 301);
- break;
- case 88:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(302, 305);
- break;
- case 89:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(306, 310);
- break;
- case 90:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(311, 316);
- break;
- case 92:
- if (curChar == 92) {
- jjCheckNAddTwoStates(83, 93);
- }
- break;
- case 93:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(317, 320);
- break;
- case 94:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(321, 327);
- break;
- case 95:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(328, 330);
- break;
- case 96:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(331, 334);
- break;
- case 97:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(335, 339);
- break;
- case 98:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddStates(340, 345);
- break;
- case 100:
- if ((0x7fffffe87fffffeL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddTwoStates(100, 101);
- break;
- case 101:
- if (curChar == 92) {
- jjAddStates(846, 847);
- }
- break;
- case 102:
- if ((0x7fffffffffffffffL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddTwoStates(100, 101);
- break;
- case 103:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(346, 349);
- break;
- case 105:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(350, 356);
- break;
- case 106:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(357, 359);
- break;
- case 107:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(360, 363);
- break;
- case 108:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(364, 368);
- break;
- case 109:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddStates(369, 374);
- break;
- case 110:
- if (curChar == 64) {
- jjAddStates(830, 833);
- }
- break;
- case 112:
- if ((0x7fffffe07fffffeL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 113:
- if ((0x7fffffe87fffffeL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 114:
- if (curChar == 92) {
- jjCheckNAddTwoStates(115, 116);
- }
- break;
- case 115:
- if ((0x7fffffffffffffffL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 116:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(375, 378);
- break;
- case 118:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(379, 385);
- break;
- case 119:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(386, 388);
- break;
- case 120:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(389, 392);
- break;
- case 121:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(393, 397);
- break;
- case 122:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(398, 403);
- break;
- case 124:
- if (curChar == 92) {
- jjCheckNAddTwoStates(115, 125);
- }
- break;
- case 125:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(404, 407);
- break;
- case 126:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(408, 414);
- break;
- case 127:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(415, 417);
- break;
- case 128:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(418, 421);
- break;
- case 129:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(422, 426);
- break;
- case 130:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddStates(427, 432);
- break;
- case 131:
- if ((0x2000000020L & l) != 0L) {
- jjAddStates(433, 434);
- }
- break;
- case 134:
- if ((0x40000000400000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 131;
- }
- break;
- case 135:
- if ((0x800000008000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 134;
- }
- break;
- case 136:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 135;
- }
- break;
- case 137:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 136;
- }
- break;
- case 138:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 137;
- }
- break;
- case 139:
- if ((0x1000000010L & l) != 0L) {
- jjAddStates(435, 436);
- }
- break;
- case 142:
- if ((0x400000004000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 139;
- }
- break;
- case 143:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 142;
- }
- break;
- case 144:
- if ((0x1000000010000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 143;
- }
- break;
- case 145:
- if ((0x1000000010000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 144;
- }
- break;
- case 146:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 145;
- }
- break;
- case 147:
- if ((0x8000000080000L & l) != 0L) {
- jjAddStates(437, 438);
- }
- break;
- case 150:
- if ((0x400000004000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 147;
- }
- break;
- case 151:
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 150;
- }
- break;
- case 152:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 151;
- }
- break;
- case 153:
- if ((0x10000000100000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 152;
- }
- break;
- case 154:
- if ((0x400000004000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 153;
- }
- break;
- case 155:
- if ((0x800000008000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 154;
- }
- break;
- case 156:
- if ((0x800000008L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 155;
- }
- break;
- case 157:
- if (curChar == 64) {
- jjAddStates(822, 826);
- }
- break;
- case 158:
- if ((0x8000000080000L & l) != 0L && kind > 102) {
- kind = 102;
- }
- break;
- case 159:
- case 167:
- case 180:
- case 191:
- case 207:
- if ((0x2000000020L & l) != 0L) {
- jjCheckNAdd(158);
- }
- break;
- case 160:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 159;
- }
- break;
- case 161:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 160;
- }
- break;
- case 162:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 161;
- }
- break;
- case 163:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 162;
- }
- break;
- case 164:
- if ((0x200000002000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 163;
- }
- break;
- case 165:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 164;
- }
- break;
- case 168:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 167;
- }
- break;
- case 169:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 168;
- }
- break;
- case 170:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 169;
- }
- break;
- case 171:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 170;
- }
- break;
- case 172:
- if ((0x200000002000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 171;
- }
- break;
- case 173:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 172;
- }
- break;
- case 181:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 180;
- }
- break;
- case 182:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 181;
- }
- break;
- case 183:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 182;
- }
- break;
- case 184:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 183;
- }
- break;
- case 185:
- if ((0x200000002000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 184;
- }
- break;
- case 186:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 185;
- }
- break;
- case 187:
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 186;
- }
- break;
- case 189:
- if ((0x800000008000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 188;
- }
- break;
- case 192:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 191;
- }
- break;
- case 193:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 192;
- }
- break;
- case 194:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 193;
- }
- break;
- case 195:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 194;
- }
- break;
- case 196:
- if ((0x200000002000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 195;
- }
- break;
- case 197:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 196;
- }
- break;
- case 198:
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 197;
- }
- break;
- case 200:
- if ((0x10000000100000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 199;
- }
- break;
- case 201:
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 200;
- }
- break;
- case 202:
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 201;
- }
- break;
- case 203:
- if ((0x400000004L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 202;
- }
- break;
- case 204:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 203;
- }
- break;
- case 205:
- if ((0x80000000800000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 204;
- }
- break;
- case 208:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 207;
- }
- break;
- case 209:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 208;
- }
- break;
- case 210:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 209;
- }
- break;
- case 211:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 210;
- }
- break;
- case 212:
- if ((0x200000002000000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 211;
- }
- break;
- case 213:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 212;
- }
- break;
- case 214:
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 213;
- }
- break;
- case 216:
- if ((0x8000000080000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 215;
- }
- break;
- case 217:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 216;
- }
- break;
- case 220:
- if ((0x7fffffe87fffffeL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 221:
- if (curChar == 92) {
- jjCheckNAddTwoStates(222, 223);
- }
- break;
- case 222:
- if ((0x7fffffffffffffffL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 223:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(439, 442);
- break;
- case 225:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(443, 449);
- break;
- case 226:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(450, 452);
- break;
- case 227:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(453, 456);
- break;
- case 228:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(457, 461);
- break;
- case 229:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(462, 467);
- break;
- case 230:
- if ((0x7fffffe87fffffeL & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 233:
- if (curChar == 92) {
- jjCheckNAddTwoStates(234, 235);
- }
- break;
- case 234:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 235:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(468, 472);
- }
- break;
- case 237:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(473, 480);
- }
- break;
- case 238:
- case 452:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(481, 484);
- }
- break;
- case 239:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(485, 489);
- }
- break;
- case 240:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(490, 495);
- }
- break;
- case 241:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(496, 502);
- }
- break;
- case 244:
- if ((0x10000000100000L & l) != 0L && kind > 70) {
- kind = 70;
- }
- break;
- case 245:
- if ((0x100000001000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 244;
- }
- break;
- case 246:
- if ((0x20000000200000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 245;
- }
- break;
- case 247:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 246;
- }
- break;
- case 248:
- if ((0x4000000040L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 247;
- }
- break;
- case 249:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 248;
- }
- break;
- case 250:
- if ((0x1000000010L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 249;
- }
- break;
- case 252:
- if ((0x10000000100000L & l) != 0L && kind > 104) {
- kind = 104;
- }
- break;
- case 253:
- if ((0x400000004000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 252;
- }
- break;
- case 254:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 253;
- }
- break;
- case 255:
- if ((0x10000000100000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 254;
- }
- break;
- case 256:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 255;
- }
- break;
- case 257:
- if ((0x800000008000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 256;
- }
- break;
- case 258:
- if ((0x1000000010000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 257;
- }
- break;
- case 259:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 258;
- }
- break;
- case 260:
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 259;
- }
- break;
- case 262:
- if ((0x7fffffe07fffffeL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 263:
- if ((0x7fffffe07fffffeL & l) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 264:
- if ((0x7fffffe07fffffeL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(812, 817);
- break;
- case 270:
- if ((0x10000000100000L & l) != 0L && kind > 78) {
- kind = 78;
- }
- break;
- case 271:
- if ((0x1000000010000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 270;
- }
- break;
- case 273:
- if ((0x200000002000L & l) != 0L && kind > 79) {
- kind = 79;
- }
- break;
- case 274:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 273;
- }
- break;
- case 276:
- if ((0x200000002000L & l) != 0L && kind > 80) {
- kind = 80;
- }
- break;
- case 277:
- if ((0x800000008L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 276;
- }
- break;
- case 279:
- if ((0x800000008L & l) != 0L && kind > 81) {
- kind = 81;
- }
- break;
- case 280:
- if ((0x1000000010000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 279;
- }
- break;
- case 282:
- if ((0x400000004000L & l) != 0L && kind > 82) {
- kind = 82;
- }
- break;
- case 283:
- if ((0x20000000200L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 282;
- }
- break;
- case 285:
- if ((0x100000001000000L & l) != 0L && kind > 83) {
- kind = 83;
- }
- break;
- case 286:
- if ((0x1000000010000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 285;
- }
- break;
- case 288:
- if ((0x200000002000L & l) != 0L && kind > 84) {
- kind = 84;
- }
- break;
- case 289:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 288;
- }
- break;
- case 291:
- if ((0x200000002000L & l) != 0L && kind > 85) {
- kind = 85;
- }
- break;
- case 292:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 291;
- }
- break;
- case 293:
- if ((0x100000001000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 292;
- }
- break;
- case 295:
- if ((0x200000002000L & l) != 0L && kind > 86) {
- kind = 86;
- }
- break;
- case 296:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 295;
- }
- break;
- case 297:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 296;
- }
- break;
- case 299:
- if ((0x100000001000000L & l) != 0L && kind > 87) {
- kind = 87;
- }
- break;
- case 300:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 299;
- }
- break;
- case 302:
- if ((0x8000000080L & l) != 0L && kind > 88) {
- kind = 88;
- }
- break;
- case 303:
- if ((0x2000000020L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 302;
- }
- break;
- case 304:
- if ((0x1000000010L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 303;
- }
- break;
- case 306:
- if ((0x1000000010L & l) != 0L && kind > 89) {
- kind = 89;
- }
- break;
- case 307:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 306;
- }
- break;
- case 308:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 307;
- }
- break;
- case 310:
- if ((0x1000000010L & l) != 0L && kind > 90) {
- kind = 90;
- }
- break;
- case 311:
- if ((0x200000002L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 310;
- }
- break;
- case 312:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 311;
- }
- break;
- case 313:
- if ((0x8000000080L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 312;
- }
- break;
- case 315:
- if ((0x8000000080000L & l) != 0L && kind > 91) {
- kind = 91;
- }
- break;
- case 316:
- if ((0x200000002000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 315;
- }
- break;
- case 318:
- if ((0x8000000080000L & l) != 0L && kind > 92) {
- kind = 92;
- }
- break;
- case 320:
- if ((0x400000004000000L & l) != 0L && kind > 93) {
- kind = 93;
- }
- break;
- case 321:
- if ((0x10000000100L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 320;
- }
- break;
- case 323:
- if ((0x400000004000000L & l) != 0L && kind > 94) {
- kind = 94;
- }
- break;
- case 324:
- if ((0x10000000100L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 323;
- }
- break;
- case 325:
- if ((0x80000000800L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 324;
- }
- break;
- case 328:
- if ((0x7fffffe07fffffeL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 329:
- if ((0x7fffffe87fffffeL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 330:
- if (curChar == 92) {
- jjCheckNAddTwoStates(331, 332);
- }
- break;
- case 331:
- if ((0x7fffffffffffffffL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 332:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(503, 506);
- break;
- case 334:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(507, 513);
- break;
- case 335:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(514, 516);
- break;
- case 336:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(517, 520);
- break;
- case 337:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(521, 525);
- break;
- case 338:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(526, 531);
- break;
- case 340:
- if (curChar == 92) {
- jjCheckNAddTwoStates(331, 341);
- }
- break;
- case 341:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(532, 535);
- break;
- case 342:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(536, 542);
- break;
- case 343:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(543, 545);
- break;
- case 344:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(546, 549);
- break;
- case 345:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(550, 554);
- break;
- case 346:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddStates(555, 560);
- break;
- case 347:
- if ((0x20000000200000L & l) != 0L) {
- jjAddStates(827, 829);
- }
- break;
- case 349:
- case 353:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(567, 570);
- }
- break;
- case 352:
- if (curChar == 92) {
- jjAddStates(848, 849);
- }
- break;
- case 354:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(571, 575);
- }
- break;
- case 356:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(576, 583);
- }
- break;
- case 357:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(584, 587);
- }
- break;
- case 358:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(588, 592);
- }
- break;
- case 359:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(593, 598);
- }
- break;
- case 360:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(599, 605);
- }
- break;
- case 362:
- case 367:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 364:
- if (curChar == 92) {
- jjAddStates(850, 853);
- }
- break;
- case 366:
- if (curChar == 92) {
- jjAddStates(854, 855);
- }
- break;
- case 368:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(610, 615);
- }
- break;
- case 370:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(616, 624);
- }
- break;
- case 371:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(625, 629);
- }
- break;
- case 372:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(630, 635);
- }
- break;
- case 373:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(636, 642);
- }
- break;
- case 374:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(643, 650);
- }
- break;
- case 379:
- case 384:
- if ((0x7fffffffffffffffL & l) != 0L) {
- jjCheckNAddStates(651, 654);
- }
- break;
- case 381:
- if (curChar == 92) {
- jjAddStates(856, 859);
- }
- break;
- case 383:
- if (curChar == 92) {
- jjAddStates(860, 861);
- }
- break;
- case 385:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(655, 660);
- }
- break;
- case 387:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(661, 669);
- }
- break;
- case 388:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(670, 674);
- }
- break;
- case 389:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(675, 680);
- }
- break;
- case 390:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(681, 687);
- }
- break;
- case 391:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(688, 695);
- }
- break;
- case 396:
- if ((0x100000001000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 348;
- }
- break;
- case 397:
- if ((0x4000000040000L & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 396;
- }
- break;
- case 405:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjAddStates(712, 717);
- break;
- case 406:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 407;
- }
- break;
- case 407:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 408;
- }
- break;
- case 408:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAdd(409);
- }
- break;
- case 409:
- if ((0x7e0000007eL & l) != 0L && kind > 114) {
- kind = 114;
- }
- break;
- case 410:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 411;
- }
- break;
- case 411:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 412;
- }
- break;
- case 412:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 413;
- }
- break;
- case 413:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 401;
- break;
- case 414:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 415;
- }
- break;
- case 415:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 416;
- }
- break;
- case 416:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 417;
- break;
- case 418:
- if ((0x7e0000007eL & l) != 0L) {
- jjstateSet[jjnewStateCnt++] = 419;
- }
- break;
- case 419:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 420;
- break;
- case 422:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 423;
- break;
- case 431:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddTwoStates(432, 438);
- }
- break;
- case 433:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjstateSet[jjnewStateCnt++] = 434;
- break;
- case 434:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(728, 731);
- break;
- case 435:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAdd(409);
- break;
- case 436:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddTwoStates(409, 435);
- break;
- case 437:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 114) {
- kind = 114;
- }
- jjCheckNAddStates(732, 734);
- break;
- case 438:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(735, 739);
- }
- break;
- case 439:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAdd(432);
- }
- break;
- case 440:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddTwoStates(439, 432);
- }
- break;
- case 441:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(740, 742);
- }
- break;
- case 442:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(743, 746);
- }
- break;
- case 443:
- if (curChar == 92) {
- jjCheckNAddStates(818, 821);
- }
- break;
- case 444:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(747, 750);
- break;
- case 445:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(751, 757);
- break;
- case 446:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(758, 760);
- break;
- case 447:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(761, 764);
- break;
- case 448:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(765, 769);
- break;
- case 449:
- if ((0x7e0000007eL & l) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddStates(770, 775);
- break;
- case 450:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(776, 780);
- }
- break;
- case 451:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(781, 788);
- }
- break;
- case 453:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(789, 793);
- }
- break;
- case 454:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(794, 799);
- }
- break;
- case 455:
- if ((0x7e0000007eL & l) != 0L) {
- jjCheckNAddStates(800, 806);
- }
- break;
- default:
- break;
- }
- } while (i != startsAt);
- } else {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- do {
- switch (jjstateSet[--i]) {
- case 520:
- case 113:
- case 115:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 166:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 174:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 4:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 41) {
- kind = 41;
- }
- jjCheckNAddStates(812, 817);
- break;
- case 517:
- if ((jjbitVec0[i2] & l2) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- }
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 175:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 33:
- if ((jjbitVec0[i2] & l2) != 0L) {
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- }
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 176:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 177:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 103) {
- kind = 103;
- }
- jjCheckNAddTwoStates(113, 114);
- break;
- case 79:
- case 81:
- case 83:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 76) {
- kind = 76;
- }
- jjCheckNAddTwoStates(81, 82);
- break;
- case 2:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 5) {
- kind = 5;
- }
- break;
- case 9:
- case 12:
- case 20:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(133, 135);
- }
- break;
- case 45:
- case 50:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(116, 119);
- }
- break;
- case 62:
- case 67:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(112, 115);
- }
- break;
- case 100:
- case 102:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 96) {
- kind = 96;
- }
- jjCheckNAddTwoStates(100, 101);
- break;
- case 220:
- case 222:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 72) {
- kind = 72;
- }
- jjCheckNAddTwoStates(220, 221);
- break;
- case 230:
- case 234:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(120, 123);
- }
- break;
- case 329:
- case 331:
- case 339:
- if ((jjbitVec0[i2] & l2) == 0L) {
- break;
- }
- if (kind > 95) {
- kind = 95;
- }
- jjCheckNAddTwoStates(329, 330);
- break;
- case 349:
- case 353:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(567, 570);
- }
- break;
- case 362:
- case 367:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(606, 609);
- }
- break;
- case 379:
- case 384:
- if ((jjbitVec0[i2] & l2) != 0L) {
- jjCheckNAddStates(651, 654);
- }
- break;
- default:
- break;
- }
- } while (i != startsAt);
- }
- if (kind != 0x7fffffff) {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 517 - (jjnewStateCnt = startsAt))) {
- return curPos;
- }
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- return curPos;
- }
- }
- }
-
- private int jjMoveStringLiteralDfa0_3() {
- switch (curChar) {
- case 42:
- return jjMoveStringLiteralDfa1_3(0x100L);
- default:
+ if ((active0 & 0xff80000000000000L) != 0L || (active1 & 0xf80000003fL) != 0L)
+ return 166;
+ if ((active0 & 0x38000000000000L) != 0L || (active1 & 0x80L) != 0L)
+ {
+ jjmatchedKind = 74;
+ return 518;
+ }
+ if ((active0 & 0x200000000L) != 0L)
+ return 519;
+ return -1;
+ case 1:
+ if ((active0 & 0x50000000000000L) != 0L)
+ {
+ jjmatchedKind = 74;
+ jjmatchedPos = 1;
+ return 518;
+ }
+ if ((active1 & 0x8L) != 0L)
+ return 178;
+ if ((active0 & 0xff80000000000000L) != 0L || (active1 & 0xf800000037L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 1;
+ return 520;
+ }
+ if ((active0 & 0x40L) != 0L)
return 1;
- }
- }
-
- private int jjMoveStringLiteralDfa1_3(long active0) {
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- return 1;
- }
- switch (curChar) {
- case 47:
- if ((active0 & 0x100L) != 0L) {
- return jjStopAtPos(1, 8);
- }
- break;
- default:
- return 2;
- }
- return 2;
- }
-
- private int jjMoveStringLiteralDfa0_1() {
- return jjMoveNfa_1(0, 0);
- }
-
- private int jjMoveNfa_1(int startState, int curPos) {
- int startsAt = 0;
- jjnewStateCnt = 4;
- int i = 1;
- jjstateSet[0] = startState;
- int kind = 0x7fffffff;
- for (;;) {
- if (++jjround == 0x7fffffff) {
- ReInitRounds();
+ if ((active0 & 0x28000000000000L) != 0L || (active1 & 0x80L) != 0L)
+ return 518;
+ return -1;
+ case 2:
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 2;
+ return 177;
+ }
+ if ((active1 & 0x1L) != 0L)
+ return 520;
+ if ((active0 & 0xff80000000000000L) != 0L || (active1 & 0xf800000036L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 2;
+ return 520;
+ }
+ if ((active0 & 0x50000000000000L) != 0L)
+ {
+ jjmatchedKind = 74;
+ jjmatchedPos = 2;
+ return 518;
+ }
+ return -1;
+ case 3:
+ if ((active0 & 0x10000000000000L) != 0L)
+ {
+ jjmatchedKind = 74;
+ jjmatchedPos = 3;
+ return 518;
+ }
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 3;
+ return 176;
+ }
+ if ((active0 & 0xdf80000000000000L) != 0L || (active1 & 0xf800000036L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 3;
+ return 520;
+ }
+ if ((active0 & 0x2000000000000000L) != 0L)
+ return 520;
+ if ((active0 & 0x40000000000000L) != 0L)
+ return 518;
+ return -1;
+ case 4:
+ if ((active0 & 0x8f80000000000000L) != 0L || (active1 & 0xb800000034L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 4;
+ return 520;
+ }
+ if ((active0 & 0x5000000000000000L) != 0L || (active1 & 0x4000000002L) != 0L)
+ return 520;
+ if ((active0 & 0x10000000000000L) != 0L)
+ {
+ jjmatchedKind = 74;
+ jjmatchedPos = 4;
+ return 518;
+ }
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 4;
+ return 175;
+ }
+ return -1;
+ case 5:
+ if ((active0 & 0x700000000000000L) != 0L || (active1 & 0xa800000034L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 5;
+ return 520;
+ }
+ if ((active0 & 0x10000000000000L) != 0L)
+ {
+ jjmatchedKind = 74;
+ jjmatchedPos = 5;
+ return 518;
+ }
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 5;
+ return 174;
+ }
+ if ((active0 & 0x8880000000000000L) != 0L || (active1 & 0x1000000000L) != 0L)
+ return 520;
+ return -1;
+ case 6:
+ if ((active0 & 0x400000000000000L) != 0L || (active1 & 0x800000004L) != 0L)
+ return 520;
+ if ((active0 & 0x300000000000000L) != 0L || (active1 & 0xa000000038L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 6;
+ return 520;
+ }
+ if ((active0 & 0x10000000000000L) != 0L)
+ return 518;
+ return -1;
+ case 7:
+ if ((active0 & 0x100000000000000L) != 0L || (active1 & 0x2000000020L) != 0L)
+ return 520;
+ if ((active0 & 0x200000000000000L) != 0L || (active1 & 0x8000000018L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 7;
+ return 520;
+ }
+ return -1;
+ case 8:
+ if ((active0 & 0x200000000000000L) != 0L || (active1 & 0x10L) != 0L)
+ return 520;
+ if ((active1 & 0x8000000008L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 8;
+ return 520;
+ }
+ return -1;
+ case 9:
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 9;
+ return 520;
+ }
+ if ((active1 & 0x8000000000L) != 0L)
+ return 520;
+ return -1;
+ case 10:
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 10;
+ return 520;
+ }
+ return -1;
+ case 11:
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 11;
+ return 520;
+ }
+ return -1;
+ case 12:
+ if ((active1 & 0x8L) != 0L)
+ {
+ jjmatchedKind = 105;
+ jjmatchedPos = 12;
+ return 520;
+ }
+ return -1;
+ default :
+ return -1;
+ }
+}
+private final int jjStartNfa_0(int pos, long active0, long active1)
+{
+ return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0, active1), pos + 1);
+}
+private int jjStopAtPos(int pos, int kind)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ return pos + 1;
+}
+private int jjMoveStringLiteralDfa0_0()
+{
+ switch(curChar)
+ {
+ case 33:
+ return jjMoveStringLiteralDfa1_0(0x8000000000L, 0x0L);
+ case 36:
+ return jjMoveStringLiteralDfa1_0(0x10000L, 0x0L);
+ case 37:
+ return jjStopAtPos(0, 31);
+ case 38:
+ jjmatchedKind = 32;
+ return jjMoveStringLiteralDfa1_0(0x4000000000L, 0x0L);
+ case 40:
+ return jjStopAtPos(0, 34);
+ case 41:
+ return jjStopAtPos(0, 35);
+ case 42:
+ jjmatchedKind = 30;
+ return jjMoveStringLiteralDfa1_0(0x20000L, 0x0L);
+ case 43:
+ return jjStopAtPos(0, 20);
+ case 44:
+ return jjStopAtPos(0, 22);
+ case 45:
+ jjmatchedKind = 21;
+ return jjMoveStringLiteralDfa1_0(0x800L, 0x0L);
+ case 46:
+ return jjStartNfaWithStates_0(0, 33, 519);
+ case 47:
+ jjmatchedKind = 27;
+ return jjMoveStringLiteralDfa1_0(0x44L, 0x0L);
+ case 58:
+ return jjStopAtPos(0, 40);
+ case 59:
+ return jjStopAtPos(0, 23);
+ case 60:
+ jjmatchedKind = 26;
+ return jjMoveStringLiteralDfa1_0(0x400L, 0x0L);
+ case 61:
+ jjmatchedKind = 19;
+ return jjMoveStringLiteralDfa1_0(0x1000000000L, 0x0L);
+ case 62:
+ return jjStopAtPos(0, 24);
+ case 64:
+ return jjMoveStringLiteralDfa1_0(0xff80000000000000L, 0xf80000003fL);
+ case 91:
+ return jjStopAtPos(0, 28);
+ case 93:
+ return jjStopAtPos(0, 29);
+ case 94:
+ return jjMoveStringLiteralDfa1_0(0x8000L, 0x0L);
+ case 70:
+ case 102:
+ return jjMoveStringLiteralDfa1_0(0x40000000000000L, 0x0L);
+ case 73:
+ case 105:
+ return jjMoveStringLiteralDfa1_0(0x20000000000000L, 0x80L);
+ case 84:
+ case 116:
+ return jjMoveStringLiteralDfa1_0(0x18000000000000L, 0x0L);
+ case 123:
+ return jjStopAtPos(0, 12);
+ case 124:
+ return jjMoveStringLiteralDfa1_0(0x2000004000L, 0x0L);
+ case 125:
+ return jjStopAtPos(0, 13);
+ case 126:
+ jjmatchedKind = 25;
+ return jjMoveStringLiteralDfa1_0(0x40000L, 0x0L);
+ default :
+ return jjMoveNfa_0(4, 0);
+ }
+}
+private int jjMoveStringLiteralDfa1_0(long active0, long active1)
+{
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(0, active0, active1);
+ return 1;
+ }
+ switch(curChar)
+ {
+ case 33:
+ return jjMoveStringLiteralDfa2_0(active0, 0x400L, active1, 0L);
+ case 38:
+ if ((active0 & 0x4000000000L) != 0L)
+ return jjStopAtPos(1, 38);
+ break;
+ case 42:
+ if ((active0 & 0x40L) != 0L)
+ return jjStartNfaWithStates_0(1, 6, 1);
+ break;
+ case 45:
+ return jjMoveStringLiteralDfa2_0(active0, 0x800L, active1, 0x8L);
+ case 47:
+ if ((active0 & 0x4L) != 0L)
+ return jjStopAtPos(1, 2);
+ break;
+ case 61:
+ if ((active0 & 0x4000L) != 0L)
+ return jjStopAtPos(1, 14);
+ else if ((active0 & 0x8000L) != 0L)
+ return jjStopAtPos(1, 15);
+ else if ((active0 & 0x10000L) != 0L)
+ return jjStopAtPos(1, 16);
+ else if ((active0 & 0x20000L) != 0L)
+ return jjStopAtPos(1, 17);
+ else if ((active0 & 0x40000L) != 0L)
+ return jjStopAtPos(1, 18);
+ else if ((active0 & 0x1000000000L) != 0L)
+ return jjStopAtPos(1, 36);
+ else if ((active0 & 0x8000000000L) != 0L)
+ return jjStopAtPos(1, 39);
+ break;
+ case 67:
+ case 99:
+ return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x2000000020L);
+ case 68:
+ case 100:
+ return jjMoveStringLiteralDfa2_0(active0, 0x800000000000000L, active1, 0L);
+ case 69:
+ case 101:
+ return jjMoveStringLiteralDfa2_0(active0, 0x4000000000000000L, active1, 0x6L);
+ case 70:
+ case 102:
+ if ((active1 & 0x80L) != 0L)
+ return jjStartNfaWithStates_0(1, 71, 518);
+ return jjMoveStringLiteralDfa2_0(active0, 0x2200000000000000L, active1, 0x8000000000L);
+ case 72:
+ case 104:
+ return jjMoveStringLiteralDfa2_0(active0, 0x10000000000000L, active1, 0L);
+ case 73:
+ case 105:
+ return jjMoveStringLiteralDfa2_0(active0, 0x100000000000000L, active1, 0x800000001L);
+ case 77:
+ case 109:
+ return jjMoveStringLiteralDfa2_0(active0, 0x80000000000000L, active1, 0x1000000000L);
+ case 78:
+ case 110:
+ if ((active0 & 0x20000000000000L) != 0L)
+ return jjStartNfaWithStates_0(1, 53, 518);
+ break;
+ case 79:
+ case 111:
+ if ((active0 & 0x8000000000000L) != 0L)
+ return jjStartNfaWithStates_0(1, 51, 518);
+ break;
+ case 80:
+ case 112:
+ return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x4000000000L);
+ case 82:
+ case 114:
+ return jjMoveStringLiteralDfa2_0(active0, 0x440000000000000L, active1, 0L);
+ case 83:
+ case 115:
+ return jjMoveStringLiteralDfa2_0(active0, 0L, active1, 0x10L);
+ case 87:
+ case 119:
+ return jjMoveStringLiteralDfa2_0(active0, 0x9000000000000000L, active1, 0L);
+ case 124:
+ if ((active0 & 0x2000000000L) != 0L)
+ return jjStopAtPos(1, 37);
+ break;
+ default :
+ break;
+ }
+ return jjStartNfa_0(0, active0, active1);
+}
+private int jjMoveStringLiteralDfa2_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(0, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(1, active0, active1);
+ return 2;
+ }
+ switch(curChar)
+ {
+ case 45:
+ return jjMoveStringLiteralDfa3_0(active0, 0x400L, active1, 0L);
+ case 62:
+ if ((active0 & 0x800L) != 0L)
+ return jjStopAtPos(2, 11);
+ break;
+ case 65:
+ case 97:
+ return jjMoveStringLiteralDfa3_0(active0, 0x5000000000000000L, active1, 0x4000000000L);
+ case 69:
+ case 101:
+ return jjMoveStringLiteralDfa3_0(active0, 0xc00000000000000L, active1, 0x1000000000L);
+ case 70:
+ case 102:
+ if ((active1 & 0x1L) != 0L)
+ return jjStartNfaWithStates_0(2, 64, 520);
+ break;
+ case 72:
+ case 104:
+ return jjMoveStringLiteralDfa3_0(active0, 0x8000000000000000L, active1, 0x2000000000L);
+ case 73:
+ case 105:
+ return jjMoveStringLiteralDfa3_0(active0, 0x80000000000000L, active1, 0L);
+ case 76:
+ case 108:
+ return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x2L);
+ case 77:
+ case 109:
+ return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x800000008L);
+ case 78:
+ case 110:
+ return jjMoveStringLiteralDfa3_0(active0, 0x100000000000000L, active1, 0L);
+ case 79:
+ case 111:
+ return jjMoveStringLiteralDfa3_0(active0, 0x2040000000000000L, active1, 0x8000000020L);
+ case 82:
+ case 114:
+ return jjMoveStringLiteralDfa3_0(active0, 0x10000000000000L, active1, 0L);
+ case 85:
+ case 117:
+ return jjMoveStringLiteralDfa3_0(active0, 0x200000000000000L, active1, 0x10L);
+ case 88:
+ case 120:
+ return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x4L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(1, active0, active1);
+}
+private int jjMoveStringLiteralDfa3_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(1, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(2, active0, active1);
+ return 3;
+ }
+ switch(curChar)
+ {
+ case 45:
+ if ((active0 & 0x400L) != 0L)
+ return jjStopAtPos(3, 10);
+ break;
+ case 65:
+ case 97:
+ return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x2000000000L);
+ case 66:
+ case 98:
+ return jjMoveStringLiteralDfa4_0(active0, 0x800000000000000L, active1, 0L);
+ case 67:
+ case 99:
+ return jjMoveStringLiteralDfa4_0(active0, 0x4100000000000000L, active1, 0L);
+ case 68:
+ case 100:
+ return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x1000000000L);
+ case 71:
+ case 103:
+ return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x4000000000L);
+ case 73:
+ case 105:
+ return jjMoveStringLiteralDfa4_0(active0, 0x8000000000000000L, active1, 0L);
+ case 77:
+ case 109:
+ if ((active0 & 0x40000000000000L) != 0L)
+ return jjStartNfaWithStates_0(3, 54, 518);
+ break;
+ case 78:
+ case 110:
+ return jjMoveStringLiteralDfa4_0(active0, 0x200000000000000L, active1, 0x8000000020L);
+ case 79:
+ case 111:
+ return jjMoveStringLiteralDfa4_0(active0, 0x10000000000000L, active1, 0x8L);
+ case 80:
+ case 112:
+ return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x800000010L);
+ case 82:
+ case 114:
+ if ((active0 & 0x2000000000000000L) != 0L)
+ return jjStartNfaWithStates_0(3, 61, 520);
+ return jjMoveStringLiteralDfa4_0(active0, 0x1000000000000000L, active1, 0L);
+ case 83:
+ case 115:
+ return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x2L);
+ case 84:
+ case 116:
+ return jjMoveStringLiteralDfa4_0(active0, 0x400000000000000L, active1, 0x4L);
+ case 88:
+ case 120:
+ return jjMoveStringLiteralDfa4_0(active0, 0x80000000000000L, active1, 0L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(2, active0, active1);
+}
+private int jjMoveStringLiteralDfa4_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(2, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(3, active0, active1);
+ return 4;
+ }
+ switch(curChar)
+ {
+ case 67:
+ case 99:
+ return jjMoveStringLiteralDfa5_0(active0, 0x200000000000000L, active1, 0L);
+ case 69:
+ case 101:
+ if ((active1 & 0x2L) != 0L)
+ return jjStartNfaWithStates_0(4, 65, 520);
+ else if ((active1 & 0x4000000000L) != 0L)
+ return jjStartNfaWithStates_0(4, 102, 520);
+ return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x4L);
+ case 72:
+ case 104:
+ if ((active0 & 0x4000000000000000L) != 0L)
+ return jjStartNfaWithStates_0(4, 62, 520);
+ break;
+ case 73:
+ case 105:
+ return jjMoveStringLiteralDfa5_0(active0, 0x80000000000000L, active1, 0x1000000000L);
+ case 76:
+ case 108:
+ return jjMoveStringLiteralDfa5_0(active0, 0x8100000000000000L, active1, 0L);
+ case 78:
+ case 110:
+ if ((active0 & 0x1000000000000000L) != 0L)
+ return jjStartNfaWithStates_0(4, 60, 520);
+ break;
+ case 79:
+ case 111:
+ return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x800000000L);
+ case 80:
+ case 112:
+ return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x10L);
+ case 82:
+ case 114:
+ return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x2000000000L);
+ case 84:
+ case 116:
+ return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x8000000020L);
+ case 85:
+ case 117:
+ return jjMoveStringLiteralDfa5_0(active0, 0xc10000000000000L, active1, 0L);
+ case 90:
+ case 122:
+ return jjMoveStringLiteralDfa5_0(active0, 0L, active1, 0x8L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(3, active0, active1);
+}
+private int jjMoveStringLiteralDfa5_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(3, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(4, active0, active1);
+ return 5;
+ }
+ switch(curChar)
+ {
+ case 45:
+ return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x8000000008L);
+ case 65:
+ case 97:
+ if ((active1 & 0x1000000000L) != 0L)
+ return jjStartNfaWithStates_0(5, 100, 520);
+ break;
+ case 69:
+ case 101:
+ if ((active0 & 0x8000000000000000L) != 0L)
+ return jjStartNfaWithStates_0(5, 63, 520);
+ return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x20L);
+ case 71:
+ case 103:
+ if ((active0 & 0x800000000000000L) != 0L)
+ return jjStartNfaWithStates_0(5, 59, 520);
+ return jjMoveStringLiteralDfa6_0(active0, 0x10000000000000L, active1, 0L);
+ case 78:
+ case 110:
+ if ((active0 & 0x80000000000000L) != 0L)
+ return jjStartNfaWithStates_0(5, 55, 520);
+ return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x4L);
+ case 79:
+ case 111:
+ return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x10L);
+ case 82:
+ case 114:
+ return jjMoveStringLiteralDfa6_0(active0, 0x400000000000000L, active1, 0x800000000L);
+ case 83:
+ case 115:
+ return jjMoveStringLiteralDfa6_0(active0, 0L, active1, 0x2000000000L);
+ case 84:
+ case 116:
+ return jjMoveStringLiteralDfa6_0(active0, 0x200000000000000L, active1, 0L);
+ case 85:
+ case 117:
+ return jjMoveStringLiteralDfa6_0(active0, 0x100000000000000L, active1, 0L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(4, active0, active1);
+}
+private int jjMoveStringLiteralDfa6_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(4, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(5, active0, active1);
+ return 6;
+ }
+ switch(curChar)
+ {
+ case 68:
+ case 100:
+ if ((active1 & 0x4L) != 0L)
+ return jjStartNfaWithStates_0(6, 66, 520);
+ return jjMoveStringLiteralDfa7_0(active0, 0x100000000000000L, active1, 0x8L);
+ case 69:
+ case 101:
+ return jjMoveStringLiteralDfa7_0(active0, 0L, active1, 0x2000000000L);
+ case 70:
+ case 102:
+ return jjMoveStringLiteralDfa7_0(active0, 0L, active1, 0x8000000000L);
+ case 72:
+ case 104:
+ if ((active0 & 0x10000000000000L) != 0L)
+ return jjStartNfaWithStates_0(6, 52, 518);
+ break;
+ case 73:
+ case 105:
+ return jjMoveStringLiteralDfa7_0(active0, 0x200000000000000L, active1, 0L);
+ case 78:
+ case 110:
+ if ((active0 & 0x400000000000000L) != 0L)
+ return jjStartNfaWithStates_0(6, 58, 520);
+ return jjMoveStringLiteralDfa7_0(active0, 0L, active1, 0x20L);
+ case 82:
+ case 114:
+ return jjMoveStringLiteralDfa7_0(active0, 0L, active1, 0x10L);
+ case 84:
+ case 116:
+ if ((active1 & 0x800000000L) != 0L)
+ return jjStartNfaWithStates_0(6, 99, 520);
+ break;
+ default :
+ break;
+ }
+ return jjStartNfa_0(5, active0, active1);
+}
+private int jjMoveStringLiteralDfa7_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(5, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(6, active0, active1);
+ return 7;
+ }
+ switch(curChar)
+ {
+ case 65:
+ case 97:
+ return jjMoveStringLiteralDfa8_0(active0, 0L, active1, 0x8000000000L);
+ case 69:
+ case 101:
+ if ((active0 & 0x100000000000000L) != 0L)
+ return jjStartNfaWithStates_0(7, 56, 520);
+ break;
+ case 79:
+ case 111:
+ return jjMoveStringLiteralDfa8_0(active0, 0x200000000000000L, active1, 0x8L);
+ case 84:
+ case 116:
+ if ((active1 & 0x20L) != 0L)
+ return jjStartNfaWithStates_0(7, 69, 520);
+ else if ((active1 & 0x2000000000L) != 0L)
+ return jjStartNfaWithStates_0(7, 101, 520);
+ return jjMoveStringLiteralDfa8_0(active0, 0L, active1, 0x10L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(6, active0, active1);
+}
+private int jjMoveStringLiteralDfa8_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(6, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(7, active0, active1);
+ return 8;
+ }
+ switch(curChar)
+ {
+ case 67:
+ case 99:
+ return jjMoveStringLiteralDfa9_0(active0, 0L, active1, 0x8000000008L);
+ case 78:
+ case 110:
+ if ((active0 & 0x200000000000000L) != 0L)
+ return jjStartNfaWithStates_0(8, 57, 520);
+ break;
+ case 83:
+ case 115:
+ if ((active1 & 0x10L) != 0L)
+ return jjStartNfaWithStates_0(8, 68, 520);
+ break;
+ default :
+ break;
+ }
+ return jjStartNfa_0(7, active0, active1);
+}
+private int jjMoveStringLiteralDfa9_0(long old0, long active0, long old1, long active1)
+{
+ if (((active0 &= old0) | (active1 &= old1)) == 0L)
+ return jjStartNfa_0(7, old0, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(8, 0L, active1);
+ return 9;
+ }
+ switch(curChar)
+ {
+ case 69:
+ case 101:
+ if ((active1 & 0x8000000000L) != 0L)
+ return jjStartNfaWithStates_0(9, 103, 520);
+ break;
+ case 85:
+ case 117:
+ return jjMoveStringLiteralDfa10_0(active1, 0x8L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(8, 0L, active1);
+}
+private int jjMoveStringLiteralDfa10_0(long old1, long active1)
+{
+ if (((active1 &= old1)) == 0L)
+ return jjStartNfa_0(8, 0L, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(9, 0L, active1);
+ return 10;
+ }
+ switch(curChar)
+ {
+ case 77:
+ case 109:
+ return jjMoveStringLiteralDfa11_0(active1, 0x8L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(9, 0L, active1);
+}
+private int jjMoveStringLiteralDfa11_0(long old1, long active1)
+{
+ if (((active1 &= old1)) == 0L)
+ return jjStartNfa_0(9, 0L, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(10, 0L, active1);
+ return 11;
+ }
+ switch(curChar)
+ {
+ case 69:
+ case 101:
+ return jjMoveStringLiteralDfa12_0(active1, 0x8L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(10, 0L, active1);
+}
+private int jjMoveStringLiteralDfa12_0(long old1, long active1)
+{
+ if (((active1 &= old1)) == 0L)
+ return jjStartNfa_0(10, 0L, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(11, 0L, active1);
+ return 12;
+ }
+ switch(curChar)
+ {
+ case 78:
+ case 110:
+ return jjMoveStringLiteralDfa13_0(active1, 0x8L);
+ default :
+ break;
+ }
+ return jjStartNfa_0(11, 0L, active1);
+}
+private int jjMoveStringLiteralDfa13_0(long old1, long active1)
+{
+ if (((active1 &= old1)) == 0L)
+ return jjStartNfa_0(11, 0L, old1);
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ jjStopStringLiteralDfa_0(12, 0L, active1);
+ return 13;
+ }
+ switch(curChar)
+ {
+ case 84:
+ case 116:
+ if ((active1 & 0x8L) != 0L)
+ return jjStartNfaWithStates_0(13, 67, 520);
+ break;
+ default :
+ break;
+ }
+ return jjStartNfa_0(12, 0L, active1);
+}
+private int jjStartNfaWithStates_0(int pos, int kind, int state)
+{
+ jjmatchedKind = kind;
+ jjmatchedPos = pos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return pos + 1; }
+ return jjMoveNfa_0(state, pos + 1);
+}
+static final long[] jjbitVec0 = {
+ 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
+};
+private int jjMoveNfa_0(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 517;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 520:
+ case 113:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 166:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 112;
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 217;
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 205;
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 189;
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 178;
+ break;
+ case 174:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 4:
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 75)
+ kind = 75;
+ jjCheckNAddStates(0, 81);
+ }
+ else if ((0x100003600L & l) != 0L)
+ {
+ if (kind > 1)
+ kind = 1;
+ jjCheckNAdd(0);
+ }
+ else if (curChar == 46)
+ jjCheckNAddStates(82, 101);
+ else if (curChar == 45)
+ jjAddStates(102, 103);
+ else if (curChar == 33)
+ jjCheckNAddStates(104, 107);
+ else if (curChar == 35)
+ jjCheckNAddTwoStates(100, 101);
+ else if (curChar == 36)
+ jjCheckNAddStates(108, 111);
+ else if (curChar == 39)
+ jjCheckNAddStates(112, 115);
+ else if (curChar == 34)
+ jjCheckNAddStates(116, 119);
+ else if (curChar == 47)
+ jjstateSet[jjnewStateCnt++] = 3;
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 42;
+ else if (curChar == 35)
+ jjstateSet[jjnewStateCnt++] = 5;
+ break;
+ case 517:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(251, 260);
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(243, 250);
+ break;
+ case 518:
+ if ((0x3ff200000000000L & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ else if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(231, 232);
+ else if (curChar == 40)
+ {
+ if (kind > 120)
+ kind = 120;
+ }
+ if ((0x3ff200000000000L & l) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ break;
+ case 175:
+ if ((0x3ff200000000000L & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 174;
+ break;
+ case 33:
+ if ((0x3ff200000000000L & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ else if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(231, 232);
+ else if (curChar == 40)
+ {
+ if (kind > 120)
+ kind = 120;
+ }
+ if ((0x3ff200000000000L & l) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ break;
+ case 176:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 519:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(124, 128);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(322, 325);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(319, 321);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(317, 318);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(314, 316);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(309, 313);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(305, 308);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(301, 304);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(298, 300);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(294, 297);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(290, 293);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(287, 289);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(284, 286);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(281, 283);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(278, 280);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(275, 277);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(272, 274);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(269, 271);
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(267, 268);
+ if ((0x3ff000000000000L & l) != 0L)
+ {
+ if (kind > 75)
+ kind = 75;
+ jjCheckNAdd(266);
+ }
+ break;
+ case 177:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 79:
+ if (curChar == 45)
+ jjCheckNAdd(80);
+ break;
+ case 0:
+ if ((0x100003600L & l) == 0L)
+ break;
+ if (kind > 1)
+ kind = 1;
+ jjCheckNAdd(0);
+ break;
+ case 1:
+ if (curChar == 42)
+ jjstateSet[jjnewStateCnt++] = 2;
+ break;
+ case 2:
+ if ((0xffff7fffffffffffL & l) != 0L && kind > 5)
+ kind = 5;
+ break;
+ case 3:
+ if (curChar == 42)
+ jjstateSet[jjnewStateCnt++] = 1;
+ break;
+ case 6:
+ if (curChar == 36)
+ jjCheckNAddStates(129, 132);
+ break;
+ case 7:
+ if (curChar == 45)
+ jjCheckNAdd(8);
+ break;
+ case 9:
+ if ((0x3ff200000000000L & l) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 12:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 13:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(136, 140);
+ break;
+ case 14:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 15:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(141, 148);
+ break;
+ case 16:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(149, 152);
+ break;
+ case 17:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(153, 157);
+ break;
+ case 18:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(158, 163);
+ break;
+ case 19:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(164, 170);
+ break;
+ case 22:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(171, 175);
+ break;
+ case 23:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(176, 183);
+ break;
+ case 24:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(184, 187);
+ break;
+ case 25:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(188, 192);
+ break;
+ case 26:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(193, 198);
+ break;
+ case 27:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(199, 205);
+ break;
+ case 28:
+ if (curChar == 35)
+ jjstateSet[jjnewStateCnt++] = 5;
+ break;
+ case 40:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 39;
+ break;
+ case 43:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 42;
+ break;
+ case 44:
+ if (curChar == 34)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 45:
+ if ((0xfffffffb00000200L & l) != 0L)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 46:
+ if (curChar == 34 && kind > 73)
+ kind = 73;
+ break;
+ case 48:
+ if (curChar == 12)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 50:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 51:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(206, 211);
+ break;
+ case 52:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 53:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(212, 220);
+ break;
+ case 54:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(221, 225);
+ break;
+ case 55:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(226, 231);
+ break;
+ case 56:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(232, 238);
+ break;
+ case 57:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(239, 246);
+ break;
+ case 58:
+ if (curChar == 13)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 59:
+ if (curChar == 10)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 60:
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 59;
+ break;
+ case 61:
+ if (curChar == 39)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 62:
+ if ((0xffffff7f00000200L & l) != 0L)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 63:
+ if (curChar == 39 && kind > 73)
+ kind = 73;
+ break;
+ case 65:
+ if (curChar == 12)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 67:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 68:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(247, 252);
+ break;
+ case 69:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 70:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(253, 261);
+ break;
+ case 71:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(262, 266);
+ break;
+ case 72:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(267, 272);
+ break;
+ case 73:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(273, 279);
+ break;
+ case 74:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(280, 287);
+ break;
+ case 75:
+ if (curChar == 13)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 76:
+ if (curChar == 10)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 77:
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 76;
+ break;
+ case 78:
+ if (curChar == 36)
+ jjCheckNAddStates(108, 111);
+ break;
+ case 81:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 83:
+ if ((0xffffffff00000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 84:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(288, 291);
+ break;
+ case 85:
+ if ((0x100003600L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 86:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(292, 298);
+ break;
+ case 87:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(299, 301);
+ break;
+ case 88:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(302, 305);
+ break;
+ case 89:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(306, 310);
+ break;
+ case 90:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(311, 316);
+ break;
+ case 93:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(317, 320);
+ break;
+ case 94:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(321, 327);
+ break;
+ case 95:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(328, 330);
+ break;
+ case 96:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(331, 334);
+ break;
+ case 97:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(335, 339);
+ break;
+ case 98:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(340, 345);
+ break;
+ case 99:
+ if (curChar == 35)
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 100:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 102:
+ if ((0xffffffff00000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 103:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(346, 349);
+ break;
+ case 104:
+ if ((0x100003600L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 105:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(350, 356);
+ break;
+ case 106:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(357, 359);
+ break;
+ case 107:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(360, 363);
+ break;
+ case 108:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(364, 368);
+ break;
+ case 109:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(369, 374);
+ break;
+ case 111:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 112;
+ break;
+ case 115:
+ if ((0xffffffff00000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 116:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(375, 378);
+ break;
+ case 117:
+ if ((0x100003600L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 118:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(379, 385);
+ break;
+ case 119:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(386, 388);
+ break;
+ case 120:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(389, 392);
+ break;
+ case 121:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(393, 397);
+ break;
+ case 122:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(398, 403);
+ break;
+ case 125:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(404, 407);
+ break;
+ case 126:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(408, 414);
+ break;
+ case 127:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(415, 417);
+ break;
+ case 128:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(418, 421);
+ break;
+ case 129:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(422, 426);
+ break;
+ case 130:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(427, 432);
+ break;
+ case 132:
+ if ((0x100003600L & l) != 0L)
+ jjAddStates(433, 434);
+ break;
+ case 133:
+ if (curChar == 40 && kind > 117)
+ kind = 117;
+ break;
+ case 140:
+ if ((0x100003600L & l) != 0L)
+ jjAddStates(435, 436);
+ break;
+ case 141:
+ if (curChar == 40 && kind > 118)
+ kind = 118;
+ break;
+ case 148:
+ if ((0x100003600L & l) != 0L)
+ jjAddStates(437, 438);
+ break;
+ case 149:
+ if (curChar == 40 && kind > 119)
+ kind = 119;
+ break;
+ case 179:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 178;
+ break;
+ case 188:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 187;
+ break;
+ case 190:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 189;
+ break;
+ case 199:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 198;
+ break;
+ case 206:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 205;
+ break;
+ case 215:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 214;
+ break;
+ case 218:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 217;
+ break;
+ case 220:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 222:
+ if ((0xffffffff00000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 223:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(439, 442);
+ break;
+ case 224:
+ if ((0x100003600L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 225:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(443, 449);
+ break;
+ case 226:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(450, 452);
+ break;
+ case 227:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(453, 456);
+ break;
+ case 228:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(457, 461);
+ break;
+ case 229:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(462, 467);
+ break;
+ case 230:
+ if ((0x3ff200000000000L & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 231:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(231, 232);
+ break;
+ case 232:
+ if (curChar == 40 && kind > 120)
+ kind = 120;
+ break;
+ case 234:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 235:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(468, 472);
+ break;
+ case 236:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 237:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(473, 480);
+ break;
+ case 238:
+ case 452:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(481, 484);
+ break;
+ case 239:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(485, 489);
+ break;
+ case 240:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(490, 495);
+ break;
+ case 241:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(496, 502);
+ break;
+ case 242:
+ if (curChar == 33)
+ jjCheckNAddStates(104, 107);
+ break;
+ case 243:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(243, 250);
+ break;
+ case 251:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(251, 260);
+ break;
+ case 261:
+ if (curChar == 45)
+ jjAddStates(102, 103);
+ break;
+ case 265:
+ if (curChar == 46)
+ jjCheckNAddStates(82, 101);
+ break;
+ case 266:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 75)
+ kind = 75;
+ jjCheckNAdd(266);
+ break;
+ case 267:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(267, 268);
+ break;
+ case 268:
+ if (curChar == 37 && kind > 79)
+ kind = 79;
+ break;
+ case 269:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(269, 271);
+ break;
+ case 272:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(272, 274);
+ break;
+ case 275:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(275, 277);
+ break;
+ case 278:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(278, 280);
+ break;
+ case 281:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(281, 283);
+ break;
+ case 284:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(284, 286);
+ break;
+ case 287:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(287, 289);
+ break;
+ case 290:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(290, 293);
+ break;
+ case 294:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(294, 297);
+ break;
+ case 298:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(298, 300);
+ break;
+ case 301:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(301, 304);
+ break;
+ case 305:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(305, 308);
+ break;
+ case 309:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(309, 313);
+ break;
+ case 314:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(314, 316);
+ break;
+ case 317:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(317, 318);
+ break;
+ case 319:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(319, 321);
+ break;
+ case 322:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(322, 325);
+ break;
+ case 326:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(124, 128);
+ break;
+ case 327:
+ if (curChar == 45)
+ jjCheckNAdd(328);
+ break;
+ case 329:
+ if ((0x3ff200000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 331:
+ if ((0xffffffff00000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 332:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(503, 506);
+ break;
+ case 333:
+ if ((0x100003600L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 334:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(507, 513);
+ break;
+ case 335:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(514, 516);
+ break;
+ case 336:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(517, 520);
+ break;
+ case 337:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(521, 525);
+ break;
+ case 338:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(526, 531);
+ break;
+ case 341:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(532, 535);
+ break;
+ case 342:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(536, 542);
+ break;
+ case 343:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(543, 545);
+ break;
+ case 344:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(546, 549);
+ break;
+ case 345:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(550, 554);
+ break;
+ case 346:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(555, 560);
+ break;
+ case 348:
+ if (curChar == 40)
+ jjCheckNAddStates(561, 566);
+ break;
+ case 349:
+ if ((0xfffffc7a00000000L & l) != 0L)
+ jjCheckNAddStates(567, 570);
+ break;
+ case 350:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddTwoStates(350, 351);
+ break;
+ case 351:
+ if (curChar == 41 && kind > 77)
+ kind = 77;
+ break;
+ case 353:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(567, 570);
+ break;
+ case 354:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(571, 575);
+ break;
+ case 355:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(567, 570);
+ break;
+ case 356:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(576, 583);
+ break;
+ case 357:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(584, 587);
+ break;
+ case 358:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(588, 592);
+ break;
+ case 359:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(593, 598);
+ break;
+ case 360:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(599, 605);
+ break;
+ case 361:
+ if (curChar == 39)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 362:
+ if ((0xffffff7f00000200L & l) != 0L)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 363:
+ if (curChar == 39)
+ jjCheckNAddTwoStates(350, 351);
+ break;
+ case 365:
+ if (curChar == 12)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 367:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 368:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(610, 615);
+ break;
+ case 369:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 370:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(616, 624);
+ break;
+ case 371:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(625, 629);
+ break;
+ case 372:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(630, 635);
+ break;
+ case 373:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(636, 642);
+ break;
+ case 374:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(643, 650);
+ break;
+ case 375:
+ if (curChar == 13)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 376:
+ if (curChar == 10)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 377:
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 376;
+ break;
+ case 378:
+ if (curChar == 34)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 379:
+ if ((0xfffffffb00000200L & l) != 0L)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 380:
+ if (curChar == 34)
+ jjCheckNAddTwoStates(350, 351);
+ break;
+ case 382:
+ if (curChar == 12)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 384:
+ if ((0xffffffff00000000L & l) != 0L)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 385:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(655, 660);
+ break;
+ case 386:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 387:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(661, 669);
+ break;
+ case 388:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(670, 674);
+ break;
+ case 389:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(675, 680);
+ break;
+ case 390:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(681, 687);
+ break;
+ case 391:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(688, 695);
+ break;
+ case 392:
+ if (curChar == 13)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 393:
+ if (curChar == 10)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 394:
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 393;
+ break;
+ case 395:
+ if ((0x100003600L & l) != 0L)
+ jjCheckNAddStates(696, 702);
+ break;
+ case 398:
+ if (curChar == 43)
+ jjAddStates(703, 704);
+ break;
+ case 399:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 400;
+ break;
+ case 400:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(705, 708);
+ break;
+ case 401:
+ if (curChar == 63 && kind > 116)
+ kind = 116;
+ break;
+ case 402:
+ case 417:
+ case 421:
+ case 424:
+ case 427:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAdd(401);
+ break;
+ case 403:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddTwoStates(401, 402);
+ break;
+ case 404:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(709, 711);
+ break;
+ case 405:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjAddStates(712, 717);
+ break;
+ case 406:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 407;
+ break;
+ case 407:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 408;
+ break;
+ case 408:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAdd(409);
+ break;
+ case 409:
+ if ((0x3ff000000000000L & l) != 0L && kind > 116)
+ kind = 116;
+ break;
+ case 410:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 411;
+ break;
+ case 411:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 412;
+ break;
+ case 412:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 413;
+ break;
+ case 413:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAdd(401);
+ break;
+ case 414:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 415;
+ break;
+ case 415:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 416;
+ break;
+ case 416:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 417;
+ break;
+ case 418:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 419;
+ break;
+ case 419:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 420;
+ break;
+ case 420:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddTwoStates(401, 421);
+ break;
+ case 422:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 423;
+ break;
+ case 423:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(718, 720);
+ break;
+ case 425:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddTwoStates(401, 424);
+ break;
+ case 426:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(721, 724);
+ break;
+ case 428:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddTwoStates(401, 427);
+ break;
+ case 429:
+ if (curChar != 63)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(725, 727);
+ break;
+ case 430:
+ if (curChar == 43)
+ jjstateSet[jjnewStateCnt++] = 431;
+ break;
+ case 431:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(432, 438);
+ break;
+ case 432:
+ if (curChar == 45)
+ jjstateSet[jjnewStateCnt++] = 433;
+ break;
+ case 433:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 434;
+ break;
+ case 434:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(728, 731);
+ break;
+ case 435:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAdd(409);
+ break;
+ case 436:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddTwoStates(409, 435);
+ break;
+ case 437:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(732, 734);
+ break;
+ case 438:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(735, 739);
+ break;
+ case 439:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAdd(432);
+ break;
+ case 440:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(439, 432);
+ break;
+ case 441:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(740, 742);
+ break;
+ case 442:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(743, 746);
+ break;
+ case 444:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(747, 750);
+ break;
+ case 445:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(751, 757);
+ break;
+ case 446:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(758, 760);
+ break;
+ case 447:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(761, 764);
+ break;
+ case 448:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(765, 769);
+ break;
+ case 449:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(770, 775);
+ break;
+ case 450:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(776, 780);
+ break;
+ case 451:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(781, 788);
+ break;
+ case 453:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(789, 793);
+ break;
+ case 454:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(794, 799);
+ break;
+ case 455:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(800, 806);
+ break;
+ case 456:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 75)
+ kind = 75;
+ jjCheckNAddStates(0, 81);
+ break;
+ case 457:
+ if ((0x3ff000000000000L & l) == 0L)
+ break;
+ if (kind > 75)
+ kind = 75;
+ jjCheckNAdd(457);
+ break;
+ case 458:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(458, 459);
+ break;
+ case 459:
+ if (curChar == 46)
+ jjCheckNAdd(266);
+ break;
+ case 460:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(460, 268);
+ break;
+ case 461:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(461, 462);
+ break;
+ case 462:
+ if (curChar == 46)
+ jjCheckNAdd(267);
+ break;
+ case 463:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(463, 271);
+ break;
+ case 464:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(464, 465);
+ break;
+ case 465:
+ if (curChar == 46)
+ jjCheckNAdd(269);
+ break;
+ case 466:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(466, 274);
+ break;
+ case 467:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(467, 468);
+ break;
+ case 468:
+ if (curChar == 46)
+ jjCheckNAdd(272);
+ break;
+ case 469:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(469, 277);
+ break;
+ case 470:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(470, 471);
+ break;
+ case 471:
+ if (curChar == 46)
+ jjCheckNAdd(275);
+ break;
+ case 472:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(472, 280);
+ break;
+ case 473:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(473, 474);
+ break;
+ case 474:
+ if (curChar == 46)
+ jjCheckNAdd(278);
+ break;
+ case 475:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(475, 283);
+ break;
+ case 476:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(476, 477);
+ break;
+ case 477:
+ if (curChar == 46)
+ jjCheckNAdd(281);
+ break;
+ case 478:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(478, 286);
+ break;
+ case 479:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(479, 480);
+ break;
+ case 480:
+ if (curChar == 46)
+ jjCheckNAdd(284);
+ break;
+ case 481:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(481, 289);
+ break;
+ case 482:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(482, 483);
+ break;
+ case 483:
+ if (curChar == 46)
+ jjCheckNAdd(287);
+ break;
+ case 484:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(484, 293);
+ break;
+ case 485:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(485, 486);
+ break;
+ case 486:
+ if (curChar == 46)
+ jjCheckNAdd(290);
+ break;
+ case 487:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(487, 297);
+ break;
+ case 488:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(488, 489);
+ break;
+ case 489:
+ if (curChar == 46)
+ jjCheckNAdd(294);
+ break;
+ case 490:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(490, 300);
+ break;
+ case 491:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(491, 492);
+ break;
+ case 492:
+ if (curChar == 46)
+ jjCheckNAdd(298);
+ break;
+ case 493:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(493, 304);
+ break;
+ case 494:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(494, 495);
+ break;
+ case 495:
+ if (curChar == 46)
+ jjCheckNAdd(301);
+ break;
+ case 496:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(496, 308);
+ break;
+ case 497:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(497, 498);
+ break;
+ case 498:
+ if (curChar == 46)
+ jjCheckNAdd(305);
+ break;
+ case 499:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(499, 313);
+ break;
+ case 500:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(500, 501);
+ break;
+ case 501:
+ if (curChar == 46)
+ jjCheckNAdd(309);
+ break;
+ case 502:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(502, 316);
+ break;
+ case 503:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(503, 504);
+ break;
+ case 504:
+ if (curChar == 46)
+ jjCheckNAdd(314);
+ break;
+ case 505:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(505, 318);
+ break;
+ case 506:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(506, 507);
+ break;
+ case 507:
+ if (curChar == 46)
+ jjCheckNAdd(317);
+ break;
+ case 508:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(508, 321);
+ break;
+ case 509:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(509, 510);
+ break;
+ case 510:
+ if (curChar == 46)
+ jjCheckNAdd(319);
+ break;
+ case 511:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(511, 325);
+ break;
+ case 512:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(512, 513);
+ break;
+ case 513:
+ if (curChar == 46)
+ jjCheckNAdd(322);
+ break;
+ case 514:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddStates(807, 811);
+ break;
+ case 515:
+ if ((0x3ff000000000000L & l) != 0L)
+ jjCheckNAddTwoStates(515, 516);
+ break;
+ case 516:
+ if (curChar == 46)
+ jjCheckNAdd(326);
+ break;
+ default : break;
}
- if (curChar < 64) {
- long l = 1L << curChar;
- do {
- switch (jjstateSet[--i]) {
- case 0:
- if ((0xffffffffffffdbffL & l) != 0L) {
- if (kind > 3) {
- kind = 3;
- }
- } else if ((0x2400L & l) != 0L) {
- if (kind > 4) {
- kind = 4;
- }
- }
- if (curChar == 13) {
- jjstateSet[jjnewStateCnt++] = 2;
- }
- break;
- case 1:
- if ((0x2400L & l) != 0L && kind > 4) {
- kind = 4;
- }
- break;
- case 2:
- if (curChar == 10 && kind > 4) {
- kind = 4;
- }
- break;
- case 3:
- if (curChar == 13) {
- jjstateSet[jjnewStateCnt++] = 2;
- }
- break;
- default:
- break;
- }
- } while (i != startsAt);
- } else if (curChar < 128) {
- long l = 1L << (curChar & 077);
- do {
- switch (jjstateSet[--i]) {
- case 0:
- kind = 3;
- break;
- default:
- break;
- }
- } while (i != startsAt);
- } else {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- do {
- switch (jjstateSet[--i]) {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 3) {
- kind = 3;
- }
- break;
- default:
- break;
- }
- } while (i != startsAt);
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 520:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(115, 116);
+ break;
+ case 166:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(115, 125);
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 165;
+ break;
+ case 174:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(115, 116);
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 173;
+ break;
+ case 4:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(812, 817);
+ }
+ else if (curChar == 92)
+ jjCheckNAddStates(818, 821);
+ else if (curChar == 64)
+ jjAddStates(822, 826);
+ if ((0x20000000200000L & l) != 0L)
+ jjAddStates(827, 829);
+ else if ((0x800000008L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 155;
+ else if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 145;
+ else if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 137;
+ else if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 33;
+ else if (curChar == 64)
+ jjAddStates(830, 833);
+ break;
+ case 517:
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 259;
+ else if ((0x1000000010L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 249;
+ break;
+ case 178:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 216;
+ else if ((0x80000000800000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 204;
+ else if ((0x800000008000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 188;
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 177;
+ break;
+ case 518:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(222, 223);
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(234, 235);
+ break;
+ case 175:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(115, 116);
+ break;
+ case 33:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(222, 223);
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(234, 235);
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 32;
+ break;
+ case 176:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(115, 116);
+ if ((0x400000004000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 175;
+ break;
+ case 42:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 41;
+ break;
+ case 177:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ {
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(115, 116);
+ if ((0x8000000080000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 215;
+ else if ((0x800000008000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 176;
+ break;
+ case 79:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ {
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ }
+ else if (curChar == 92)
+ jjCheckNAddTwoStates(83, 93);
+ break;
+ case 2:
+ if (kind > 5)
+ kind = 5;
+ break;
+ case 5:
+ if (curChar == 123)
+ jjstateSet[jjnewStateCnt++] = 6;
+ break;
+ case 8:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 9:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 10:
+ if (curChar == 125 && kind > 41)
+ kind = 41;
+ break;
+ case 11:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(12, 13);
+ break;
+ case 12:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 13:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(136, 140);
+ break;
+ case 15:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(141, 148);
+ break;
+ case 16:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(149, 152);
+ break;
+ case 17:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(153, 157);
+ break;
+ case 18:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(158, 163);
+ break;
+ case 19:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(164, 170);
+ break;
+ case 21:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(12, 22);
+ break;
+ case 22:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(171, 175);
+ break;
+ case 23:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(176, 183);
+ break;
+ case 24:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(184, 187);
+ break;
+ case 25:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(188, 192);
+ break;
+ case 26:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(193, 198);
+ break;
+ case 27:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(199, 205);
+ break;
+ case 29:
+ if ((0x4000000040000L & l) != 0L && kind > 70)
+ kind = 70;
+ break;
+ case 30:
+ case 35:
+ if ((0x2000000020L & l) != 0L)
+ jjCheckNAdd(29);
+ break;
+ case 31:
+ if ((0x10000000100000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 30;
+ break;
+ case 32:
+ if ((0x100000001000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 31;
+ break;
+ case 34:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 33;
+ break;
+ case 36:
+ if ((0x10000000100000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 35;
+ break;
+ case 37:
+ if ((0x100000001000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 36;
+ break;
+ case 38:
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 37;
+ break;
+ case 39:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 38;
+ break;
+ case 41:
+ if ((0x8000000080000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 40;
+ break;
+ case 45:
+ case 50:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 47:
+ if (curChar == 92)
+ jjAddStates(834, 837);
+ break;
+ case 49:
+ if (curChar == 92)
+ jjAddStates(838, 839);
+ break;
+ case 51:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(206, 211);
+ break;
+ case 53:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(212, 220);
+ break;
+ case 54:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(221, 225);
+ break;
+ case 55:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(226, 231);
+ break;
+ case 56:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(232, 238);
+ break;
+ case 57:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(239, 246);
+ break;
+ case 62:
+ case 67:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 64:
+ if (curChar == 92)
+ jjAddStates(840, 843);
+ break;
+ case 66:
+ if (curChar == 92)
+ jjAddStates(844, 845);
+ break;
+ case 68:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(247, 252);
+ break;
+ case 70:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(253, 261);
+ break;
+ case 71:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(262, 266);
+ break;
+ case 72:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(267, 272);
+ break;
+ case 73:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(273, 279);
+ break;
+ case 74:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(280, 287);
+ break;
+ case 80:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 81:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 82:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(83, 84);
+ break;
+ case 83:
+ if ((0x7fffffffffffffffL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 84:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(288, 291);
+ break;
+ case 86:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(292, 298);
+ break;
+ case 87:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(299, 301);
+ break;
+ case 88:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(302, 305);
+ break;
+ case 89:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(306, 310);
+ break;
+ case 90:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(311, 316);
+ break;
+ case 92:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(83, 93);
+ break;
+ case 93:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(317, 320);
+ break;
+ case 94:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(321, 327);
+ break;
+ case 95:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(328, 330);
+ break;
+ case 96:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(331, 334);
+ break;
+ case 97:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(335, 339);
+ break;
+ case 98:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddStates(340, 345);
+ break;
+ case 100:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 101:
+ if (curChar == 92)
+ jjAddStates(846, 847);
+ break;
+ case 102:
+ if ((0x7fffffffffffffffL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 103:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(346, 349);
+ break;
+ case 105:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(350, 356);
+ break;
+ case 106:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(357, 359);
+ break;
+ case 107:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(360, 363);
+ break;
+ case 108:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(364, 368);
+ break;
+ case 109:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddStates(369, 374);
+ break;
+ case 110:
+ if (curChar == 64)
+ jjAddStates(830, 833);
+ break;
+ case 112:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 113:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 114:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(115, 116);
+ break;
+ case 115:
+ if ((0x7fffffffffffffffL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 116:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(375, 378);
+ break;
+ case 118:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(379, 385);
+ break;
+ case 119:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(386, 388);
+ break;
+ case 120:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(389, 392);
+ break;
+ case 121:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(393, 397);
+ break;
+ case 122:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(398, 403);
+ break;
+ case 124:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(115, 125);
+ break;
+ case 125:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(404, 407);
+ break;
+ case 126:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(408, 414);
+ break;
+ case 127:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(415, 417);
+ break;
+ case 128:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(418, 421);
+ break;
+ case 129:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(422, 426);
+ break;
+ case 130:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddStates(427, 432);
+ break;
+ case 131:
+ if ((0x2000000020L & l) != 0L)
+ jjAddStates(433, 434);
+ break;
+ case 134:
+ if ((0x40000000400000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 131;
+ break;
+ case 135:
+ if ((0x800000008000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 134;
+ break;
+ case 136:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 135;
+ break;
+ case 137:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 136;
+ break;
+ case 138:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 137;
+ break;
+ case 139:
+ if ((0x1000000010L & l) != 0L)
+ jjAddStates(435, 436);
+ break;
+ case 142:
+ if ((0x400000004000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 139;
+ break;
+ case 143:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 142;
+ break;
+ case 144:
+ if ((0x1000000010000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 143;
+ break;
+ case 145:
+ if ((0x1000000010000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 144;
+ break;
+ case 146:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 145;
+ break;
+ case 147:
+ if ((0x8000000080000L & l) != 0L)
+ jjAddStates(437, 438);
+ break;
+ case 150:
+ if ((0x400000004000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 147;
+ break;
+ case 151:
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 150;
+ break;
+ case 152:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 151;
+ break;
+ case 153:
+ if ((0x10000000100000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 152;
+ break;
+ case 154:
+ if ((0x400000004000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 153;
+ break;
+ case 155:
+ if ((0x800000008000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 154;
+ break;
+ case 156:
+ if ((0x800000008L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 155;
+ break;
+ case 157:
+ if (curChar == 64)
+ jjAddStates(822, 826);
+ break;
+ case 158:
+ if ((0x8000000080000L & l) != 0L && kind > 104)
+ kind = 104;
+ break;
+ case 159:
+ case 167:
+ case 180:
+ case 191:
+ case 207:
+ if ((0x2000000020L & l) != 0L)
+ jjCheckNAdd(158);
+ break;
+ case 160:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 159;
+ break;
+ case 161:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 160;
+ break;
+ case 162:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 161;
+ break;
+ case 163:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 162;
+ break;
+ case 164:
+ if ((0x200000002000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 163;
+ break;
+ case 165:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 164;
+ break;
+ case 168:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 167;
+ break;
+ case 169:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 168;
+ break;
+ case 170:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 169;
+ break;
+ case 171:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 170;
+ break;
+ case 172:
+ if ((0x200000002000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 171;
+ break;
+ case 173:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 172;
+ break;
+ case 181:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 180;
+ break;
+ case 182:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 181;
+ break;
+ case 183:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 182;
+ break;
+ case 184:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 183;
+ break;
+ case 185:
+ if ((0x200000002000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 184;
+ break;
+ case 186:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 185;
+ break;
+ case 187:
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 186;
+ break;
+ case 189:
+ if ((0x800000008000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 188;
+ break;
+ case 192:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 191;
+ break;
+ case 193:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 192;
+ break;
+ case 194:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 193;
+ break;
+ case 195:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 194;
+ break;
+ case 196:
+ if ((0x200000002000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 195;
+ break;
+ case 197:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 196;
+ break;
+ case 198:
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 197;
+ break;
+ case 200:
+ if ((0x10000000100000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 199;
+ break;
+ case 201:
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 200;
+ break;
+ case 202:
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 201;
+ break;
+ case 203:
+ if ((0x400000004L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 202;
+ break;
+ case 204:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 203;
+ break;
+ case 205:
+ if ((0x80000000800000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 204;
+ break;
+ case 208:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 207;
+ break;
+ case 209:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 208;
+ break;
+ case 210:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 209;
+ break;
+ case 211:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 210;
+ break;
+ case 212:
+ if ((0x200000002000000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 211;
+ break;
+ case 213:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 212;
+ break;
+ case 214:
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 213;
+ break;
+ case 216:
+ if ((0x8000000080000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 215;
+ break;
+ case 217:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 216;
+ break;
+ case 220:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 221:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(222, 223);
+ break;
+ case 222:
+ if ((0x7fffffffffffffffL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 223:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(439, 442);
+ break;
+ case 225:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(443, 449);
+ break;
+ case 226:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(450, 452);
+ break;
+ case 227:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(453, 456);
+ break;
+ case 228:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(457, 461);
+ break;
+ case 229:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(462, 467);
+ break;
+ case 230:
+ if ((0x7fffffe87fffffeL & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 233:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(234, 235);
+ break;
+ case 234:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 235:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(468, 472);
+ break;
+ case 237:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(473, 480);
+ break;
+ case 238:
+ case 452:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(481, 484);
+ break;
+ case 239:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(485, 489);
+ break;
+ case 240:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(490, 495);
+ break;
+ case 241:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(496, 502);
+ break;
+ case 244:
+ if ((0x10000000100000L & l) != 0L && kind > 72)
+ kind = 72;
+ break;
+ case 245:
+ if ((0x100000001000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 244;
+ break;
+ case 246:
+ if ((0x20000000200000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 245;
+ break;
+ case 247:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 246;
+ break;
+ case 248:
+ if ((0x4000000040L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 247;
+ break;
+ case 249:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 248;
+ break;
+ case 250:
+ if ((0x1000000010L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 249;
+ break;
+ case 252:
+ if ((0x10000000100000L & l) != 0L && kind > 106)
+ kind = 106;
+ break;
+ case 253:
+ if ((0x400000004000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 252;
+ break;
+ case 254:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 253;
+ break;
+ case 255:
+ if ((0x10000000100000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 254;
+ break;
+ case 256:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 255;
+ break;
+ case 257:
+ if ((0x800000008000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 256;
+ break;
+ case 258:
+ if ((0x1000000010000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 257;
+ break;
+ case 259:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 258;
+ break;
+ case 260:
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 259;
+ break;
+ case 262:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 263:
+ if ((0x7fffffe07fffffeL & l) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 264:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(812, 817);
+ break;
+ case 270:
+ if ((0x10000000100000L & l) != 0L && kind > 80)
+ kind = 80;
+ break;
+ case 271:
+ if ((0x1000000010000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 270;
+ break;
+ case 273:
+ if ((0x200000002000L & l) != 0L && kind > 81)
+ kind = 81;
+ break;
+ case 274:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 273;
+ break;
+ case 276:
+ if ((0x200000002000L & l) != 0L && kind > 82)
+ kind = 82;
+ break;
+ case 277:
+ if ((0x800000008L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 276;
+ break;
+ case 279:
+ if ((0x800000008L & l) != 0L && kind > 83)
+ kind = 83;
+ break;
+ case 280:
+ if ((0x1000000010000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 279;
+ break;
+ case 282:
+ if ((0x400000004000L & l) != 0L && kind > 84)
+ kind = 84;
+ break;
+ case 283:
+ if ((0x20000000200L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 282;
+ break;
+ case 285:
+ if ((0x100000001000000L & l) != 0L && kind > 85)
+ kind = 85;
+ break;
+ case 286:
+ if ((0x1000000010000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 285;
+ break;
+ case 288:
+ if ((0x200000002000L & l) != 0L && kind > 86)
+ kind = 86;
+ break;
+ case 289:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 288;
+ break;
+ case 291:
+ if ((0x200000002000L & l) != 0L && kind > 87)
+ kind = 87;
+ break;
+ case 292:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 291;
+ break;
+ case 293:
+ if ((0x100000001000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 292;
+ break;
+ case 295:
+ if ((0x200000002000L & l) != 0L && kind > 88)
+ kind = 88;
+ break;
+ case 296:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 295;
+ break;
+ case 297:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 296;
+ break;
+ case 299:
+ if ((0x100000001000000L & l) != 0L && kind > 89)
+ kind = 89;
+ break;
+ case 300:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 299;
+ break;
+ case 302:
+ if ((0x8000000080L & l) != 0L && kind > 90)
+ kind = 90;
+ break;
+ case 303:
+ if ((0x2000000020L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 302;
+ break;
+ case 304:
+ if ((0x1000000010L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 303;
+ break;
+ case 306:
+ if ((0x1000000010L & l) != 0L && kind > 91)
+ kind = 91;
+ break;
+ case 307:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 306;
+ break;
+ case 308:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 307;
+ break;
+ case 310:
+ if ((0x1000000010L & l) != 0L && kind > 92)
+ kind = 92;
+ break;
+ case 311:
+ if ((0x200000002L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 310;
+ break;
+ case 312:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 311;
+ break;
+ case 313:
+ if ((0x8000000080L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 312;
+ break;
+ case 315:
+ if ((0x8000000080000L & l) != 0L && kind > 93)
+ kind = 93;
+ break;
+ case 316:
+ if ((0x200000002000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 315;
+ break;
+ case 318:
+ if ((0x8000000080000L & l) != 0L && kind > 94)
+ kind = 94;
+ break;
+ case 320:
+ if ((0x400000004000000L & l) != 0L && kind > 95)
+ kind = 95;
+ break;
+ case 321:
+ if ((0x10000000100L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 320;
+ break;
+ case 323:
+ if ((0x400000004000000L & l) != 0L && kind > 96)
+ kind = 96;
+ break;
+ case 324:
+ if ((0x10000000100L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 323;
+ break;
+ case 325:
+ if ((0x80000000800L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 324;
+ break;
+ case 328:
+ if ((0x7fffffe07fffffeL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 329:
+ if ((0x7fffffe87fffffeL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 330:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(331, 332);
+ break;
+ case 331:
+ if ((0x7fffffffffffffffL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 332:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(503, 506);
+ break;
+ case 334:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(507, 513);
+ break;
+ case 335:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(514, 516);
+ break;
+ case 336:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(517, 520);
+ break;
+ case 337:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(521, 525);
+ break;
+ case 338:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(526, 531);
+ break;
+ case 340:
+ if (curChar == 92)
+ jjCheckNAddTwoStates(331, 341);
+ break;
+ case 341:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(532, 535);
+ break;
+ case 342:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(536, 542);
+ break;
+ case 343:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(543, 545);
+ break;
+ case 344:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(546, 549);
+ break;
+ case 345:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(550, 554);
+ break;
+ case 346:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddStates(555, 560);
+ break;
+ case 347:
+ if ((0x20000000200000L & l) != 0L)
+ jjAddStates(827, 829);
+ break;
+ case 349:
+ case 353:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(567, 570);
+ break;
+ case 352:
+ if (curChar == 92)
+ jjAddStates(848, 849);
+ break;
+ case 354:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(571, 575);
+ break;
+ case 356:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(576, 583);
+ break;
+ case 357:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(584, 587);
+ break;
+ case 358:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(588, 592);
+ break;
+ case 359:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(593, 598);
+ break;
+ case 360:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(599, 605);
+ break;
+ case 362:
+ case 367:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 364:
+ if (curChar == 92)
+ jjAddStates(850, 853);
+ break;
+ case 366:
+ if (curChar == 92)
+ jjAddStates(854, 855);
+ break;
+ case 368:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(610, 615);
+ break;
+ case 370:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(616, 624);
+ break;
+ case 371:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(625, 629);
+ break;
+ case 372:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(630, 635);
+ break;
+ case 373:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(636, 642);
+ break;
+ case 374:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(643, 650);
+ break;
+ case 379:
+ case 384:
+ if ((0x7fffffffffffffffL & l) != 0L)
+ jjCheckNAddStates(651, 654);
+ break;
+ case 381:
+ if (curChar == 92)
+ jjAddStates(856, 859);
+ break;
+ case 383:
+ if (curChar == 92)
+ jjAddStates(860, 861);
+ break;
+ case 385:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(655, 660);
+ break;
+ case 387:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(661, 669);
+ break;
+ case 388:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(670, 674);
+ break;
+ case 389:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(675, 680);
+ break;
+ case 390:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(681, 687);
+ break;
+ case 391:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(688, 695);
+ break;
+ case 396:
+ if ((0x100000001000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 348;
+ break;
+ case 397:
+ if ((0x4000000040000L & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 396;
+ break;
+ case 405:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjAddStates(712, 717);
+ break;
+ case 406:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 407;
+ break;
+ case 407:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 408;
+ break;
+ case 408:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAdd(409);
+ break;
+ case 409:
+ if ((0x7e0000007eL & l) != 0L && kind > 116)
+ kind = 116;
+ break;
+ case 410:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 411;
+ break;
+ case 411:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 412;
+ break;
+ case 412:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 413;
+ break;
+ case 413:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 401;
+ break;
+ case 414:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 415;
+ break;
+ case 415:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 416;
+ break;
+ case 416:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 417;
+ break;
+ case 418:
+ if ((0x7e0000007eL & l) != 0L)
+ jjstateSet[jjnewStateCnt++] = 419;
+ break;
+ case 419:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 420;
+ break;
+ case 422:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 423;
+ break;
+ case 431:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddTwoStates(432, 438);
+ break;
+ case 433:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjstateSet[jjnewStateCnt++] = 434;
+ break;
+ case 434:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(728, 731);
+ break;
+ case 435:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAdd(409);
+ break;
+ case 436:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddTwoStates(409, 435);
+ break;
+ case 437:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 116)
+ kind = 116;
+ jjCheckNAddStates(732, 734);
+ break;
+ case 438:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(735, 739);
+ break;
+ case 439:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAdd(432);
+ break;
+ case 440:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddTwoStates(439, 432);
+ break;
+ case 441:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(740, 742);
+ break;
+ case 442:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(743, 746);
+ break;
+ case 443:
+ if (curChar == 92)
+ jjCheckNAddStates(818, 821);
+ break;
+ case 444:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(747, 750);
+ break;
+ case 445:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(751, 757);
+ break;
+ case 446:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(758, 760);
+ break;
+ case 447:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(761, 764);
+ break;
+ case 448:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(765, 769);
+ break;
+ case 449:
+ if ((0x7e0000007eL & l) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddStates(770, 775);
+ break;
+ case 450:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(776, 780);
+ break;
+ case 451:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(781, 788);
+ break;
+ case 453:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(789, 793);
+ break;
+ case 454:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(794, 799);
+ break;
+ case 455:
+ if ((0x7e0000007eL & l) != 0L)
+ jjCheckNAddStates(800, 806);
+ break;
+ default : break;
}
- if (kind != 0x7fffffff) {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 520:
+ case 113:
+ case 115:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 166:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 174:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 4:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 42)
+ kind = 42;
+ jjCheckNAddStates(812, 817);
+ break;
+ case 518:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 175:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 33:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ {
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ }
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 176:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 177:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 105)
+ kind = 105;
+ jjCheckNAddTwoStates(113, 114);
+ break;
+ case 79:
+ case 81:
+ case 83:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 78)
+ kind = 78;
+ jjCheckNAddTwoStates(81, 82);
+ break;
+ case 2:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 5)
+ kind = 5;
+ break;
+ case 9:
+ case 12:
+ case 20:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(133, 135);
+ break;
+ case 45:
+ case 50:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(116, 119);
+ break;
+ case 62:
+ case 67:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(112, 115);
+ break;
+ case 100:
+ case 102:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 98)
+ kind = 98;
+ jjCheckNAddTwoStates(100, 101);
+ break;
+ case 220:
+ case 222:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 74)
+ kind = 74;
+ jjCheckNAddTwoStates(220, 221);
+ break;
+ case 230:
+ case 234:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(120, 123);
+ break;
+ case 329:
+ case 331:
+ case 339:
+ if ((jjbitVec0[i2] & l2) == 0L)
+ break;
+ if (kind > 97)
+ kind = 97;
+ jjCheckNAddTwoStates(329, 330);
+ break;
+ case 349:
+ case 353:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(567, 570);
+ break;
+ case 362:
+ case 367:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(606, 609);
+ break;
+ case 379:
+ case 384:
+ if ((jjbitVec0[i2] & l2) != 0L)
+ jjCheckNAddStates(651, 654);
+ break;
+ default : break;
}
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt))) {
- return curPos;
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 517 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private int jjMoveStringLiteralDfa0_3()
+{
+ switch(curChar)
+ {
+ case 42:
+ return jjMoveStringLiteralDfa1_3(0x100L);
+ default :
+ return 1;
+ }
+}
+private int jjMoveStringLiteralDfa1_3(long active0)
+{
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ return 1;
+ }
+ switch(curChar)
+ {
+ case 47:
+ if ((active0 & 0x100L) != 0L)
+ return jjStopAtPos(1, 8);
+ break;
+ default :
+ return 2;
+ }
+ return 2;
+}
+private int jjMoveStringLiteralDfa0_1()
+{
+ return jjMoveNfa_1(0, 0);
+}
+private int jjMoveNfa_1(int startState, int curPos)
+{
+ int startsAt = 0;
+ jjnewStateCnt = 4;
+ int i = 1;
+ jjstateSet[0] = startState;
+ int kind = 0x7fffffff;
+ for (;;)
+ {
+ if (++jjround == 0x7fffffff)
+ ReInitRounds();
+ if (curChar < 64)
+ {
+ long l = 1L << curChar;
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((0xffffffffffffdbffL & l) != 0L)
+ {
+ if (kind > 3)
+ kind = 3;
+ }
+ else if ((0x2400L & l) != 0L)
+ {
+ if (kind > 4)
+ kind = 4;
+ }
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 2;
+ break;
+ case 1:
+ if ((0x2400L & l) != 0L && kind > 4)
+ kind = 4;
+ break;
+ case 2:
+ if (curChar == 10 && kind > 4)
+ kind = 4;
+ break;
+ case 3:
+ if (curChar == 13)
+ jjstateSet[jjnewStateCnt++] = 2;
+ break;
+ default : break;
}
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- return curPos;
+ } while(i != startsAt);
+ }
+ else if (curChar < 128)
+ {
+ long l = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ kind = 3;
+ break;
+ default : break;
}
- }
- }
-
- private int jjMoveStringLiteralDfa0_2() {
- switch (curChar) {
- case 42:
- return jjMoveStringLiteralDfa1_2(0x80L);
- default:
- return 1;
- }
- }
-
- private int jjMoveStringLiteralDfa1_2(long active0) {
- try {
- curChar = input_stream.readChar();
- } catch (java.io.IOException e) {
- return 1;
- }
- switch (curChar) {
- case 47:
- if ((active0 & 0x80L) != 0L) {
- return jjStopAtPos(1, 7);
+ } while(i != startsAt);
+ }
+ else
+ {
+ int i2 = (curChar & 0xff) >> 6;
+ long l2 = 1L << (curChar & 077);
+ do
+ {
+ switch(jjstateSet[--i])
+ {
+ case 0:
+ if ((jjbitVec0[i2] & l2) != 0L && kind > 3)
+ kind = 3;
+ break;
+ default : break;
}
- break;
- default:
- return 2;
- }
- return 2;
- }
-
- static final int[] jjnextStates = { 457, 458, 459, 460, 461, 462, 268, 463,
- 464, 465, 271, 466, 467, 468, 274, 469, 470, 471, 277, 472, 473,
- 474, 280, 475, 476, 477, 283, 478, 479, 480, 286, 481, 482, 483,
- 289, 484, 485, 486, 293, 487, 488, 489, 297, 490, 491, 492, 300,
- 493, 494, 495, 304, 496, 497, 498, 308, 499, 500, 501, 313, 502,
- 503, 504, 316, 505, 506, 507, 318, 508, 509, 510, 321, 511, 512,
- 513, 325, 514, 515, 516, 327, 328, 339, 340, 266, 267, 269, 272,
- 275, 278, 281, 284, 287, 290, 294, 298, 301, 305, 309, 314, 317,
- 319, 322, 326, 262, 263, 243, 250, 251, 260, 79, 80, 91, 92, 62,
- 63, 64, 66, 45, 46, 47, 49, 230, 231, 232, 233, 326, 327, 328, 339,
- 340, 7, 8, 20, 21, 9, 10, 11, 9, 14, 10, 11, 15, 9, 16, 14, 10, 11,
- 17, 18, 19, 9, 14, 10, 11, 9, 16, 14, 10, 11, 9, 16, 14, 10, 11,
- 17, 9, 16, 14, 10, 11, 17, 18, 14, 9, 10, 11, 23, 24, 14, 9, 10,
- 11, 25, 26, 27, 14, 9, 10, 11, 24, 14, 9, 10, 11, 24, 14, 9, 10,
- 11, 25, 24, 14, 9, 10, 11, 25, 26, 45, 52, 46, 47, 49, 53, 45, 54,
- 52, 46, 47, 49, 55, 56, 57, 45, 52, 46, 47, 49, 45, 54, 52, 46, 47,
- 49, 45, 54, 52, 46, 47, 49, 55, 45, 54, 52, 46, 47, 49, 55, 56, 62,
- 69, 63, 64, 66, 70, 62, 71, 69, 63, 64, 66, 72, 73, 74, 62, 69, 63,
- 64, 66, 62, 71, 69, 63, 64, 66, 62, 71, 69, 63, 64, 66, 72, 62, 71,
- 69, 63, 64, 66, 72, 73, 81, 85, 82, 86, 81, 87, 85, 82, 88, 89, 90,
- 81, 85, 82, 81, 87, 85, 82, 81, 87, 85, 82, 88, 81, 87, 85, 82, 88,
- 89, 85, 81, 82, 94, 95, 85, 81, 82, 96, 97, 98, 85, 81, 82, 95, 85,
- 81, 82, 95, 85, 81, 82, 96, 95, 85, 81, 82, 96, 97, 100, 104, 101,
- 105, 100, 106, 104, 101, 107, 108, 109, 100, 104, 101, 100, 106,
- 104, 101, 100, 106, 104, 101, 107, 100, 106, 104, 101, 107, 108,
- 113, 117, 114, 118, 113, 119, 117, 114, 120, 121, 122, 113, 117,
- 114, 113, 119, 117, 114, 113, 119, 117, 114, 120, 113, 119, 117,
- 114, 120, 121, 117, 113, 114, 126, 127, 117, 113, 114, 128, 129,
- 130, 117, 113, 114, 127, 117, 113, 114, 127, 117, 113, 114, 128,
- 127, 117, 113, 114, 128, 129, 132, 133, 140, 141, 148, 149, 220,
- 224, 221, 225, 220, 226, 224, 221, 227, 228, 229, 220, 224, 221,
- 220, 226, 224, 221, 220, 226, 224, 221, 227, 220, 226, 224, 221,
- 227, 228, 230, 232, 233, 236, 237, 230, 238, 232, 233, 236, 239,
- 240, 241, 230, 232, 233, 236, 230, 238, 232, 233, 236, 230, 238,
- 232, 233, 236, 239, 230, 238, 232, 233, 236, 239, 240, 329, 333,
- 330, 334, 329, 335, 333, 330, 336, 337, 338, 329, 333, 330, 329,
- 335, 333, 330, 329, 335, 333, 330, 336, 329, 335, 333, 330, 336,
- 337, 333, 329, 330, 342, 343, 333, 329, 330, 344, 345, 346, 333,
- 329, 330, 343, 333, 329, 330, 343, 333, 329, 330, 344, 343, 333,
- 329, 330, 344, 345, 349, 361, 378, 351, 352, 395, 349, 350, 351,
- 352, 349, 351, 352, 355, 356, 349, 357, 351, 352, 355, 358, 359,
- 360, 349, 351, 352, 355, 349, 357, 351, 352, 355, 349, 357, 351,
- 352, 355, 358, 349, 357, 351, 352, 355, 358, 359, 362, 363, 364,
- 366, 362, 369, 363, 364, 366, 370, 362, 371, 369, 363, 364, 366,
- 372, 373, 374, 362, 369, 363, 364, 366, 362, 371, 369, 363, 364,
- 366, 362, 371, 369, 363, 364, 366, 372, 362, 371, 369, 363, 364,
- 366, 372, 373, 379, 380, 381, 383, 379, 386, 380, 381, 383, 387,
- 379, 388, 386, 380, 381, 383, 389, 390, 391, 379, 386, 380, 381,
- 383, 379, 388, 386, 380, 381, 383, 379, 388, 386, 380, 381, 383,
- 389, 379, 388, 386, 380, 381, 383, 389, 390, 349, 361, 378, 350,
- 351, 352, 395, 399, 405, 401, 402, 403, 404, 401, 402, 403, 406,
- 410, 414, 418, 422, 426, 401, 424, 425, 401, 427, 428, 429, 401,
- 427, 428, 409, 435, 436, 437, 409, 435, 436, 439, 432, 440, 441,
- 442, 439, 432, 440, 439, 432, 440, 441, 224, 220, 221, 445, 446,
- 224, 220, 221, 447, 448, 449, 224, 220, 221, 446, 224, 220, 221,
- 446, 224, 220, 221, 447, 446, 224, 220, 221, 447, 448, 230, 232,
- 233, 236, 451, 452, 230, 232, 233, 236, 453, 454, 455, 452, 230,
- 232, 233, 236, 452, 230, 232, 233, 236, 453, 452, 230, 232, 233,
- 236, 453, 454, 514, 327, 328, 339, 340, 220, 230, 231, 232, 233,
- 221, 222, 444, 234, 450, 166, 179, 190, 206, 218, 397, 398, 430,
- 111, 112, 123, 124, 48, 58, 60, 59, 50, 51, 65, 75, 77, 76, 67, 68,
- 102, 103, 353, 354, 365, 375, 377, 376, 367, 368, 382, 392, 394,
- 393, 384, 385, };
-
- /** Token literal values. */
- public static final String[] jjstrLiteralImages = { "", null, null, null,
- null, null, null, null, null, null, "\74\41\55\55", "\55\55\76",
- "\173", "\175", "\174\75", "\136\75", "\44\75", "\52\75",
- "\176\75", "\75", "\53", "\55", "\54", "\73", "\76", "\176", "\74",
- "\57", "\133", "\135", "\52", "\46", "\56", "\50", "\51", "\75\75",
- "\174\174", "\46\46", "\41\75", "\72", null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, };
-
- /** Lexer state names. */
- public static final String[] lexStateNames = { "DEFAULT",
- "IN_SINGLE_LINE_COMMENT", "IN_FORMAL_COMMENT",
- "IN_MULTI_LINE_COMMENT", };
-
- /** Lex State array. */
- public static final int[] jjnewLexState = { -1, -1, 1, -1, 0, 2, 3, 0, 0,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, };
- static final long[] jjtoToken = { 0xfffc03fffffffc03L, 0xfc01fffffffbffL, };
- static final long[] jjtoSkip = { 0x190L, 0x0L, };
- static final long[] jjtoSpecial = { 0x80L, 0x0L, };
- static final long[] jjtoMore = { 0x26cL, 0x0L, };
- protected CharStream input_stream;
- private final int[] jjrounds = new int[517];
- private final int[] jjstateSet = new int[1034];
- private final StringBuilder jjimage = new StringBuilder();
- private StringBuilder image = jjimage;
- private int jjimageLen;
- private int lengthOfMatch;
- protected char curChar;
+ } while(i != startsAt);
+ }
+ if (kind != 0x7fffffff)
+ {
+ jjmatchedKind = kind;
+ jjmatchedPos = curPos;
+ kind = 0x7fffffff;
+ }
+ ++curPos;
+ if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt)))
+ return curPos;
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) { return curPos; }
+ }
+}
+private int jjMoveStringLiteralDfa0_2()
+{
+ switch(curChar)
+ {
+ case 42:
+ return jjMoveStringLiteralDfa1_2(0x80L);
+ default :
+ return 1;
+ }
+}
+private int jjMoveStringLiteralDfa1_2(long active0)
+{
+ try { curChar = input_stream.readChar(); }
+ catch(java.io.IOException e) {
+ return 1;
+ }
+ switch(curChar)
+ {
+ case 47:
+ if ((active0 & 0x80L) != 0L)
+ return jjStopAtPos(1, 7);
+ break;
+ default :
+ return 2;
+ }
+ return 2;
+}
+static final int[] jjnextStates = {
+ 457, 458, 459, 460, 461, 462, 268, 463, 464, 465, 271, 466, 467, 468, 274, 469,
+ 470, 471, 277, 472, 473, 474, 280, 475, 476, 477, 283, 478, 479, 480, 286, 481,
+ 482, 483, 289, 484, 485, 486, 293, 487, 488, 489, 297, 490, 491, 492, 300, 493,
+ 494, 495, 304, 496, 497, 498, 308, 499, 500, 501, 313, 502, 503, 504, 316, 505,
+ 506, 507, 318, 508, 509, 510, 321, 511, 512, 513, 325, 514, 515, 516, 327, 328,
+ 339, 340, 266, 267, 269, 272, 275, 278, 281, 284, 287, 290, 294, 298, 301, 305,
+ 309, 314, 317, 319, 322, 326, 262, 263, 243, 250, 251, 260, 79, 80, 91, 92,
+ 62, 63, 64, 66, 45, 46, 47, 49, 230, 231, 232, 233, 326, 327, 328, 339,
+ 340, 7, 8, 20, 21, 9, 10, 11, 9, 14, 10, 11, 15, 9, 16, 14,
+ 10, 11, 17, 18, 19, 9, 14, 10, 11, 9, 16, 14, 10, 11, 9, 16,
+ 14, 10, 11, 17, 9, 16, 14, 10, 11, 17, 18, 14, 9, 10, 11, 23,
+ 24, 14, 9, 10, 11, 25, 26, 27, 14, 9, 10, 11, 24, 14, 9, 10,
+ 11, 24, 14, 9, 10, 11, 25, 24, 14, 9, 10, 11, 25, 26, 45, 52,
+ 46, 47, 49, 53, 45, 54, 52, 46, 47, 49, 55, 56, 57, 45, 52, 46,
+ 47, 49, 45, 54, 52, 46, 47, 49, 45, 54, 52, 46, 47, 49, 55, 45,
+ 54, 52, 46, 47, 49, 55, 56, 62, 69, 63, 64, 66, 70, 62, 71, 69,
+ 63, 64, 66, 72, 73, 74, 62, 69, 63, 64, 66, 62, 71, 69, 63, 64,
+ 66, 62, 71, 69, 63, 64, 66, 72, 62, 71, 69, 63, 64, 66, 72, 73,
+ 81, 85, 82, 86, 81, 87, 85, 82, 88, 89, 90, 81, 85, 82, 81, 87,
+ 85, 82, 81, 87, 85, 82, 88, 81, 87, 85, 82, 88, 89, 85, 81, 82,
+ 94, 95, 85, 81, 82, 96, 97, 98, 85, 81, 82, 95, 85, 81, 82, 95,
+ 85, 81, 82, 96, 95, 85, 81, 82, 96, 97, 100, 104, 101, 105, 100, 106,
+ 104, 101, 107, 108, 109, 100, 104, 101, 100, 106, 104, 101, 100, 106, 104, 101,
+ 107, 100, 106, 104, 101, 107, 108, 113, 117, 114, 118, 113, 119, 117, 114, 120,
+ 121, 122, 113, 117, 114, 113, 119, 117, 114, 113, 119, 117, 114, 120, 113, 119,
+ 117, 114, 120, 121, 117, 113, 114, 126, 127, 117, 113, 114, 128, 129, 130, 117,
+ 113, 114, 127, 117, 113, 114, 127, 117, 113, 114, 128, 127, 117, 113, 114, 128,
+ 129, 132, 133, 140, 141, 148, 149, 220, 224, 221, 225, 220, 226, 224, 221, 227,
+ 228, 229, 220, 224, 221, 220, 226, 224, 221, 220, 226, 224, 221, 227, 220, 226,
+ 224, 221, 227, 228, 230, 232, 233, 236, 237, 230, 238, 232, 233, 236, 239, 240,
+ 241, 230, 232, 233, 236, 230, 238, 232, 233, 236, 230, 238, 232, 233, 236, 239,
+ 230, 238, 232, 233, 236, 239, 240, 329, 333, 330, 334, 329, 335, 333, 330, 336,
+ 337, 338, 329, 333, 330, 329, 335, 333, 330, 329, 335, 333, 330, 336, 329, 335,
+ 333, 330, 336, 337, 333, 329, 330, 342, 343, 333, 329, 330, 344, 345, 346, 333,
+ 329, 330, 343, 333, 329, 330, 343, 333, 329, 330, 344, 343, 333, 329, 330, 344,
+ 345, 349, 361, 378, 351, 352, 395, 349, 350, 351, 352, 349, 351, 352, 355, 356,
+ 349, 357, 351, 352, 355, 358, 359, 360, 349, 351, 352, 355, 349, 357, 351, 352,
+ 355, 349, 357, 351, 352, 355, 358, 349, 357, 351, 352, 355, 358, 359, 362, 363,
+ 364, 366, 362, 369, 363, 364, 366, 370, 362, 371, 369, 363, 364, 366, 372, 373,
+ 374, 362, 369, 363, 364, 366, 362, 371, 369, 363, 364, 366, 362, 371, 369, 363,
+ 364, 366, 372, 362, 371, 369, 363, 364, 366, 372, 373, 379, 380, 381, 383, 379,
+ 386, 380, 381, 383, 387, 379, 388, 386, 380, 381, 383, 389, 390, 391, 379, 386,
+ 380, 381, 383, 379, 388, 386, 380, 381, 383, 379, 388, 386, 380, 381, 383, 389,
+ 379, 388, 386, 380, 381, 383, 389, 390, 349, 361, 378, 350, 351, 352, 395, 399,
+ 405, 401, 402, 403, 404, 401, 402, 403, 406, 410, 414, 418, 422, 426, 401, 424,
+ 425, 401, 427, 428, 429, 401, 427, 428, 409, 435, 436, 437, 409, 435, 436, 439,
+ 432, 440, 441, 442, 439, 432, 440, 439, 432, 440, 441, 224, 220, 221, 445, 446,
+ 224, 220, 221, 447, 448, 449, 224, 220, 221, 446, 224, 220, 221, 446, 224, 220,
+ 221, 447, 446, 224, 220, 221, 447, 448, 230, 232, 233, 236, 451, 452, 230, 232,
+ 233, 236, 453, 454, 455, 452, 230, 232, 233, 236, 452, 230, 232, 233, 236, 453,
+ 452, 230, 232, 233, 236, 453, 454, 514, 327, 328, 339, 340, 220, 230, 231, 232,
+ 233, 221, 222, 444, 234, 450, 166, 179, 190, 206, 218, 397, 398, 430, 111, 112,
+ 123, 124, 48, 58, 60, 59, 50, 51, 65, 75, 77, 76, 67, 68, 102, 103,
+ 353, 354, 365, 375, 377, 376, 367, 368, 382, 392, 394, 393, 384, 385,
+};
- /** Constructor. */
- public ParserTokenManager(CharStream stream) {
- input_stream = stream;
- }
+/** Token literal values. */
+public static final String[] jjstrLiteralImages = {
+"", null, null, null, null, null, null, null, null, null, "\74\41\55\55",
+"\55\55\76", "\173", "\175", "\174\75", "\136\75", "\44\75", "\52\75", "\176\75", "\75",
+"\53", "\55", "\54", "\73", "\76", "\176", "\74", "\57", "\133", "\135", "\52",
+"\45", "\46", "\56", "\50", "\51", "\75\75", "\174\174", "\46\46", "\41\75", "\72",
+null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+null, null, null, null, null, null, null, null, null, null, null, };
- /** Constructor. */
- public ParserTokenManager(CharStream stream, int lexState) {
- this(stream);
- SwitchTo(lexState);
- }
+/** Lexer state names. */
+public static final String[] lexStateNames = {
+ "DEFAULT",
+ "IN_SINGLE_LINE_COMMENT",
+ "IN_FORMAL_COMMENT",
+ "IN_MULTI_LINE_COMMENT",
+};
- /** Reinitialise parser. */
- public void ReInit(CharStream stream) {
- jjmatchedPos = jjnewStateCnt = 0;
- curLexState = defaultLexState;
- input_stream = stream;
- ReInitRounds();
- }
+/** Lex State array. */
+public static final int[] jjnewLexState = {
+ -1, -1, 1, -1, 0, 2, 3, 0, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+};
+static final long[] jjtoToken = {
+ 0xfff807fffffffc03L, 0x3f007ffffffefffL,
+};
+static final long[] jjtoSkip = {
+ 0x190L, 0x0L,
+};
+static final long[] jjtoSpecial = {
+ 0x80L, 0x0L,
+};
+static final long[] jjtoMore = {
+ 0x26cL, 0x0L,
+};
+protected CharStream input_stream;
+private final int[] jjrounds = new int[517];
+private final int[] jjstateSet = new int[1034];
+private final StringBuilder jjimage = new StringBuilder();
+private StringBuilder image = jjimage;
+private int jjimageLen;
+private int lengthOfMatch;
+protected char curChar;
+/** Constructor. */
+public ParserTokenManager(CharStream stream){
+ input_stream = stream;
+}
- private void ReInitRounds() {
- int i;
- jjround = 0x80000001;
- for (i = 517; i-- > 0;) {
- jjrounds[i] = 0x80000000;
- }
- }
+/** Constructor. */
+public ParserTokenManager(CharStream stream, int lexState){
+ this(stream);
+ SwitchTo(lexState);
+}
- /** Reinitialise parser. */
- public void ReInit(CharStream stream, int lexState) {
- ReInit(stream);
- SwitchTo(lexState);
- }
+/** Reinitialise parser. */
+public void ReInit(CharStream stream)
+{
+ jjmatchedPos = jjnewStateCnt = 0;
+ curLexState = defaultLexState;
+ input_stream = stream;
+ ReInitRounds();
+}
+private void ReInitRounds()
+{
+ int i;
+ jjround = 0x80000001;
+ for (i = 517; i-- > 0;)
+ jjrounds[i] = 0x80000000;
+}
- /** Switch to specified lex state. */
- public void SwitchTo(int lexState) {
- if (lexState >= 4 || lexState < 0) {
- throw new TokenMgrError("Error: Ignoring invalid lexical state : "
- + lexState + ". State unchanged.",
- TokenMgrError.INVALID_LEXICAL_STATE);
- } else {
- curLexState = lexState;
- }
- }
+/** Reinitialise parser. */
+public void ReInit(CharStream stream, int lexState)
+{
+ ReInit(stream);
+ SwitchTo(lexState);
+}
- protected Token jjFillToken() {
- final Token t;
- final String curTokenImage;
- final int beginLine;
- final int endLine;
- final int beginColumn;
- final int endColumn;
- String im = jjstrLiteralImages[jjmatchedKind];
- curTokenImage = (im == null) ? input_stream.GetImage() : im;
- beginLine = input_stream.getBeginLine();
- beginColumn = input_stream.getBeginColumn();
- endLine = input_stream.getEndLine();
- endColumn = input_stream.getEndColumn();
- t = Token.newToken(jjmatchedKind, curTokenImage);
+/** Switch to specified lex state. */
+public void SwitchTo(int lexState)
+{
+ if (lexState >= 4 || lexState < 0)
+ throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
+ else
+ curLexState = lexState;
+}
- t.beginLine = beginLine;
- t.endLine = endLine;
- t.beginColumn = beginColumn;
- t.endColumn = endColumn;
+protected Token jjFillToken()
+{
+ final Token t;
+ final String curTokenImage;
+ final int beginLine;
+ final int endLine;
+ final int beginColumn;
+ final int endColumn;
+ String im = jjstrLiteralImages[jjmatchedKind];
+ curTokenImage = (im == null) ? input_stream.GetImage() : im;
+ beginLine = input_stream.getBeginLine();
+ beginColumn = input_stream.getBeginColumn();
+ endLine = input_stream.getEndLine();
+ endColumn = input_stream.getEndColumn();
+ t = Token.newToken(jjmatchedKind, curTokenImage);
- return t;
- }
+ t.beginLine = beginLine;
+ t.endLine = endLine;
+ t.beginColumn = beginColumn;
+ t.endColumn = endColumn;
- int curLexState = 0;
- int defaultLexState = 0;
- int jjnewStateCnt;
- int jjround;
- int jjmatchedPos;
- int jjmatchedKind;
+ return t;
+}
- /** Get the next Token. */
- public Token getNextToken() {
- Token specialToken = null;
- Token matchedToken;
- int curPos = 0;
+int curLexState = 0;
+int defaultLexState = 0;
+int jjnewStateCnt;
+int jjround;
+int jjmatchedPos;
+int jjmatchedKind;
- EOFLoop: for (;;) {
- try {
- curChar = input_stream.BeginToken();
- } catch (java.io.IOException e) {
- jjmatchedKind = 0;
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- return matchedToken;
- }
- image = jjimage;
- image.setLength(0);
- jjimageLen = 0;
+/** Get the next Token. */
+public Token getNextToken()
+{
+ Token specialToken = null;
+ Token matchedToken;
+ int curPos = 0;
- for (;;) {
- switch (curLexState) {
- case 0:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_0();
- if (jjmatchedPos == 0 && jjmatchedKind > 119) {
- jjmatchedKind = 119;
- }
- break;
- case 1:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_1();
- break;
- case 2:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_2();
- if (jjmatchedPos == 0 && jjmatchedKind > 9) {
- jjmatchedKind = 9;
- }
- break;
- case 3:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_3();
- if (jjmatchedPos == 0 && jjmatchedKind > 9) {
- jjmatchedKind = 9;
- }
- break;
- }
- if (jjmatchedKind != 0x7fffffff) {
- if (jjmatchedPos + 1 < curPos) {
- input_stream.backup(curPos - jjmatchedPos - 1);
- }
- if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) {
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- TokenLexicalActions(matchedToken);
- if (jjnewLexState[jjmatchedKind] != -1) {
- curLexState = jjnewLexState[jjmatchedKind];
- }
- return matchedToken;
- } else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) {
- if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) {
- matchedToken = jjFillToken();
- if (specialToken == null) {
- specialToken = matchedToken;
- } else {
- matchedToken.specialToken = specialToken;
- specialToken = (specialToken.next = matchedToken);
- }
- SkipLexicalActions(matchedToken);
- } else {
- SkipLexicalActions(null);
- }
- if (jjnewLexState[jjmatchedKind] != -1) {
- curLexState = jjnewLexState[jjmatchedKind];
- }
- continue EOFLoop;
- }
- MoreLexicalActions();
- if (jjnewLexState[jjmatchedKind] != -1) {
- curLexState = jjnewLexState[jjmatchedKind];
- }
- curPos = 0;
- jjmatchedKind = 0x7fffffff;
- try {
- curChar = input_stream.readChar();
- continue;
- } catch (java.io.IOException e1) {
- }
- }
- int error_line = input_stream.getEndLine();
- int error_column = input_stream.getEndColumn();
- String error_after = null;
- boolean EOFSeen = false;
- try {
- input_stream.readChar();
- input_stream.backup(1);
- } catch (java.io.IOException e1) {
- EOFSeen = true;
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- if (curChar == '\n' || curChar == '\r') {
- error_line++;
- error_column = 0;
- } else {
- error_column++;
- }
- }
- if (!EOFSeen) {
- input_stream.backup(1);
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- }
- throw new TokenMgrError(EOFSeen, curLexState, error_line,
- error_column, error_after, curChar,
- TokenMgrError.LEXICAL_ERROR);
- }
- }
- }
+ EOFLoop :
+ for (;;)
+ {
+ try
+ {
+ curChar = input_stream.BeginToken();
+ }
+ catch(java.io.IOException e)
+ {
+ jjmatchedKind = 0;
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ return matchedToken;
+ }
+ image = jjimage;
+ image.setLength(0);
+ jjimageLen = 0;
- void SkipLexicalActions(Token matchedToken) {
- switch (jjmatchedKind) {
- default:
- break;
+ for (;;)
+ {
+ switch(curLexState)
+ {
+ case 0:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_0();
+ if (jjmatchedPos == 0 && jjmatchedKind > 121)
+ {
+ jjmatchedKind = 121;
+ }
+ break;
+ case 1:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_1();
+ break;
+ case 2:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_2();
+ if (jjmatchedPos == 0 && jjmatchedKind > 9)
+ {
+ jjmatchedKind = 9;
+ }
+ break;
+ case 3:
+ jjmatchedKind = 0x7fffffff;
+ jjmatchedPos = 0;
+ curPos = jjMoveStringLiteralDfa0_3();
+ if (jjmatchedPos == 0 && jjmatchedKind > 9)
+ {
+ jjmatchedKind = 9;
+ }
+ break;
+ }
+ if (jjmatchedKind != 0x7fffffff)
+ {
+ if (jjmatchedPos + 1 < curPos)
+ input_stream.backup(curPos - jjmatchedPos - 1);
+ if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ matchedToken.specialToken = specialToken;
+ TokenLexicalActions(matchedToken);
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ return matchedToken;
}
- }
-
- void MoreLexicalActions() {
- jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
- switch (jjmatchedKind) {
- case 5:
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- input_stream.backup(1);
- break;
- default:
- break;
+ else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
+ {
+ matchedToken = jjFillToken();
+ if (specialToken == null)
+ specialToken = matchedToken;
+ else
+ {
+ matchedToken.specialToken = specialToken;
+ specialToken = (specialToken.next = matchedToken);
+ }
+ SkipLexicalActions(matchedToken);
+ }
+ else
+ SkipLexicalActions(null);
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ continue EOFLoop;
}
- }
-
- void TokenLexicalActions(Token matchedToken) {
- switch (jjmatchedKind) {
- case 1:
- image.append(input_stream.GetSuffix(jjimageLen
- + (lengthOfMatch = jjmatchedPos + 1)));
- image = Parser.SPACE;
- break;
- default:
- break;
+ MoreLexicalActions();
+ if (jjnewLexState[jjmatchedKind] != -1)
+ curLexState = jjnewLexState[jjmatchedKind];
+ curPos = 0;
+ jjmatchedKind = 0x7fffffff;
+ try {
+ curChar = input_stream.readChar();
+ continue;
}
- }
-
- private void jjCheckNAdd(int state) {
- if (jjrounds[state] != jjround) {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
+ catch (java.io.IOException e1) { }
+ }
+ int error_line = input_stream.getEndLine();
+ int error_column = input_stream.getEndColumn();
+ String error_after = null;
+ boolean EOFSeen = false;
+ try { input_stream.readChar(); input_stream.backup(1); }
+ catch (java.io.IOException e1) {
+ EOFSeen = true;
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ if (curChar == '\n' || curChar == '\r') {
+ error_line++;
+ error_column = 0;
}
- }
-
- private void jjAddStates(int start, int end) {
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
- }
+ else
+ error_column++;
+ }
+ if (!EOFSeen) {
+ input_stream.backup(1);
+ error_after = curPos <= 1 ? "" : input_stream.GetImage();
+ }
+ throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
+ }
+ }
+}
- private void jjCheckNAddTwoStates(int state1, int state2) {
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
- }
+void SkipLexicalActions(Token matchedToken)
+{
+ switch(jjmatchedKind)
+ {
+ default :
+ break;
+ }
+}
+void MoreLexicalActions()
+{
+ jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
+ switch(jjmatchedKind)
+ {
+ case 5 :
+ image.append(input_stream.GetSuffix(jjimageLen));
+ jjimageLen = 0;
+ input_stream.backup(1);
+ break;
+ default :
+ break;
+ }
+}
+void TokenLexicalActions(Token matchedToken)
+{
+ switch(jjmatchedKind)
+ {
+ case 1 :
+ image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
+ image = Parser.SPACE;
+ break;
+ default :
+ break;
+ }
+}
+private void jjCheckNAdd(int state)
+{
+ if (jjrounds[state] != jjround)
+ {
+ jjstateSet[jjnewStateCnt++] = state;
+ jjrounds[state] = jjround;
+ }
+}
+private void jjAddStates(int start, int end)
+{
+ do {
+ jjstateSet[jjnewStateCnt++] = jjnextStates[start];
+ } while (start++ != end);
+}
+private void jjCheckNAddTwoStates(int state1, int state2)
+{
+ jjCheckNAdd(state1);
+ jjCheckNAdd(state2);
+}
- private void jjCheckNAddStates(int start, int end) {
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
- }
+private void jjCheckNAddStates(int start, int end)
+{
+ do {
+ jjCheckNAdd(jjnextStates[start]);
+ } while (start++ != end);
+}
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/parser/SCSSLexicalUnit.java b/theme-compiler/src/com/vaadin/sass/internal/parser/SCSSLexicalUnit.java
index 935e4e5abd..709d1d3576 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/parser/SCSSLexicalUnit.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/parser/SCSSLexicalUnit.java
@@ -19,6 +19,8 @@ import org.w3c.css.sac.LexicalUnit;
public interface SCSSLexicalUnit extends LexicalUnit {
static final short SCSS_VARIABLE = 100;
+ static final short SCSS_OPERATOR_LEFT_PAREN = 101;
+ static final short SCSS_OPERATOR_RIGHT_PAREN = 102;
static final short SAC_LEM = 200;
static final short SAC_REM = 201;
@@ -31,4 +33,6 @@ public interface SCSSLexicalUnit extends LexicalUnit {
LexicalUnitImpl multiply(LexicalUnitImpl another);
+ LexicalUnitImpl modulo(LexicalUnitImpl another);
+
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/resolver/ClassloaderResolver.java b/theme-compiler/src/com/vaadin/sass/internal/resolver/ClassloaderResolver.java
index 7ab789ca3f..8711a0a3e9 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/resolver/ClassloaderResolver.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/resolver/ClassloaderResolver.java
@@ -40,6 +40,12 @@ public class ClassloaderResolver implements ScssStylesheetResolver {
// Ensure only "/" is used, also in Windows
fileName = fileName.replace(File.separatorChar, '/');
+ // Filename should be a relative path starting with VAADIN/...
+ int vaadinIdx = fileName.lastIndexOf("VAADIN/");
+ if (vaadinIdx > -1) {
+ fileName = fileName.substring(vaadinIdx);
+ }
+
// Can the classloader find it?
InputStream is = getClass().getClassLoader().getResourceAsStream(
fileName);
diff --git a/theme-compiler/src/com/vaadin/sass/internal/resolver/VaadinResolver.java b/theme-compiler/src/com/vaadin/sass/internal/resolver/VaadinResolver.java
index f51201da06..fec16a54c8 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/resolver/VaadinResolver.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/resolver/VaadinResolver.java
@@ -15,8 +15,8 @@
*/
package com.vaadin.sass.internal.resolver;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import java.io.File;
+import java.util.Stack;
import org.w3c.css.sac.InputSource;
@@ -24,41 +24,67 @@ public class VaadinResolver implements ScssStylesheetResolver {
@Override
public InputSource resolve(String identifier) {
- if (identifier.endsWith(".css")) {
- // CSS support mainly for testing, don't load from classpath etc
- ScssStylesheetResolver resolver = new FilesystemResolver();
- return resolver.resolve(identifier);
- }
+
+ // Remove extra "." and ".."
+ identifier = normalize(identifier);
InputSource source = null;
- Pattern pattern = Pattern
- .compile("\\.\\.\\/([^\\/]+)\\/([^\\/]+\\.scss)");
- Matcher matcher = pattern.matcher(identifier);
+ // Can we find the scss from the file system?
+ ScssStylesheetResolver resolver = new FilesystemResolver();
+ source = resolver.resolve(identifier);
- if (matcher.find()) {
- // theme include
- ScssStylesheetResolver resolver = new FilesystemResolver();
+ if (source == null) {
+ // How about the classpath?
+ resolver = new ClassloaderResolver();
source = resolver.resolve(identifier);
+ }
- if (source == null) {
- String themeName = matcher.group(1);
- String fileName = matcher.group(2);
- resolver = new ClassloaderResolver();
- String id = "VAADIN/themes/" + themeName + "/" + fileName;
- source = resolver.resolve(id);
- }
+ return source;
+ }
- } else {
- ScssStylesheetResolver resolver = new FilesystemResolver();
- source = resolver.resolve(identifier);
+ /**
+ * Normalizes "." and ".." from the path string where parent path segments
+ * can be removed. Preserve leading "..".
+ *
+ * @param path
+ * A relative or absolute file path
+ * @return The normalized path
+ */
+ private static String normalize(String path) {
- if (source == null) {
- resolver = new ClassloaderResolver();
- source = resolver.resolve(identifier);
+ // Ensure only "/" is used, also in Windows
+ path = path.replace(File.separatorChar, '/');
+
+ // Split into segments
+ String[] segments = path.split("/");
+ Stack<String> result = new Stack<String>();
+
+ // Replace '.' and '..' segments
+ for (int i = 0; i < segments.length; i++) {
+ if (segments[i].equals(".")) {
+ // Segments marked '.' are ignored
+
+ } else if (segments[i].equals("..") && !result.isEmpty()
+ && !result.lastElement().equals("..")) {
+ // If segment is ".." then remove the previous iff the previous
+ // element is not a ".." and the result stack is not empty
+ result.pop();
+ } else {
+ // Other segments are just added to the stack
+ result.push(segments[i]);
}
}
- return source;
+ // Reconstruct path
+ StringBuilder pathBuilder = new StringBuilder();
+ for (int i = 0; i < result.size(); i++) {
+ if (i > 0) {
+ pathBuilder.append("/");
+ }
+ pathBuilder.append(result.get(i));
+ }
+ return pathBuilder.toString();
}
+
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/ContentNode.java b/theme-compiler/src/com/vaadin/sass/internal/tree/ContentNode.java
new file mode 100644
index 0000000000..10cb1599c1
--- /dev/null
+++ b/theme-compiler/src/com/vaadin/sass/internal/tree/ContentNode.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ * ContentNode represents a {@literal @}content in a SCSS tree.
+ */
+package com.vaadin.sass.internal.tree;
+
+public class ContentNode extends Node {
+
+ @Override
+ public void traverse() {
+ /*
+ * ContentNode is basically just a placeholder for some content which
+ * will be included. So for traverse of this node, it does nothing. it
+ * will be replaced when traversing MixinDefNode which contains it.
+ */
+ }
+
+}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/MixinDefNode.java b/theme-compiler/src/com/vaadin/sass/internal/tree/MixinDefNode.java
index d3dce12c48..bae1475076 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/tree/MixinDefNode.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/tree/MixinDefNode.java
@@ -85,4 +85,38 @@ public class MixinDefNode extends Node implements IVariableNode {
}
}
+ /**
+ * This should only happen on a cloned MixinDefNode, since it changes the
+ * Node itself.
+ *
+ * @param mixinNode
+ * @return
+ */
+ public MixinDefNode replaceContentDirective(MixinNode mixinNode) {
+ return findAndReplaceContentNodeInChildren(this, mixinNode);
+ }
+
+ private MixinDefNode findAndReplaceContentNodeInChildren(Node node,
+ MixinNode mixinNode) {
+ ContentNode contentNode = null;
+ for (Node child : new ArrayList<Node>(node.getChildren())) {
+ if (child instanceof ContentNode) {
+ contentNode = (ContentNode) child;
+ replaceContentNode(contentNode, mixinNode);
+ } else {
+ findAndReplaceContentNodeInChildren(child, mixinNode);
+ }
+ }
+ return this;
+ }
+
+ public MixinDefNode replaceContentNode(ContentNode contentNode,
+ MixinNode mixinNode) {
+ if (contentNode != null) {
+ contentNode.getParentNode().appendChildrenAfter(
+ DeepCopy.copy(mixinNode.getChildren()), contentNode);
+ contentNode.getParentNode().removeChild(contentNode);
+ }
+ return this;
+ }
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/MixinNode.java b/theme-compiler/src/com/vaadin/sass/internal/tree/MixinNode.java
index 755c2d5c88..e702bc8577 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/tree/MixinNode.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/tree/MixinNode.java
@@ -30,10 +30,13 @@ public class MixinNode extends Node implements IVariableNode {
private String name;
private ArrayList<LexicalUnitImpl> arglist;
- public MixinNode(String name, Collection<LexicalUnitImpl> args) {
- super();
+ public MixinNode(String name) {
this.name = name;
arglist = new ArrayList<LexicalUnitImpl>();
+ }
+
+ public MixinNode(String name, Collection<LexicalUnitImpl> args) {
+ this(name);
if (args != null && !args.isEmpty()) {
arglist.addAll(args);
}
@@ -69,7 +72,8 @@ public class MixinNode extends Node implements IVariableNode {
for (final LexicalUnitImpl arg : new ArrayList<LexicalUnitImpl>(
arglist)) {
LexicalUnitImpl unit = arg;
- // only perform replace in the value if separate argument name
+ // only perform replace in the value if separate argument
+ // name
// and value
if (unit.getNextLexicalUnit() != null) {
unit = unit.getNextLexicalUnit();
@@ -89,7 +93,15 @@ public class MixinNode extends Node implements IVariableNode {
name = var.getExpr().toString();
}
}
+ }
+ }
+ protected void replaceVariablesForChildren() {
+ for (Node child : getChildren()) {
+ if (child instanceof IVariableNode) {
+ ((IVariableNode) child).replaceVariables(ScssStylesheet
+ .getVariables());
+ }
}
}
@@ -101,6 +113,7 @@ public class MixinNode extends Node implements IVariableNode {
.openVariableScope();
replaceVariables(ScssStylesheet.getVariables());
+ replaceVariablesForChildren();
MixinNodeHandler.traverse(this);
ScssStylesheet.closeVariableScope(variableScope);
diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/Node.java b/theme-compiler/src/com/vaadin/sass/internal/tree/Node.java
index 9a2cc6371e..98b701d5a9 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/tree/Node.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/tree/Node.java
@@ -45,6 +45,23 @@ public abstract class Node implements Serializable {
}
}
+ public void appendChildrenAfter(Collection<Node> childrenNodes, Node after) {
+ if (childrenNodes != null && !childrenNodes.isEmpty()) {
+ int index = children.indexOf(after);
+ if (index != -1) {
+ children.addAll(index, childrenNodes);
+ for (final Node child : childrenNodes) {
+ if (child.getParentNode() != null) {
+ child.getParentNode().removeChild(child);
+ }
+ child.setParentNode(this);
+ }
+ } else {
+ throw new NullPointerException("after-node was not found");
+ }
+ }
+ }
+
public void appendChild(Node node) {
if (node != null) {
children.add(node);
diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/RuleNode.java b/theme-compiler/src/com/vaadin/sass/internal/tree/RuleNode.java
index a78d9d66d2..19880e4ce5 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/tree/RuleNode.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/tree/RuleNode.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.regex.Pattern;
import com.vaadin.sass.internal.ScssStylesheet;
+import com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator;
import com.vaadin.sass.internal.parser.LexicalUnitImpl;
import com.vaadin.sass.internal.util.StringUtil;
@@ -140,6 +141,20 @@ public class RuleNode extends Node implements IVariableNode {
@Override
public void traverse() {
- replaceVariables(ScssStylesheet.getVariables());
+ /*
+ * "replaceVariables(ScssStylesheet.getVariables());" seems duplicated
+ * and can be extracted out of if, but it is not.
+ * containsArithmeticalOperator must be called before replaceVariables.
+ * Because for the "/" operator, it needs to see if its predecessor or
+ * successor is a Variable or not, to determine it is an arithmetic
+ * operator.
+ */
+ if (ArithmeticExpressionEvaluator.get().containsArithmeticalOperator(
+ value)) {
+ replaceVariables(ScssStylesheet.getVariables());
+ value = ArithmeticExpressionEvaluator.get().evaluate(value);
+ } else {
+ replaceVariables(ScssStylesheet.getVariables());
+ }
}
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/tree/VariableNode.java b/theme-compiler/src/com/vaadin/sass/internal/tree/VariableNode.java
index 90be727f88..f2499d72ab 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/tree/VariableNode.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/tree/VariableNode.java
@@ -19,6 +19,7 @@ package com.vaadin.sass.internal.tree;
import java.util.ArrayList;
import com.vaadin.sass.internal.ScssStylesheet;
+import com.vaadin.sass.internal.expression.ArithmeticExpressionEvaluator;
import com.vaadin.sass.internal.parser.LexicalUnitImpl;
import com.vaadin.sass.internal.util.StringUtil;
import com.vaadin.sass.internal.visitor.VariableNodeHandler;
@@ -101,7 +102,21 @@ public class VariableNode extends Node implements IVariableNode {
@Override
public void traverse() {
- replaceVariables(ScssStylesheet.getVariables());
+ /*
+ * "replaceVariables(ScssStylesheet.getVariables());" seems duplicated
+ * and can be extracted out of if, but it is not.
+ * containsArithmeticalOperator must be called before replaceVariables.
+ * Because for the "/" operator, it needs to see if its predecessor or
+ * successor is a Variable or not, to determine it is an arithmetic
+ * operator.
+ */
+ if (ArithmeticExpressionEvaluator.get().containsArithmeticalOperator(
+ expr)) {
+ replaceVariables(ScssStylesheet.getVariables());
+ expr = ArithmeticExpressionEvaluator.get().evaluate(expr);
+ } else {
+ replaceVariables(ScssStylesheet.getVariables());
+ }
VariableNodeHandler.traverse(this);
}
}
diff --git a/theme-compiler/src/com/vaadin/sass/internal/util/DeepCopy.java b/theme-compiler/src/com/vaadin/sass/internal/util/DeepCopy.java
index 6b16183588..bc30ffdd6c 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/util/DeepCopy.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/util/DeepCopy.java
@@ -19,6 +19,9 @@ package com.vaadin.sass.internal.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
/**
* Utility for making deep copies (vs. clone()'s shallow copies) of objects.
@@ -70,4 +73,11 @@ public class DeepCopy {
}
}
+ public static <T> Collection<T> copy(Collection<T> objects) {
+ List<T> copies = new LinkedList<T>();
+ for (T object : objects) {
+ copies.add((T) copy(object));
+ }
+ return copies;
+ }
} \ No newline at end of file
diff --git a/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java b/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java
index 5593241297..e356ed3525 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/visitor/ImportNodeHandler.java
@@ -67,12 +67,9 @@ public class ImportNodeHandler {
updateUrlInImportedSheet(imported, prefix);
}
- Node pre = importNode;
- for (Node importedChild : new ArrayList<Node>(
- imported.getChildren())) {
- node.appendChild(importedChild, pre);
- pre = importedChild;
- }
+ node.appendChildrenAfter(
+ new ArrayList<Node>(imported.getChildren()),
+ importNode);
node.removeChild(importNode);
} catch (CSSException e) {
e.printStackTrace();
diff --git a/theme-compiler/src/com/vaadin/sass/internal/visitor/MixinNodeHandler.java b/theme-compiler/src/com/vaadin/sass/internal/visitor/MixinNodeHandler.java
index 4e54416522..feb1d7e622 100644
--- a/theme-compiler/src/com/vaadin/sass/internal/visitor/MixinNodeHandler.java
+++ b/theme-compiler/src/com/vaadin/sass/internal/visitor/MixinNodeHandler.java
@@ -45,19 +45,19 @@ public class MixinNodeHandler {
private static void replaceMixinNode(MixinNode mixinNode,
MixinDefNode mixinDef) {
- Node pre = mixinNode;
-
MixinDefNode defClone = (MixinDefNode) DeepCopy.copy(mixinDef);
defClone.traverse();
+ defClone.replaceContentDirective(mixinNode);
+
if (mixinDef.getArglist().isEmpty()) {
- for (Node child : new ArrayList<Node>(defClone.getChildren())) {
- mixinNode.getParentNode().appendChild(child, pre);
- pre = child;
- }
+ mixinNode.getParentNode().appendChildrenAfter(
+ new ArrayList<Node>(defClone.getChildren()), mixinNode);
} else {
-
- replacePossibleArguments(mixinNode, defClone);
+ if (mixinNode.getArglist() != null
+ && !mixinNode.getArglist().isEmpty()) {
+ replacePossibleArguments(mixinNode, defClone);
+ }
Node previous = mixinNode;
for (final Node child : new ArrayList<Node>(defClone.getChildren())) {
@@ -81,7 +81,6 @@ public class MixinNodeHandler {
*/
private static void replacePossibleArguments(MixinNode mixinNode,
MixinDefNode def) {
-
if (mixinNode.getArglist().size() > 0) {
ArrayList<VariableNode> remainingNodes = new ArrayList<VariableNode>(
def.getArglist());
diff --git a/theme-compiler/tests/resources/automatic/css/basic_arithmetics.css b/theme-compiler/tests/resources/automatic/css/basic_arithmetics.css
new file mode 100644
index 0000000000..9fd33f2efe
--- /dev/null
+++ b/theme-compiler/tests/resources/automatic/css/basic_arithmetics.css
@@ -0,0 +1,31 @@
+.foo {
+ font: 10px / 8px;
+ font: 5px;
+ margin-left: 9px;
+}
+
+.foo {
+ size: 1;
+}
+
+.foo {
+ bar: 8;
+ bar: 8;
+ bar: 12;
+}
+
+.foo {
+ bar: 2 3;
+ bar: 5;
+ bar: 5;
+}
+
+.foo {
+ bar: 2 -3;
+ bar: -1;
+ bar: -1;
+}
+
+.foo {
+ bar: 14;
+} \ No newline at end of file
diff --git a/theme-compiler/tests/resources/automatic/css/mixin-content-directive-with-vars.css b/theme-compiler/tests/resources/automatic/css/mixin-content-directive-with-vars.css
new file mode 100644
index 0000000000..799d6ae90c
--- /dev/null
+++ b/theme-compiler/tests/resources/automatic/css/mixin-content-directive-with-vars.css
@@ -0,0 +1,5 @@
+.colors {
+ background-color: blue;
+ color: white;
+ border-color: blue;
+} \ No newline at end of file
diff --git a/theme-compiler/tests/resources/automatic/css/mixin-content-directive.css b/theme-compiler/tests/resources/automatic/css/mixin-content-directive.css
new file mode 100644
index 0000000000..07813d1c99
--- /dev/null
+++ b/theme-compiler/tests/resources/automatic/css/mixin-content-directive.css
@@ -0,0 +1,20 @@
+.foobar {
+ color: red;
+}
+
+.foobar {
+ background-color: blue;
+}
+
+* html #logo {
+ background-image: url(/logo.gif);
+}
+
+* html .link {
+ color: blue;
+}
+
+.foobar {
+ color: red;
+ color: red;
+} \ No newline at end of file
diff --git a/theme-compiler/tests/resources/automatic/scss/basic_arithmetics.scss b/theme-compiler/tests/resources/automatic/scss/basic_arithmetics.scss
new file mode 100644
index 0000000000..cc913fe048
--- /dev/null
+++ b/theme-compiler/tests/resources/automatic/scss/basic_arithmetics.scss
@@ -0,0 +1,44 @@
+/*
+*supports:
+* 1. standard arithmetic operations (+, -, *, /, %)
+* 2. / is treated as css operator, unless one of its operands is variable or there is another binary arithmetic operator
+*limits:
+* 1. cannot mix arithmetic and css operations, e.g. "margin: 1px + 3px 2px" will fail
+* 2. space between add and minus operator and their following operand is mandatory. e.g. "1 + 2" is valid, "1+2" is not
+* 3. parenthesis is not supported now.
+*/
+
+$div: 10px;
+.foo {
+ font: 10px/8px; // Plain CSS, no division
+ font: $div/2; // Uses a variable, does division
+ margin-left: 5px + 8px/2px; //Uses +, does division
+}
+
+.foo{
+ size: 5 % 2; // modular
+}
+
+$mul: 2*4; //valid multiply in variable
+$mul1: 2 * 4; //valid multiply in variable
+.foo{
+ bar: $mul;
+ bar: $mul1;
+ bar: 3*4; //valid multiply in declaration
+}
+
+.foo {
+ bar: 2 +3; //'+' is regarded as an unary operator, because no space between '+' and '3'
+ bar: 2+ 3; //valid add expression
+ bar: 2 + 3; //beautiful valid add expression
+}
+
+.foo {
+ bar: 2 -3; //'-' is regarded as an unary operator, because no space between '-' and '3'
+ bar: 2 - 3; //beautiful valid minus expression
+ bar: 2- 3; //valid minus expression
+}
+
+.foo {
+ bar: 2 + 3 * 4; // combinations
+} \ No newline at end of file
diff --git a/theme-compiler/tests/resources/automatic/scss/mixin-content-directive-with-vars.scss b/theme-compiler/tests/resources/automatic/scss/mixin-content-directive-with-vars.scss
new file mode 100644
index 0000000000..e7e0c3b7e6
--- /dev/null
+++ b/theme-compiler/tests/resources/automatic/scss/mixin-content-directive-with-vars.scss
@@ -0,0 +1,9 @@
+$color: white;
+@mixin colors($color: blue) {
+ background-color: $color;
+ @content;
+ border-color: $color;
+}
+.colors {
+ @include colors { color: $color; }
+} \ No newline at end of file
diff --git a/theme-compiler/tests/resources/automatic/scss/mixin-content-directive.scss b/theme-compiler/tests/resources/automatic/scss/mixin-content-directive.scss
new file mode 100644
index 0000000000..71217cb814
--- /dev/null
+++ b/theme-compiler/tests/resources/automatic/scss/mixin-content-directive.scss
@@ -0,0 +1,40 @@
+@mixin my-mixin {
+ .foobar {
+ @content;
+ }
+}
+
+@include my-mixin {
+ color: red;
+}
+
+@include my-mixin {
+ background-color: blue;
+}
+
+@mixin apply-to-ie6-only {
+ * html {
+ @content;
+ }
+}
+@include apply-to-ie6-only {
+ #logo {
+ background-image: url(/logo.gif);
+ }
+}
+@include apply-to-ie6-only {
+ .link {
+ color: blue;
+ }
+}
+
+@mixin mixin-multi-contents {
+ .foobar {
+ @content;
+ @content;
+ }
+}
+
+@include mixin-multi-contents {
+ color: red;
+} \ No newline at end of file
diff --git a/theme-compiler/tests/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluatorTest.java b/theme-compiler/tests/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluatorTest.java
new file mode 100644
index 0000000000..8978eb812e
--- /dev/null
+++ b/theme-compiler/tests/src/com/vaadin/sass/internal/expression/ArithmeticExpressionEvaluatorTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.sass.internal.expression;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.w3c.css.sac.LexicalUnit;
+
+import com.vaadin.sass.internal.expression.exception.IncompatibleUnitsException;
+import com.vaadin.sass.internal.parser.LexicalUnitImpl;
+
+public class ArithmeticExpressionEvaluatorTest {
+ private ArithmeticExpressionEvaluator evaluator = new ArithmeticExpressionEvaluator();
+
+ @Test
+ public void testPrecedenceSameAsAppearOrder() {
+ // 2 * 3 - 4 = 2
+ LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, null, 2);
+ LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0,
+ operand2);
+ LexicalUnitImpl operand3 = LexicalUnitImpl.createInteger(0, 0,
+ operatorMultiply, 3);
+ LexicalUnitImpl operatorMinus = LexicalUnitImpl.createMinus(0, 0,
+ operand3);
+ LexicalUnitImpl operand4 = LexicalUnitImpl.createInteger(0, 0,
+ operatorMinus, 4);
+ LexicalUnitImpl result = evaluator.evaluate(operand2);
+ Assert.assertEquals(2, result.getIntegerValue());
+ }
+
+ @Test
+ public void testPrecedenceDifferFromAppearOrder() {
+ // 2 - 3 * 4 = -10
+ LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, null, 2);
+ LexicalUnitImpl operatorMinus = LexicalUnitImpl.createMinus(0, 0,
+ operand2);
+ LexicalUnitImpl operand3 = LexicalUnitImpl.createInteger(0, 0,
+ operatorMinus, 3);
+ LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0,
+ operand3);
+ LexicalUnitImpl operand4 = LexicalUnitImpl.createInteger(0, 0,
+ operatorMultiply, 4);
+ LexicalUnitImpl result = evaluator.evaluate(operand2);
+ Assert.assertEquals(-10, result.getIntegerValue());
+ }
+
+ @Test(expected = IncompatibleUnitsException.class)
+ public void testIncompatibleUnit() {
+ // 2cm - 3px
+ LexicalUnitImpl operand2 = LexicalUnitImpl.createCM(0, 0, null, 2);
+ LexicalUnitImpl operatorMinus = LexicalUnitImpl.createMinus(0, 0,
+ operand2);
+ LexicalUnitImpl operand3 = LexicalUnitImpl.createPX(0, 0,
+ operatorMinus, 3);
+ evaluator.evaluate(operand2);
+ }
+
+ @Test
+ public void testMultiplyWithUnitInfirstOperand() {
+ // 2cm * 3 = 6cm
+ LexicalUnitImpl operand2cm = LexicalUnitImpl.createCM(0, 0, null, 2);
+ LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0,
+ operand2cm);
+ LexicalUnitImpl operand3 = LexicalUnitImpl.createInteger(0, 0,
+ operatorMultiply, 3);
+ LexicalUnitImpl result = evaluator.evaluate(operand2cm);
+ Assert.assertEquals(6, result.getIntegerValue());
+ Assert.assertEquals(LexicalUnit.SAC_CENTIMETER,
+ result.getLexicalUnitType());
+ }
+
+ @Test
+ public void testMultiplyWithUnitInSecondOperand() {
+ // 2 * 3cm = 6cm
+ LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0, null, 2);
+ LexicalUnitImpl operatorMultiply = LexicalUnitImpl.createMultiply(0, 0,
+ operand2);
+ LexicalUnitImpl operand3cm = LexicalUnitImpl.createCM(0, 0,
+ operatorMultiply, 3);
+ LexicalUnitImpl result = evaluator.evaluate(operand2);
+ Assert.assertEquals(6, result.getIntegerValue());
+ Assert.assertEquals(LexicalUnit.SAC_CENTIMETER,
+ result.getLexicalUnitType());
+ }
+
+ @Test
+ public void testDivideWithSameUnit() {
+ // 4cm / 2cm = 2
+ LexicalUnitImpl operand4cm = LexicalUnitImpl.createCM(0, 0, null, 4);
+ LexicalUnitImpl operatorDivide = LexicalUnitImpl.createSlash(0, 0,
+ operand4cm);
+ LexicalUnitImpl operand2cm = LexicalUnitImpl.createCM(0, 0,
+ operatorDivide, 2);
+ LexicalUnitImpl result = evaluator.evaluate(operand4cm);
+ Assert.assertEquals(2, result.getIntegerValue());
+ Assert.assertEquals(LexicalUnit.SAC_REAL, result.getLexicalUnitType());
+ }
+
+ @Test
+ public void testDivideDenominatorWithoutUnit() {
+ // 4cm / 2 = 2cm
+ LexicalUnitImpl operand4cm = LexicalUnitImpl.createCM(0, 0, null, 4);
+ LexicalUnitImpl operatorDivide = LexicalUnitImpl.createSlash(0, 0,
+ operand4cm);
+ LexicalUnitImpl operand2 = LexicalUnitImpl.createInteger(0, 0,
+ operatorDivide, 2);
+ LexicalUnitImpl result = evaluator.evaluate(operand4cm);
+ Assert.assertEquals(2, result.getIntegerValue());
+ Assert.assertEquals(LexicalUnit.SAC_CENTIMETER,
+ result.getLexicalUnitType());
+ }
+}
diff --git a/theme-compiler/tests/src/com/vaadin/sass/resolvers/VaadinResolverTest.java b/theme-compiler/tests/src/com/vaadin/sass/resolvers/VaadinResolverTest.java
new file mode 100644
index 0000000000..59b49888c2
--- /dev/null
+++ b/theme-compiler/tests/src/com/vaadin/sass/resolvers/VaadinResolverTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+/**
+ *
+ */
+package com.vaadin.sass.resolvers;
+
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+import java.lang.reflect.Method;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.vaadin.sass.internal.resolver.VaadinResolver;
+
+public class VaadinResolverTest {
+
+ @Test
+ public void testPathNormalization() throws Exception {
+
+ VaadinResolver resolver = new VaadinResolver();
+
+ Method normalizeMethod = VaadinResolver.class.getDeclaredMethod(
+ "normalize", String.class);
+ normalizeMethod.setAccessible(true);
+
+ String identifier, result;
+
+ identifier = "a/b/../../../a b/b.scss";
+ result = (String) normalizeMethod.invoke(resolver, identifier);
+ Assert.assertEquals("../a b/b.scss", result);
+
+ identifier = "./a/b/../c/d/.././e.scss";
+ result = (String) normalizeMethod.invoke(resolver, identifier);
+ Assert.assertEquals("a/c/e.scss", result);
+
+ identifier = "/äåäåäääå/:;:;:;/???????/- -/e.scss";
+ result = (String) normalizeMethod.invoke(resolver, identifier);
+ Assert.assertEquals("/äåäåäääå/:;:;:;/???????/- -/e.scss", result);
+
+ identifier = ".";
+ result = (String) normalizeMethod.invoke(resolver, identifier);
+ Assert.assertEquals("", result);
+
+ identifier = "../..";
+ result = (String) normalizeMethod.invoke(resolver, identifier);
+ Assert.assertEquals("../..", result);
+
+ identifier = "./../a.scss";
+ result = (String) normalizeMethod.invoke(resolver, identifier);
+ Assert.assertEquals("../a.scss", result);
+ }
+
+}
diff --git a/themes/build.xml b/themes/build.xml
index 6e9e3c9951..75b3e5a903 100644
--- a/themes/build.xml
+++ b/themes/build.xml
@@ -99,8 +99,8 @@
<target name="checkstyle">
<echo>No java files in module</echo>
</target>
- <target name="tests" depends="checkstyle">
- <!--<antcall target="common.tests.run" />-->
+ <target name="test" depends="checkstyle">
+ <!--<antcall target="common.test.run" />-->
<echo>WHAT? No tests for ${module.name}!</echo>
</target>
diff --git a/uitest/build.xml b/uitest/build.xml
index 53da0ae2e9..453fc26ea5 100644
--- a/uitest/build.xml
+++ b/uitest/build.xml
@@ -16,7 +16,7 @@
</path>
<target name="dependencies">
- <!-- This is copied from common.xml to be able to add server.tests.source to the source path -->
+ <!-- This is copied from common.xml to be able to add server.test.source to the source path -->
<ivy:resolve resolveid="common" conf="build, build-provided" />
<ivy:cachepath pathid="classpath.compile.dependencies" conf="build, build-provided" />
@@ -28,12 +28,12 @@
<property name="result.dir" location="result" />
<property name="src" location="${result.dir}/../src" />
<property name="classes" location="${result.dir}/classes" />
- <property name="server.tests.sources" location="${result.dir}/../../server/tests/src" />
+ <property name="server.test.sources" location="${result.dir}/../../server/tests/src" />
<mkdir dir="${classes}" />
<!-- TODO: Get rid of this -->
<javac destdir="${classes}" source="${vaadin.java.version}" target="${vaadin.java.version}" debug="true" encoding="UTF-8" includeantruntime="false">
- <src path="${server.tests.sources}" />
+ <src path="${server.test.sources}" />
<include name="com/vaadin/tests/data/bean/**" />
<include name="com/vaadin/tests/VaadinClasses.java" />
<include name="com/vaadin/data/util/sqlcontainer/SQLTestsConstants.java" />
@@ -140,8 +140,8 @@
<target name="checkstyle">
<echo>Checkstyle is disabled for uitest for now</echo>
</target>
- <target name="tests" depends="checkstyle">
- <!--<antcall target="common.tests.run" />-->
+ <target name="test" depends="checkstyle">
+ <!--<antcall target="common.test.run" />-->
<echo>WHAT? No JUnit tests for ${module.name}!</echo>
</target>
diff --git a/uitest/integration-testscripts/common/integration_push_test.tpl b/uitest/integration-testscripts/common/integration_push_test.tpl
new file mode 100644
index 0000000000..4e93f628e5
--- /dev/null
+++ b/uitest/integration-testscripts/common/integration_push_test.tpl
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://vaadin-integration-tests:8080/" />
+<title>integration_test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">integration_test</td></tr>
+</thead><tbody>
+<tr>
+ <td>openAndWait</td>
+ <td>/demo/run-push/com.vaadin.tests.integration.IntegrationTestApplication?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>1000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>initial</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=demorunpushcomvaadintestsintegrationIntegrationTestApplication::/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>51,13</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>finland</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml
index f8d250554c..cb96834307 100644
--- a/uitest/integration_tests.xml
+++ b/uitest/integration_tests.xml
@@ -13,7 +13,7 @@
<fail unless="test.integration.antfile" message="test.integration.antfile must be set for integration tests to run" />
<!-- Test with these browsers -->
- <property name="test_browsers" value="winxp-firefox11" />
+ <property name="test_browsers" value="winxp-firefox17-esr" />
<!-- Path to key file. Default value -->
<property name="sshkey.file" value="id_dsa" />
@@ -54,6 +54,23 @@
<fileset dir="." includes="test.xml" />
</subant>
</target>
+
+ <target name="integration-test-push-servlet">
+ <fileset dir="integration-testscripts" id="html-test-files" includes="integration-test-${server-name}-push-servlet.html" />
+ <pathconvert pathsep=" " property="testfiles" refid="html-test-files" />
+ <subant target="run-tests" failonerror="false" antfile="test.xml">
+ <property name="com.vaadin.testbench.lib.dir" value="${com.vaadin.testbench.lib.dir}" />
+ <property name="com.vaadin.testbench.tester.host" value="${com.vaadin.testbench.tester.host}" />
+ <property name="com.vaadin.testbench.deployment.url" value="${deployment.url}" />
+ <property name="server.start.succeeded" value="1" />
+ <property name="browsers" value="${test_browsers}" />
+ <property name="testfiles" value="${testfiles}" />
+ <property name="test-output-dir" value="${integration_test.dir}/result/integration-test-output/${server-name}" />
+ <property name="retries" value="0" />
+
+ <fileset dir="." includes="test.xml" />
+ </subant>
+ </target>
<target name="integration-test-theme">
<subant target="run-tests" failonerror="false" antfile="test.xml">
@@ -427,6 +444,24 @@
</antcontrib:then>
</antcontrib:if>
+ <!-- Run integration tests with push -->
+ <copy file="integration-testscripts/common/integration_push_test.tpl" tofile="integration-testscripts/integration-test-${target-server}-push-servlet.html" overwrite="true" />
+ <antcall target="integration-test-push-servlet">
+ <param name="server-name" value="${target-server}" />
+ <param name="deployment.url" value="http://${target-host}:${target-port}" />
+ </antcall>
+
+ <!-- Run theme tests in all browsers if there's a property with the test files -->
+ <antcontrib:if>
+ <isset property="testfiles-theme" />
+ <antcontrib:then>
+ <antcall target="integration-test-theme">
+ <param name="server-name" value="${target-server}" />
+ <param name="deployment.url" value="http://${target-host}:${target-port}" />
+ </antcall>
+ </antcontrib:then>
+ </antcontrib:if>
+
<!-- timeout in five minutes -->
<sshexec host="${target-host}" outputproperty="stop-output" timeout="600000" username="${user}" keyfile="${sshkey.file}" trust="yes" command="ant -f deploy.xml shutdown-and-cleanup" failonerror="false" />
<antcall target="echo-prefix">
diff --git a/uitest/ivy.xml b/uitest/ivy.xml
index 4196cca4da..bb54232852 100644
--- a/uitest/ivy.xml
+++ b/uitest/ivy.xml
@@ -40,6 +40,8 @@
rev="${vaadin.version}" conf="build->build"></dependency>
<dependency org="com.vaadin" name="vaadin-themes"
rev="${vaadin.version}" conf="build->build"></dependency>
+ <dependency org="com.vaadin" name="vaadin-push"
+ rev="${vaadin.version}" conf="build->build"></dependency>
<!-- For compiling TestingWidgetSet -->
<dependency org="com.vaadin" name="vaadin-client-compiler"
@@ -48,22 +50,23 @@
<!-- Newest Jetty does not work with Ivy currently (orbit -> jar
mapping problem) -->
<dependency org="org.eclipse.jetty" name="jetty-server"
- rev="7.4.5.v20110725" conf="build, ide, jetty-run->default" />
- <!-- jetty-servlets needed in .war by ProxyTest, but not by jetty-runner -->
+ rev="7.5.0.v20110901" conf="ide, build-provided, jetty-run->default" />
+ <!-- jetty-servlets needed by ProxyTest, but not by jetty-runner -->
<dependency org="org.eclipse.jetty" name="jetty-servlets"
- rev="7.4.5.v20110725" conf="build, ide->default" />
- <!-- <dependency org="org.mortbay.jetty" name="jetty-util" -->
- <!-- rev="8.1.5.v20120716" conf="build,ide,jetty-run->default" /> -->
+ rev="7.5.0.v20110901" conf="ide, build-provided, jetty-run->default" />
+ <dependency org="org.eclipse.jetty" name="jetty-websocket"
+ rev="7.5.0.v20110901" conf="ide, jetty-run->default" />
<dependency org="org.eclipse.jetty" name="jetty-webapp"
- rev="7.4.5.v20110725" conf="build, ide,jetty-run->default" />
+ rev="7.5.0.v20110901" conf="ide, build-provided, jetty-run->default" />
<dependency org="org.mortbay.jetty" name="jetty-runner"
- rev="7.4.5.v20110725" conf="jetty-run->default" />
+ rev="7.5.0.v20110901" conf="jetty-run->default" />
+
<dependency org="junit" name="junit" rev="4.5"
conf="build,ide -> default" />
<dependency org="commons-codec" name="commons-codec"
rev="1.5" conf="build,ide->default" />
- <dependency org="commons-io" name="commons-io" rev="1.4"
+ <dependency org="commons-io" name="commons-io" rev="2.2"
conf="build,ide->default" />
<!-- Mainly for SQLContainer tests -->
<dependency org="org.hsqldb" name="hsqldb" rev="2.2.6"
diff --git a/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java b/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java
index ec060bc73a..070cd2834d 100644
--- a/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java
+++ b/uitest/src/com/vaadin/launcher/DevelopmentServerLauncher.java
@@ -69,9 +69,12 @@ public class DevelopmentServerLauncher {
// Pass-through of arguments for Jetty
final Map<String, String> serverArgs = parseArguments(args);
+ if (!serverArgs.containsKey("shutdownPort")) {
+ serverArgs.put("shutdownPort", "8889");
+ }
- if (serverArgs.containsKey("shutdownPort")) {
- int port = Integer.parseInt(serverArgs.get("shutdownPort"));
+ int port = Integer.parseInt(serverArgs.get("shutdownPort"));
+ if (port > 0) {
try {
// Try to notify another instance that it's time to close
Socket socket = new Socket((String) null, port);
@@ -105,7 +108,7 @@ public class DevelopmentServerLauncher {
try {
assert false;
- throw new RuntimeException("You should run "
+ System.err.println("You should run "
+ DevelopmentServerLauncher.class.getSimpleName()
+ " with assertions enabled. Add -ea as a VM argument.");
} catch (AssertionError e) {
diff --git a/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java b/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java
index b6774ae56a..ed611117d0 100644
--- a/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java
+++ b/uitest/src/com/vaadin/tests/application/ThreadLocalInstances.java
@@ -52,7 +52,12 @@ public class ThreadLocalInstances extends AbstractTestCase {
private final FlagSeResource resource = new FlagSeResource() {
@Override
public DownloadStream getStream() {
- reportCurrentStatus("resource handler");
+ ThreadLocalInstances.this.getContext().lock();
+ try {
+ reportCurrentStatus("resource handler");
+ } finally {
+ ThreadLocalInstances.this.getContext().unlock();
+ }
return super.getStream();
}
};
diff --git a/uitest/src/com/vaadin/tests/applicationcontext/CloseSession.java b/uitest/src/com/vaadin/tests/applicationcontext/CloseSession.java
index 446638f8a2..cca76cc9e3 100644
--- a/uitest/src/com/vaadin/tests/applicationcontext/CloseSession.java
+++ b/uitest/src/com/vaadin/tests/applicationcontext/CloseSession.java
@@ -18,13 +18,16 @@ package com.vaadin.tests.applicationcontext;
import javax.servlet.http.HttpSession;
+import com.vaadin.server.Page;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
import com.vaadin.server.WrappedHttpSession;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.tests.util.Log;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.UI;
public class CloseSession extends AbstractTestUI {
private static final String OLD_HASH_PARAM = "oldHash";
@@ -158,6 +161,17 @@ public class CloseSession extends AbstractTestUI {
@Override
public void detach() {
super.detach();
- System.out.println("UI " + getUIId() + " detached");
+ log.log("Detach of " + this + " (" + getUIId() + ")");
+ boolean correctUI = (UI.getCurrent() == this);
+ boolean correctPage = (Page.getCurrent() == getPage());
+ boolean correctVaadinSession = (VaadinSession.getCurrent() == getSession());
+ boolean correctVaadinService = (VaadinService.getCurrent() == getSession()
+ .getService());
+ log.log("UI.current correct in detach: " + correctUI);
+ log.log("Page.current correct in detach: " + correctPage);
+ log.log("VaadinSession.current correct in detach: "
+ + correctVaadinSession);
+ log.log("VaadinService.current correct in detach: "
+ + correctVaadinService);
}
}
diff --git a/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java b/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java
new file mode 100644
index 0000000000..bec8c0a10f
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/applicationcontext/CloseUI.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2012 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.tests.applicationcontext;
+
+import com.vaadin.server.Page;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.VaadinService;
+import com.vaadin.server.VaadinSession;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.UI;
+
+public class CloseUI extends AbstractTestUI {
+ private static final String OLD_HASH_PARAM = "oldHash";
+ private static final String OLD_SESSION_ID_PARAM = "oldSessionId";
+
+ private final Log log = new Log(6);
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ System.out.println("UI " + getUIId() + " inited");
+
+ final int sessionHash = getSession().hashCode();
+ final String sessionId = request.getWrappedSession().getId();
+
+ log.log("Current session hashcode: " + sessionHash);
+ log.log("Current WrappedSession id: " + sessionId);
+
+ // Log previous values to make it easier to see what has changed
+ String oldHashValue = request.getParameter(OLD_HASH_PARAM);
+ if (oldHashValue != null) {
+ log.log("Old session hashcode: " + oldHashValue);
+ log.log("Same hash as current? "
+ + oldHashValue.equals(Integer.toString(sessionHash)));
+ }
+
+ String oldSessionId = request.getParameter(OLD_SESSION_ID_PARAM);
+ if (oldSessionId != null) {
+ log.log("Old WrappedSession id: " + oldSessionId);
+ log.log("Same WrappedSession id? " + oldSessionId.equals(sessionId));
+ }
+
+ addComponent(log);
+ addComponent(new Button("Log 'hello'", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ log.log("Hello");
+ }
+ }));
+ addComponent(new Button("Close UI", new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ close();
+ }
+ }));
+
+ addComponent(new Button("Close UI (background)",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ new UIRunSafelyThread(CloseUI.this) {
+ @Override
+ protected void runSafely() {
+ close();
+ };
+ }.start();
+ }
+ }));
+ addComponent(new Button(
+ "Close UI and redirect to /statictestfiles/static.html",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ getPage().setLocation("/statictestfiles/static.html");
+ close();
+ }
+ }));
+ addComponent(new Button(
+ "Close UI and redirect to /statictestfiles/static.html (background)",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ new UIRunSafelyThread(CloseUI.this) {
+
+ @Override
+ protected void runSafely() {
+ getPage().setLocation(
+ "/statictestfiles/static.html");
+ close();
+ }
+ }.start();
+ }
+ }));
+
+ }
+
+ private abstract class RunSafelyThread extends Thread {
+ private UI ui;
+
+ public RunSafelyThread(UI ui) {
+ this.ui = ui;
+ }
+
+ @Override
+ public void run() {
+ ui.access(new Runnable() {
+
+ @Override
+ public void run() {
+ runSafely();
+ }
+ });
+ }
+
+ protected abstract void runSafely();
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Test for closing the session and redirecting the user";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(9859);
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ log.log("Detach of " + this + " (" + getUIId() + ")");
+ boolean correctUI = (UI.getCurrent() == this);
+ boolean correctPage = (Page.getCurrent() == getPage());
+ boolean correctVaadinSession = (VaadinSession.getCurrent() == getSession());
+ boolean correctVaadinService = (VaadinService.getCurrent() == getSession()
+ .getService());
+ log.log("UI.current correct in detach: " + correctUI);
+ log.log("Page.current correct in detach: " + correctPage);
+ log.log("VaadinSession.current correct in detach: "
+ + correctVaadinSession);
+ log.log("VaadinService.current correct in detach: "
+ + correctVaadinService);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/applicationcontext/RpcForClosedUI.html b/uitest/src/com/vaadin/tests/applicationcontext/RpcForClosedUI.html
new file mode 100644
index 0000000000..642e31b22c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/applicationcontext/RpcForClosedUI.html
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://192.168.2.75:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/CloseUI?restartApplication</td>
+ <td></td>
+</tr>
+<!--Close the UI in a background thread-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runCloseUI::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Try to log 'hello'-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runCloseUI::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Ensure 'hello' was not logged-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runCloseUI::PID_SLog_row_0</td>
+ <td>2. Current WrappedSession id: *</td>
+</tr>
+<tr>
+ <td>assertTextNotPresent</td>
+ <td>Hello</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java b/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java
new file mode 100644
index 0000000000..ddc0f28664
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/applicationcontext/UIRunSafelyThread.java
@@ -0,0 +1,24 @@
+package com.vaadin.tests.applicationcontext;
+
+import com.vaadin.ui.UI;
+
+public abstract class UIRunSafelyThread extends Thread {
+ private UI ui;
+
+ public UIRunSafelyThread(UI ui) {
+ this.ui = ui;
+ }
+
+ @Override
+ public void run() {
+ ui.access(new Runnable() {
+
+ @Override
+ public void run() {
+ runSafely();
+ }
+ });
+ }
+
+ protected abstract void runSafely();
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/button/ButtonWithShortcutNotRendered.java b/uitest/src/com/vaadin/tests/components/button/ButtonWithShortcutNotRendered.java
index b01e0a85d0..f866928054 100644
--- a/uitest/src/com/vaadin/tests/components/button/ButtonWithShortcutNotRendered.java
+++ b/uitest/src/com/vaadin/tests/components/button/ButtonWithShortcutNotRendered.java
@@ -83,6 +83,7 @@ public class ButtonWithShortcutNotRendered extends AbstractTestUI {
addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
public void valueChange(
com.vaadin.data.Property.ValueChangeEvent event) {
final Item item = getItem(getValue());
@@ -162,6 +163,7 @@ public class ButtonWithShortcutNotRendered extends AbstractTestUI {
}
}
+ @Override
public void buttonClick(ClickEvent event) {
// NOP
}
diff --git a/uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.html b/uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.html
new file mode 100644
index 0000000000..8d10438c1d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.html
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://127.0.0.1:8080/" />
+<title>ButtonsWaiAria</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">ButtonsWaiAria</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.button.ButtonsWaiAria?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>verifyElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]@role</td>
+ <td>button</td>
+</tr>
+<tr>
+ <td>verifyElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementPresent</td>
+ <td>xpath=/html/body/div/div/div[2]/div/div[2]/div/div[5]/div/span/img[@alt='']</td>
+ <td></td>
+</tr>
+<tr>
+ <td>verifyElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]@alt</td>
+ <td>user icon</td>
+</tr>
+<tr>
+ <td>verifyElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VButton[0]/</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::PID_Scheckboxaction-Enabled/domChild[0]</td>
+ <td>7,7</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VButton[0]/@aria-disabled</td>
+ <td>true</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsbuttonButtonsWaiAria::PID_Scheckboxaction-Enabled/domChild[0]</td>
+ <td>7,7</td>
+</tr>
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>/html/body/div/div/div[2]/div/div[2]/div/div[3]/div[@aria-disabled]</td>
+ <td></td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.java b/uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.java
new file mode 100644
index 0000000000..1208b8be3b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/button/ButtonsWaiAria.java
@@ -0,0 +1,51 @@
+package com.vaadin.tests.components.button;
+
+import com.vaadin.tests.components.ComponentTestCase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.NativeButton;
+
+public class ButtonsWaiAria extends ComponentTestCase<Button> {
+
+ @Override
+ protected Class<Button> getTestClass() {
+ return Button.class;
+ }
+
+ @Override
+ protected void initializeComponents() {
+
+ Button l;
+ boolean nat = false;
+
+ l = createButton("Default Button", nat);
+ addTestComponent(l);
+
+ l = createButton("Icon Button, empty alt", nat);
+ l.setIcon(ICON_16_USER_PNG_CACHEABLE);
+ addTestComponent(l);
+
+ l = createButton("Icon Button with alt", nat);
+ l.setIcon(ICON_16_USER_PNG_CACHEABLE, "user icon");
+ addTestComponent(l);
+
+ l = createButton("Tooltip Button", nat);
+ l.setDescription("Tooltip");
+ addTestComponent(l);
+ }
+
+ private Button createButton(String text, boolean nativeButton) {
+ Button b;
+ if (nativeButton) {
+ b = new NativeButton(text);
+ } else {
+ b = new Button(text);
+ }
+
+ return b;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "A generic test for Buttons in different configurations";
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java b/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java
new file mode 100644
index 0000000000..83fc4a03cb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/BeanItemContainerTestUI.java
@@ -0,0 +1,184 @@
+/**
+ * Copyright 2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import java.util.Arrays;
+import java.util.Date;
+
+import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.data.util.BeanItemContainer;
+import com.vaadin.event.Action;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalSplitPanel;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Window.CloseEvent;
+import com.vaadin.ui.components.calendar.ContainerEventProvider;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+
+public class BeanItemContainerTestUI extends UI {
+
+ private Calendar calendar;
+
+ private Table table;
+
+ private BeanItemContainer<BasicEvent> events = new BeanItemContainer<BasicEvent>(
+ BasicEvent.class);
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void init(VaadinRequest request) {
+ VerticalSplitPanel content = new VerticalSplitPanel();
+ content.setSizeFull();
+ setContent(content);
+
+ // Create Calendar
+ calendar = new Calendar();
+ calendar.setImmediate(true);
+ calendar.setSizeFull();
+ calendar.setContainerDataSource(events);
+ calendar.setStartDate(new Date(100, 1, 1));
+ calendar.setEndDate(new Date(100, 2, 1));
+
+ content.addComponent(calendar);
+
+ // Add event table connected to same data source
+ table = createTable();
+ table.setContainerDataSource(events);
+ table.setVisibleColumns(new Object[] { "caption", "description",
+ "start", "end" });
+ content.addComponent(table);
+ }
+
+ /**
+ * Creates a table with some actions
+ *
+ * @return
+ */
+ private Table createTable() {
+ Table table = new Table();
+ table.setSizeFull();
+ table.addActionHandler(new Action.Handler() {
+
+ private final Action ADD = new Action("Add event");
+ private final Action EDIT = new Action("Edit event");
+ private final Action REMOVE = new Action("Remove event");
+
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ if (action == ADD) {
+ BasicEvent event = new BasicEvent();
+ event.setStart(new Date(100, 1, 1));
+ event.setEnd(new Date(100, 1, 1));
+ editEvent(event);
+ } else if (action == EDIT) {
+ editEvent((BasicEvent) target);
+ } else if (action == REMOVE) {
+ events.removeItem(target);
+ }
+ }
+
+ @Override
+ public Action[] getActions(Object target, Object sender) {
+ if (target == null) {
+ return new Action[] { ADD };
+ } else {
+ return new Action[] { EDIT, REMOVE };
+ }
+ }
+ });
+ return table;
+ }
+
+ /**
+ * Opens up a modal dialog window where an event can be modified
+ *
+ * @param event
+ * The event to modify
+ */
+ private void editEvent(final BasicEvent event) {
+ Window modal = new Window("Add event");
+ modal.setModal(true);
+ modal.setResizable(false);
+ modal.setDraggable(false);
+ modal.setWidth("300px");
+ final FieldGroup fieldGroup = new FieldGroup();
+
+ FormLayout formLayout = new FormLayout();
+ TextField captionField = new TextField("Caption");
+ captionField.setImmediate(true);
+ TextField descriptionField = new TextField("Description");
+ descriptionField.setImmediate(true);
+ DateField startField = new DateField("Start");
+ startField.setResolution(Resolution.MINUTE);
+ startField.setImmediate(true);
+ DateField endField = new DateField("End");
+ endField.setImmediate(true);
+ endField.setResolution(Resolution.MINUTE);
+
+ formLayout.addComponent(captionField);
+ formLayout.addComponent(descriptionField);
+ formLayout.addComponent(startField);
+ formLayout.addComponent(endField);
+
+ fieldGroup.bind(captionField, ContainerEventProvider.CAPTION_PROPERTY);
+ fieldGroup.bind(descriptionField,
+ ContainerEventProvider.DESCRIPTION_PROPERTY);
+ fieldGroup.bind(startField, ContainerEventProvider.STARTDATE_PROPERTY);
+ fieldGroup.bind(endField, ContainerEventProvider.ENDDATE_PROPERTY);
+
+ fieldGroup.setItemDataSource(new BeanItem<BasicEvent>(event, Arrays
+ .asList(ContainerEventProvider.CAPTION_PROPERTY,
+ ContainerEventProvider.DESCRIPTION_PROPERTY,
+ ContainerEventProvider.STARTDATE_PROPERTY,
+ ContainerEventProvider.ENDDATE_PROPERTY)));
+ modal.setContent(formLayout);
+ modal.addCloseListener(new Window.CloseListener() {
+ @Override
+ public void windowClose(CloseEvent e) {
+ // Commit changes to bean
+ try {
+ fieldGroup.commit();
+ } catch (CommitException e1) {
+ e1.printStackTrace();
+ }
+
+ if (events.containsId(event)) {
+ /*
+ * BeanItemContainer does not notify container listeners
+ * when the bean changes so we need to trigger a
+ * ItemSetChange event
+ */
+ BasicEvent dummy = new BasicEvent();
+ events.addBean(dummy);
+ events.removeItem(dummy);
+
+ } else {
+ events.addBean(event);
+ }
+ }
+ });
+ getUI().addWindow(modal);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarActions.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarActions.html
new file mode 100644
index 0000000000..bec3f2aded
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarActions.html
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8080/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarActionsUI?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>contextMenuAt</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsUI::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[7]</td>
+ <td>100,20</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>addEventContextMenu</td>
+</tr>
+<tr>
+ <td>contextMenuAt</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsUI::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[8]</td>
+ <td>100,20</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>removeEventContextMenu</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarActionsUI::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[8]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>NoContextMenu</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsUI.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsUI.java
new file mode 100644
index 0000000000..ee898e0790
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarActionsUI.java
@@ -0,0 +1,110 @@
+/**
+ * Copyright 2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import java.util.Date;
+import java.util.Locale;
+
+import com.vaadin.event.Action;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.components.calendar.CalendarDateRange;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+
+public class CalendarActionsUI extends UI {
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void init(VaadinRequest request) {
+ GridLayout content = new GridLayout(1, 2);
+ content.setSizeFull();
+ setContent(content);
+
+ final Calendar calendar = new Calendar();
+ calendar.setLocale(new Locale("fi", "FI"));
+
+ calendar.setSizeFull();
+ calendar.setStartDate(new Date(100, 1, 1));
+ calendar.setEndDate(new Date(100, 2, 1));
+
+ calendar.addActionHandler(new Action.Handler() {
+
+ public final Action NEW_EVENT = new Action("Add event");
+ public final Action EDIT_EVENT = new Action("Edit event");
+ public final Action REMOVE_EVENT = new Action("Remove event");
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.vaadin.event.Action.Handler#handleAction(com.vaadin.event
+ * .Action, java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ Date date = (Date) target;
+ if (action == NEW_EVENT) {
+ BasicEvent event = new BasicEvent("New event",
+ "Hello world", date, date);
+ calendar.addEvent(event);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.event.Action.Handler#getActions(java.lang.Object,
+ * java.lang.Object)
+ */
+ @Override
+ public Action[] getActions(Object target, Object sender) {
+ CalendarDateRange date = (CalendarDateRange) target;
+
+ java.util.Calendar cal = java.util.Calendar.getInstance();
+ cal.set(2000, 1, 1, 12, 0, 0);
+
+ if (date.inRange(cal.getTime())) {
+ return new Action[] { NEW_EVENT, };
+ }
+
+ cal.add(java.util.Calendar.DAY_OF_WEEK, 1);
+
+ if (date.inRange(cal.getTime())) {
+ return new Action[] { REMOVE_EVENT };
+ }
+
+ return null;
+ }
+ });
+
+ content.addComponent(calendar);
+
+ content.addComponent(new Button("Set week view",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ calendar.setEndDate(new Date(100, 1, 7));
+ }
+ }));
+
+ content.setRowExpandRatio(0, 1);
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarBasicNavigation.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarBasicNavigation.html
new file mode 100644
index 0000000000..cccb88bfb2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarBasicNavigation.html
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>basicNavigation</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">basicNavigation</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;width=1000px&amp;height=600px&amp;restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Feb 2000</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Mar 2000</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Feb 2000</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>26</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[5]/domChild[6]/domChild[0]/domChild[0]</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>9,44</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>Sunday 1/9/00</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[7]/domChild[0]</td>
+ <td>Saturday 1/15/00</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>1 AM</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[23]</td>
+ <td>11 PM</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[8]/domChild[0]</td>
+ <td>4,6</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[8]/domChild[0]</td>
+ <td>4,5</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>Sunday 1/23/00</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[7]/domChild[0]</td>
+ <td>Saturday 1/29/00</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>9,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>9,7</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>Sunday 1/9/00</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[7]/domChild[0]</td>
+ <td>Saturday 1/15/00</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]</td>
+ <td>77,5</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>Tuesday 1/11/00</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>8,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>10,9</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>Friday 12/31/99</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]</td>
+ <td>Sunday 1/30/00</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[7]/domChild[0]</td>
+ <td>Saturday 2/5/00</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>26</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarEventSizingNoOverlap.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarEventSizingNoOverlap.html
new file mode 100644
index 0000000000..dcf6c1ec53
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarEventSizingNoOverlap.html
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>eventSizingNoOverlap</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">eventSizingNoOverlap</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;firstDay=1&amp;lastDay=5&amp;firstHour=8&amp;lastHour=16&amp;restartApplication</td>
+ <td></td>
+</tr>
+<!-- Go to week view -->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>4,57</td>
+</tr>
+<!-- Open add-event popup, enter event between 12:45-13:15 -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/9/00 12:45 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/9/00 13:15 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>12:45-13:15</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- Open add-event popup, enter event between 13:15-13:25 -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/9/00 13:15 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/9/00 13:25 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>13:15-13:25</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!-- Open add-event popup, enter event between 13:25-13:55 -->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/9/00 13:25 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/9/00 13:55 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>13:25-13:55</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarMidnightEventsTest.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarMidnightEventsTest.html
new file mode 100644
index 0000000000..8991e1983d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarMidnightEventsTest.html
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>midnightEventsTest</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">midnightEventsTest</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;width=1000px&amp;height=600px&amp;secondsResolution&amp;restartApplication</td>
+ <td></td>
+</tr>
+<!--Add event from 0:00 to 0:00-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[1]/domChild[0]/domChild[2]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/3/00 12:00:00 AM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/4/00 12:00:00 AM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Midnight to midnight</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Add event from 00:00 to 00:00 on the same day-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[1]/domChild[0]/domChild[2]</td>
+ <td>84,10</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/7/00 12:00:00 AM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Zero-length midnight event</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td></td>
+</tr>
+<!--Go to weekly view-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>10,48</td>
+</tr>
+<!--Assert zero-length event exists-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[48]/domChild[0]</td>
+ <td>50,4</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Zero-length midnight event</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Assert that the the all day event does not overflow to the next day by checking that the first time-cell is empty-->
+<tr>
+ <td>dragAndDrop</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[5]</td>
+ <td>+0,+5</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvent.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvent.html
new file mode 100644
index 0000000000..760beef6c0
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvent.html
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>monthlyViewNewEvent</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">monthlyViewNewEvent</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;width=1000px&amp;height=600px&amp;restartApplication</td>
+ <td></td>
+</tr>
+<!--Create new event with the button-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>10,5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>52,8</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/26/99</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/1/00</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Test description</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Open previously created event, assert values-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>91,9</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/26/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/1/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>on</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Test description</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Green</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Open previously created event, assert values and shorten the event-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>41,8</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/26/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/1/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>on</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Test description</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Green</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/27/99</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/31/99</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Click the calendar where the event previously was, assert new event creation-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]</td>
+ <td>107,8</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvents.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvents.html
new file mode 100644
index 0000000000..68690f81b4
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarMonthlyViewNewEvents.html
@@ -0,0 +1,410 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>monthlyViewNewEvents</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">monthlyViewNewEvents</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;width=1000px&amp;height=600px&amp;restartApplication</td>
+ <td></td>
+</tr>
+<!--Create new event by dragging, make it all-day-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[5]/domChild[0]/domChild[2]</td>
+ <td>98,83</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/27/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/31/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>on</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Description</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Create new event by dragging-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]</td>
+ <td>38,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>7,9</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Second test event</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Desc</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Create new event by dragging, make it blue-->
+<tr>
+ <td>drag</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[4]/domChild[0]/domChild[4]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>drop</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[6]/domChild[0]/domChild[3]</td>
+ <td>125,80</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>10,8</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Third test event</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Testing</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]#button</td>
+ <td>6,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item2</td>
+ <td>49,10</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[4]</td>
+ <td>45,85</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>5,9</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Fourth test event</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Fourth event</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]#button</td>
+ <td>13,18</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item3</td>
+ <td>57,9</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Start asserting the previously entered events-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]</td>
+ <td>12,7</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/27/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/31/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>on</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Description</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Green</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[1]</td>
+ <td>72,6</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/27/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/31/99</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>44,10</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/26/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/29/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Second test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Desc</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Green</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>79,5</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/26/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/29/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Second test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Desc</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Green</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[4]/domChild[0]/domChild[2]</td>
+ <td>47,9</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/30/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/1/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Third test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Testing</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Blue</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[4]/domChild[0]/domChild[2]</td>
+ <td>72,9</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/30/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/1/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Third test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Testing</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Blue</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[3]/domChild[0]/domChild[3]</td>
+ <td>37,9</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>12/29/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>12/29/99</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Fourth test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Fourth event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Red</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarNotifications.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarNotifications.html
new file mode 100644
index 0000000000..15bf29a0fd
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarNotifications.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8080/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.NotificationTestUI?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarNotificationTestUI::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>83,11</td>
+</tr>
+<tr>
+ <td>mouseMove</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarNotificationTestUI::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[3]/domChild[0]/domChild[3]</td>
+ <td>10,10</td>
+</tr>
+<tr>
+ <td>closeNotification</td>
+ <td>//div[@id='runcomvaadintestscomponentscalendarNotificationTestUI-1842310749-overlays']/div</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>no-notification</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest1000x600px.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest1000x600px.html
new file mode 100644
index 0000000000..bd4c671361
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest1000x600px.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTest1000x600px</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTest1000x600px</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;width=1000px&amp;height=600px</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>7,53</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100percentXundefined.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100percentXundefined.html
new file mode 100644
index 0000000000..64b5444d34
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100percentXundefined.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTest100percentXundefined</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTest100percentXundefined</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;width=100%25</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>10,53</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100x100percent.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100x100percent.html
new file mode 100644
index 0000000000..0905034b13
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest100x100percent.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTest100x100percent</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTest100x100percent</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;width=100%25&amp;height=100%25</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>12,54</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest300pxXundefined.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest300pxXundefined.html
new file mode 100644
index 0000000000..99327a01df
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTest300pxXundefined.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTest300pxXundefined</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTest300pxXundefined</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;width=300px</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>11,52</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX100percent.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX100percent.html
new file mode 100644
index 0000000000..2e4c811ff1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX100percent.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTestUndefinedX100percent</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTestUndefinedX100percent</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;height=100%25</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>9,53</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX300px.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX300px.html
new file mode 100644
index 0000000000..cca66c7145
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedX300px.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTestUndefinedX300px</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTestUndefinedX300px</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;height=300px</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>9,26</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedXUndefined.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedXUndefined.html
new file mode 100644
index 0000000000..e4a8da691b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarSizeTestUndefinedXUndefined.html
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>sizeTestUndefinedXUndefined</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">sizeTestUndefinedXUndefined</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;restartApplication&amp;width=&amp;height=</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[1]/VLabel[0]</td>
+ <td>Jan 2000</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>month</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>8,52</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>week</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarTest.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarTest.java
new file mode 100644
index 0000000000..a1bcca2e4e
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarTest.java
@@ -0,0 +1,1242 @@
+/**
+ * Copyright 2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import java.text.DateFormatSymbols;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+
+import com.vaadin.annotations.Theme;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.MarginInfo;
+import com.vaadin.shared.ui.combobox.FilteringMode;
+import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.Calendar.TimeFormat;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.RangeSelectEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.RangeSelectHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClick;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.WeekClickHandler;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+import com.vaadin.ui.components.calendar.event.BasicEventProvider;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.handler.BasicDateClickHandler;
+import com.vaadin.ui.components.calendar.handler.BasicWeekClickHandler;
+
+/** Calendar component test application */
+@Theme("tests-calendar")
+public class CalendarTest extends UI {
+
+ private static final long serialVersionUID = -5436777475398410597L;
+
+ private static final String DEFAULT_ITEMID = "DEFAULT";
+
+ private enum Mode {
+ MONTH, WEEK, DAY;
+ }
+
+ /**
+ * This Gregorian calendar is used to control dates and time inside of this
+ * test application.
+ */
+ private GregorianCalendar calendar;
+
+ /** Target calendar component that this test application is made for. */
+ private Calendar calendarComponent;
+
+ private Date currentMonthsFirstDate;
+
+ private final Label captionLabel = new Label("");
+
+ private Button monthButton;
+
+ private Button weekButton;
+
+ private Button nextButton;
+
+ private Button prevButton;
+
+ private ComboBox timeZoneSelect;
+
+ private ComboBox formatSelect;
+
+ private ComboBox localeSelect;
+
+ private CheckBox hideWeekendsButton;
+
+ private CheckBox readOnlyButton;
+
+ private TextField captionField;
+
+ private Window scheduleEventPopup;
+
+ private final FormLayout scheduleEventFieldLayout = new FormLayout();
+ private FieldGroup scheduleEventFieldGroup = new FieldGroup();
+
+ private Button deleteEventButton;
+
+ private Button applyEventButton;
+
+ private Mode viewMode = Mode.MONTH;
+
+ private BasicEventProvider dataSource;
+
+ private Button addNewEvent;
+
+ /*
+ * When testBench is set to true, CalendarTest will have static content that
+ * is more suitable for Vaadin TestBench testing. Calendar will use a static
+ * date Mon 10 Jan 2000. Enable by starting the application with a
+ * "testBench" parameter in the URL.
+ */
+ private boolean testBench = false;
+
+ private String calendarHeight = null;
+
+ private String calendarWidth = null;
+
+ private CheckBox disabledButton;
+
+ private Integer firstHour;
+
+ private Integer lastHour;
+
+ private Integer firstDay;
+
+ private Integer lastDay;
+
+ private Locale defaultLocale = Locale.US;
+
+ private boolean showWeeklyView;
+
+ private boolean useSecondResolution;
+
+ private DateField startDateField;
+ private DateField endDateField;
+
+ @SuppressWarnings("serial")
+ @Override
+ public void init(VaadinRequest request) {
+ GridLayout layout = new GridLayout();
+ layout.setSizeFull();
+ layout.setMargin(true);
+ setContent(layout);
+
+ handleURLParams(request.getParameterMap());
+
+ initContent();
+ }
+
+ private void handleURLParams(Map<String, String[]> parameters) {
+ testBench = parameters.containsKey("testBench")
+ || parameters.containsKey("?testBench");
+
+ if (parameters.containsKey("width")) {
+ calendarWidth = parameters.get("width")[0];
+ }
+
+ if (parameters.containsKey("height")) {
+ calendarHeight = parameters.get("height")[0];
+ }
+
+ if (parameters.containsKey("firstDay")) {
+ firstDay = Integer.parseInt(parameters.get("firstDay")[0]);
+ }
+
+ if (parameters.containsKey("lastDay")) {
+ lastDay = Integer.parseInt(parameters.get("lastDay")[0]);
+ }
+
+ if (parameters.containsKey("firstHour")) {
+ firstHour = Integer.parseInt(parameters.get("firstHour")[0]);
+ }
+
+ if (parameters.containsKey("lastHour")) {
+ lastHour = Integer.parseInt(parameters.get("lastHour")[0]);
+ }
+
+ if (parameters.containsKey("locale")) {
+ String localeArray[] = parameters.get("locale")[0].split("_");
+ defaultLocale = new Locale(localeArray[0], localeArray[1]);
+ setLocale(defaultLocale);
+ }
+
+ if (parameters.containsKey(("secondsResolution"))) {
+ useSecondResolution = true;
+ }
+
+ showWeeklyView = parameters.containsKey("weekly");
+
+ }
+
+ public void initContent() {
+ // Set default Locale for this application
+ if (testBench) {
+ setLocale(defaultLocale);
+
+ } else {
+ setLocale(Locale.getDefault());
+ }
+
+ // Initialize locale, timezone and timeformat selects.
+ localeSelect = createLocaleSelect();
+ timeZoneSelect = createTimeZoneSelect();
+ formatSelect = createCalendarFormatSelect();
+
+ initCalendar();
+ initLayoutContent();
+ addInitialEvents();
+ }
+
+ private Date resolveFirstDateOfWeek(Date today,
+ java.util.Calendar currentCalendar) {
+ int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
+ currentCalendar.setTime(today);
+ while (firstDayOfWeek != currentCalendar
+ .get(java.util.Calendar.DAY_OF_WEEK)) {
+ currentCalendar.add(java.util.Calendar.DATE, -1);
+ }
+ return currentCalendar.getTime();
+ }
+
+ private Date resolveLastDateOfWeek(Date today,
+ java.util.Calendar currentCalendar) {
+ currentCalendar.setTime(today);
+ currentCalendar.add(java.util.Calendar.DATE, 1);
+ int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
+ // Roll to weeks last day using firstdayofweek. Roll until FDofW is
+ // found and then roll back one day.
+ while (firstDayOfWeek != currentCalendar
+ .get(java.util.Calendar.DAY_OF_WEEK)) {
+ currentCalendar.add(java.util.Calendar.DATE, 1);
+ }
+ currentCalendar.add(java.util.Calendar.DATE, -1);
+ return currentCalendar.getTime();
+ }
+
+ private void addInitialEvents() {
+ Date originalDate = calendar.getTime();
+ Date today = getToday();
+
+ // Add a event that last a whole week
+
+ Date start = resolveFirstDateOfWeek(today, calendar);
+ Date end = resolveLastDateOfWeek(today, calendar);
+ CalendarTestEvent event = getNewEvent("Whole week event", start, end);
+ event.setAllDay(true);
+ event.setStyleName("color4");
+ event.setDescription("Description for the whole week event.");
+ dataSource.addEvent(event);
+
+ // Add a allday event
+ calendar.setTime(start);
+ calendar.add(GregorianCalendar.DATE, 3);
+ start = calendar.getTime();
+ end = start;
+ event = getNewEvent("Allday event", start, end);
+ event.setAllDay(true);
+ event.setDescription("Some description.");
+ event.setStyleName("color3");
+ dataSource.addEvent(event);
+
+ // Add a second allday event
+ calendar.add(GregorianCalendar.DATE, 1);
+ start = calendar.getTime();
+ end = start;
+ event = getNewEvent("Second allday event", start, end);
+ event.setAllDay(true);
+ event.setDescription("Some description.");
+ event.setStyleName("color2");
+ dataSource.addEvent(event);
+
+ calendar.add(GregorianCalendar.DATE, -3);
+ calendar.set(GregorianCalendar.HOUR_OF_DAY, 9);
+ calendar.set(GregorianCalendar.MINUTE, 30);
+ start = calendar.getTime();
+ calendar.add(GregorianCalendar.HOUR_OF_DAY, 5);
+ calendar.set(GregorianCalendar.MINUTE, 0);
+ end = calendar.getTime();
+ event = getNewEvent("Appointment", start, end);
+ event.setWhere("Office");
+ event.setStyleName("color1");
+ event.setDescription("A longer description, which should display correctly.");
+ dataSource.addEvent(event);
+
+ calendar.add(GregorianCalendar.DATE, 1);
+ calendar.set(GregorianCalendar.HOUR_OF_DAY, 11);
+ calendar.set(GregorianCalendar.MINUTE, 0);
+ start = calendar.getTime();
+ calendar.add(GregorianCalendar.HOUR_OF_DAY, 8);
+ end = calendar.getTime();
+ event = getNewEvent("Training", start, end);
+ event.setStyleName("color2");
+ dataSource.addEvent(event);
+
+ calendar.add(GregorianCalendar.DATE, 4);
+ calendar.set(GregorianCalendar.HOUR_OF_DAY, 9);
+ calendar.set(GregorianCalendar.MINUTE, 0);
+ start = calendar.getTime();
+ calendar.add(GregorianCalendar.HOUR_OF_DAY, 9);
+ end = calendar.getTime();
+ event = getNewEvent("Free time", start, end);
+ dataSource.addEvent(event);
+
+ calendar.setTime(originalDate);
+ }
+
+ private void initLayoutContent() {
+ initNavigationButtons();
+ initHideWeekEndButton();
+ initReadOnlyButton();
+ initDisabledButton();
+ initAddNewEventButton();
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setWidth("100%");
+ hl.setSpacing(true);
+ hl.setMargin(new MarginInfo(false, false, true, false));
+ hl.addComponent(prevButton);
+ hl.addComponent(captionLabel);
+ hl.addComponent(monthButton);
+ hl.addComponent(weekButton);
+ hl.addComponent(nextButton);
+ hl.setComponentAlignment(prevButton, Alignment.MIDDLE_LEFT);
+ hl.setComponentAlignment(captionLabel, Alignment.MIDDLE_CENTER);
+ hl.setComponentAlignment(monthButton, Alignment.MIDDLE_CENTER);
+ hl.setComponentAlignment(weekButton, Alignment.MIDDLE_CENTER);
+ hl.setComponentAlignment(nextButton, Alignment.MIDDLE_RIGHT);
+
+ monthButton.setVisible(viewMode == Mode.WEEK);
+ weekButton.setVisible(viewMode == Mode.DAY);
+
+ HorizontalLayout controlPanel = new HorizontalLayout();
+ controlPanel.setSpacing(true);
+ controlPanel.setMargin(new MarginInfo(false, false, true, false));
+ controlPanel.setWidth("100%");
+ controlPanel.addComponent(localeSelect);
+ controlPanel.addComponent(timeZoneSelect);
+ controlPanel.addComponent(formatSelect);
+ controlPanel.addComponent(hideWeekendsButton);
+ controlPanel.addComponent(readOnlyButton);
+ controlPanel.addComponent(disabledButton);
+ controlPanel.addComponent(addNewEvent);
+
+ controlPanel.setComponentAlignment(timeZoneSelect,
+ Alignment.MIDDLE_LEFT);
+ controlPanel.setComponentAlignment(formatSelect, Alignment.MIDDLE_LEFT);
+ controlPanel.setComponentAlignment(localeSelect, Alignment.MIDDLE_LEFT);
+ controlPanel.setComponentAlignment(hideWeekendsButton,
+ Alignment.MIDDLE_LEFT);
+ controlPanel.setComponentAlignment(readOnlyButton,
+ Alignment.MIDDLE_LEFT);
+ controlPanel.setComponentAlignment(disabledButton,
+ Alignment.MIDDLE_LEFT);
+ controlPanel.setComponentAlignment(addNewEvent, Alignment.MIDDLE_LEFT);
+
+ GridLayout layout = (GridLayout) getContent();
+ layout.addComponent(controlPanel);
+ layout.addComponent(hl);
+ layout.addComponent(calendarComponent);
+ layout.setRowExpandRatio(layout.getRows() - 1, 1.0f);
+ }
+
+ private void initNavigationButtons() {
+ monthButton = new Button("Month view", new ClickListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ switchToMonthView();
+ }
+ });
+
+ weekButton = new Button("Week view", new ClickListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ // simulate week click
+ WeekClickHandler handler = (WeekClickHandler) calendarComponent
+ .getHandler(WeekClick.EVENT_ID);
+ handler.weekClick(new WeekClick(calendarComponent, calendar
+ .get(GregorianCalendar.WEEK_OF_YEAR), calendar
+ .get(GregorianCalendar.YEAR)));
+ }
+ });
+
+ nextButton = new Button("Next", new Button.ClickListener() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ handleNextButtonClick();
+ }
+ });
+
+ prevButton = new Button("Prev", new Button.ClickListener() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ handlePreviousButtonClick();
+ }
+ });
+ }
+
+ private void initHideWeekEndButton() {
+ hideWeekendsButton = new CheckBox("Hide weekends");
+ hideWeekendsButton.setImmediate(true);
+ hideWeekendsButton
+ .addValueChangeListener(new Property.ValueChangeListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setWeekendsHidden(hideWeekendsButton.getValue());
+ }
+ });
+ }
+
+ private void setWeekendsHidden(boolean weekendsHidden) {
+ if (weekendsHidden) {
+ int firstToShow = (GregorianCalendar.MONDAY - calendar
+ .getFirstDayOfWeek()) % 7;
+ calendarComponent.setFirstVisibleDayOfWeek(firstToShow + 1);
+ calendarComponent.setLastVisibleDayOfWeek(firstToShow + 5);
+ } else {
+ calendarComponent.setFirstVisibleDayOfWeek(1);
+ calendarComponent.setLastVisibleDayOfWeek(7);
+ }
+
+ }
+
+ private void initReadOnlyButton() {
+ readOnlyButton = new CheckBox("Read-only mode");
+ readOnlyButton.setImmediate(true);
+ readOnlyButton
+ .addValueChangeListener(new Property.ValueChangeListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ calendarComponent.setReadOnly(readOnlyButton.getValue());
+ }
+ });
+ }
+
+ private void initDisabledButton() {
+ disabledButton = new CheckBox("Disabled");
+ disabledButton.setImmediate(true);
+ disabledButton
+ .addValueChangeListener(new Property.ValueChangeListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ calendarComponent.setEnabled(!disabledButton.getValue());
+ }
+ });
+ }
+
+ public void initAddNewEventButton() {
+ addNewEvent = new Button("Add new event");
+ addNewEvent.addClickListener(new Button.ClickListener() {
+
+ private static final long serialVersionUID = -8307244759142541067L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Date start = getToday();
+ start.setHours(0);
+ start.setMinutes(0);
+ start.setSeconds(0);
+
+ Date end = getEndOfDay(calendar, start);
+
+ showEventPopup(createNewEvent(start, end), true);
+ }
+ });
+ }
+
+ private void initFormFields(Layout formLayout,
+ Class<? extends CalendarEvent> eventClass) {
+
+ startDateField = createDateField("Start date");
+ endDateField = createDateField("End date");
+
+ final CheckBox allDayField = createCheckBox("All-day");
+ allDayField.addValueChangeListener(new Property.ValueChangeListener() {
+
+ private static final long serialVersionUID = -7104996493482558021L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ Object value = event.getProperty().getValue();
+ if (value instanceof Boolean && Boolean.TRUE.equals(value)) {
+ setFormDateResolution(Resolution.DAY);
+
+ } else {
+ setFormDateResolution(Resolution.MINUTE);
+ }
+ }
+
+ });
+
+ captionField = createTextField("Caption");
+ final TextField whereField = createTextField("Where");
+ final TextArea descriptionField = createTextArea("Description");
+ descriptionField.setRows(3);
+
+ final ComboBox styleNameField = createStyleNameComboBox();
+
+ formLayout.addComponent(startDateField);
+ formLayout.addComponent(endDateField);
+ formLayout.addComponent(allDayField);
+ formLayout.addComponent(captionField);
+ if (eventClass == CalendarTestEvent.class) {
+ formLayout.addComponent(whereField);
+ }
+ formLayout.addComponent(descriptionField);
+ formLayout.addComponent(styleNameField);
+
+ scheduleEventFieldGroup.bind(startDateField, "start");
+ scheduleEventFieldGroup.bind(endDateField, "end");
+ scheduleEventFieldGroup.bind(captionField, "caption");
+ scheduleEventFieldGroup.bind(descriptionField, "description");
+ if (eventClass == CalendarTestEvent.class) {
+ scheduleEventFieldGroup.bind(whereField, "where");
+ }
+ scheduleEventFieldGroup.bind(styleNameField, "styleName");
+ scheduleEventFieldGroup.bind(allDayField, "allDay");
+ }
+
+ private CheckBox createCheckBox(String caption) {
+ CheckBox cb = new CheckBox(caption);
+ cb.setImmediate(true);
+ return cb;
+ }
+
+ private TextField createTextField(String caption) {
+ TextField f = new TextField(caption);
+ f.setNullRepresentation("");
+ return f;
+ }
+
+ private TextArea createTextArea(String caption) {
+ TextArea f = new TextArea(caption);
+ f.setNullRepresentation("");
+ return f;
+ }
+
+ private DateField createDateField(String caption) {
+ DateField f = new DateField(caption);
+ if (useSecondResolution) {
+ f.setResolution(Resolution.SECOND);
+ } else {
+ f.setResolution(Resolution.MINUTE);
+ }
+ return f;
+ }
+
+ private ComboBox createStyleNameComboBox() {
+ ComboBox s = new ComboBox("Color");
+ s.addContainerProperty("c", String.class, "");
+ s.setItemCaptionPropertyId("c");
+ Item i = s.addItem("color1");
+ i.getItemProperty("c").setValue("Green");
+ i = s.addItem("color2");
+ i.getItemProperty("c").setValue("Blue");
+ i = s.addItem("color3");
+ i.getItemProperty("c").setValue("Red");
+ i = s.addItem("color4");
+ i.getItemProperty("c").setValue("Orange");
+ return s;
+ }
+
+ private void initCalendar() {
+ dataSource = new BasicEventProvider();
+
+ calendarComponent = new Calendar(dataSource);
+ calendarComponent.setLocale(getLocale());
+ calendarComponent.setImmediate(true);
+
+ if (calendarWidth != null || calendarHeight != null) {
+ if (calendarHeight != null) {
+ calendarComponent.setHeight(calendarHeight);
+ }
+ if (calendarWidth != null) {
+ calendarComponent.setWidth(calendarWidth);
+ }
+ } else {
+ calendarComponent.setSizeFull();
+ }
+
+ if (firstHour != null && lastHour != null) {
+ calendarComponent.setFirstVisibleHourOfDay(firstHour);
+ calendarComponent.setLastVisibleHourOfDay(lastHour);
+ }
+
+ if (firstDay != null && lastDay != null) {
+ calendarComponent.setFirstVisibleDayOfWeek(firstDay);
+ calendarComponent.setLastVisibleDayOfWeek(lastDay);
+ }
+
+ Date today = getToday();
+ calendar = new GregorianCalendar(getLocale());
+ calendar.setTime(today);
+
+ updateCaptionLabel();
+
+ if (!showWeeklyView) {
+ int rollAmount = calendar.get(GregorianCalendar.DAY_OF_MONTH) - 1;
+ calendar.add(GregorianCalendar.DAY_OF_MONTH, -rollAmount);
+ resetTime(false);
+ currentMonthsFirstDate = calendar.getTime();
+ calendarComponent.setStartDate(currentMonthsFirstDate);
+ calendar.add(GregorianCalendar.MONTH, 1);
+ calendar.add(GregorianCalendar.DATE, -1);
+ calendarComponent.setEndDate(calendar.getTime());
+ }
+
+ addCalendarEventListeners();
+ }
+
+ private Date getToday() {
+ if (testBench) {
+ GregorianCalendar testDate = new GregorianCalendar();
+ testDate.set(GregorianCalendar.YEAR, 2000);
+ testDate.set(GregorianCalendar.MONTH, 0);
+ testDate.set(GregorianCalendar.DATE, 10);
+ testDate.set(GregorianCalendar.HOUR_OF_DAY, 0);
+ testDate.set(GregorianCalendar.MINUTE, 0);
+ testDate.set(GregorianCalendar.SECOND, 0);
+ testDate.set(GregorianCalendar.MILLISECOND, 0);
+ return testDate.getTime();
+ }
+ return new Date();
+ }
+
+ @SuppressWarnings("serial")
+ private void addCalendarEventListeners() {
+ // Register week clicks by changing the schedules start and end dates.
+ calendarComponent.setHandler(new BasicWeekClickHandler() {
+
+ @Override
+ public void weekClick(WeekClick event) {
+ // let BasicWeekClickHandler handle calendar dates, and update
+ // only the other parts of UI here
+ super.weekClick(event);
+ updateCaptionLabel();
+ switchToWeekView();
+ }
+ });
+
+ calendarComponent.setHandler(new EventClickHandler() {
+
+ @Override
+ public void eventClick(EventClick event) {
+ showEventPopup(event.getCalendarEvent(), false);
+ }
+ });
+
+ calendarComponent.setHandler(new BasicDateClickHandler() {
+
+ @Override
+ public void dateClick(DateClickEvent event) {
+ // let BasicDateClickHandler handle calendar dates, and update
+ // only the other parts of UI here
+ super.dateClick(event);
+ switchToDayView();
+ }
+ });
+
+ calendarComponent.setHandler(new RangeSelectHandler() {
+
+ @Override
+ public void rangeSelect(RangeSelectEvent event) {
+ handleRangeSelect(event);
+ }
+ });
+ }
+
+ private ComboBox createTimeZoneSelect() {
+ ComboBox s = new ComboBox("Timezone");
+ s.addContainerProperty("caption", String.class, "");
+ s.setItemCaptionPropertyId("caption");
+ s.setFilteringMode(FilteringMode.CONTAINS);
+
+ Item i = s.addItem(DEFAULT_ITEMID);
+ i.getItemProperty("caption").setValue(
+ "Default (" + TimeZone.getDefault().getID() + ")");
+ for (String id : TimeZone.getAvailableIDs()) {
+ if (!s.containsId(id)) {
+ i = s.addItem(id);
+ i.getItemProperty("caption").setValue(id);
+ }
+ }
+
+ if (testBench) {
+ s.select("America/New_York");
+ } else {
+ s.select(DEFAULT_ITEMID);
+ }
+ s.setImmediate(true);
+ s.addValueChangeListener(new ValueChangeListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ updateCalendarTimeZone(event.getProperty().getValue());
+ }
+ });
+
+ return s;
+ }
+
+ private ComboBox createCalendarFormatSelect() {
+ ComboBox s = new ComboBox("Calendar format");
+ s.addContainerProperty("caption", String.class, "");
+ s.setItemCaptionPropertyId("caption");
+
+ Item i = s.addItem(DEFAULT_ITEMID);
+ i.getItemProperty("caption").setValue("Default by locale");
+ i = s.addItem(TimeFormat.Format12H);
+ i.getItemProperty("caption").setValue("12H");
+ i = s.addItem(TimeFormat.Format24H);
+ i.getItemProperty("caption").setValue("24H");
+
+ s.select(DEFAULT_ITEMID);
+ s.setImmediate(true);
+ s.addValueChangeListener(new ValueChangeListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ updateCalendarFormat(event.getProperty().getValue());
+ }
+ });
+
+ return s;
+ }
+
+ private ComboBox createLocaleSelect() {
+ ComboBox s = new ComboBox("Locale");
+ s.addContainerProperty("caption", String.class, "");
+ s.setItemCaptionPropertyId("caption");
+ s.setFilteringMode(FilteringMode.CONTAINS);
+
+ for (Locale l : Locale.getAvailableLocales()) {
+ if (!s.containsId(l)) {
+ Item i = s.addItem(l);
+ i.getItemProperty("caption").setValue(getLocaleItemCaption(l));
+ }
+ }
+
+ s.select(getLocale());
+ s.setImmediate(true);
+ s.addValueChangeListener(new ValueChangeListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ updateCalendarLocale((Locale) event.getProperty().getValue());
+ }
+ });
+
+ return s;
+ }
+
+ private void updateCalendarTimeZone(Object timezoneId) {
+ TimeZone tz = null;
+ if (!DEFAULT_ITEMID.equals(timezoneId)) {
+ tz = TimeZone.getTimeZone((String) timezoneId);
+ }
+
+ // remember the week that was showing, so we can re-set it later
+ Date startDate = calendarComponent.getStartDate();
+ calendar.setTime(startDate);
+ int weekNumber = calendar.get(java.util.Calendar.WEEK_OF_YEAR);
+ calendarComponent.setTimeZone(tz);
+ calendar.setTimeZone(calendarComponent.getTimeZone());
+
+ if (viewMode == Mode.WEEK) {
+ calendar.set(java.util.Calendar.WEEK_OF_YEAR, weekNumber);
+ calendar.set(java.util.Calendar.DAY_OF_WEEK,
+ calendar.getFirstDayOfWeek());
+
+ calendarComponent.setStartDate(calendar.getTime());
+ calendar.add(java.util.Calendar.DATE, 6);
+ calendarComponent.setEndDate(calendar.getTime());
+ }
+ }
+
+ private void updateCalendarFormat(Object format) {
+ TimeFormat calFormat = null;
+ if (format instanceof TimeFormat) {
+ calFormat = (TimeFormat) format;
+ }
+
+ calendarComponent.setTimeFormat(calFormat);
+ }
+
+ private String getLocaleItemCaption(Locale l) {
+ String country = l.getDisplayCountry(getLocale());
+ String language = l.getDisplayLanguage(getLocale());
+ StringBuilder caption = new StringBuilder(country);
+ if (caption.length() != 0) {
+ caption.append(", ");
+ }
+ caption.append(language);
+ return caption.toString();
+ }
+
+ private void updateCalendarLocale(Locale l) {
+ int oldFirstDayOfWeek = calendar.getFirstDayOfWeek();
+ setLocale(l);
+ calendarComponent.setLocale(l);
+ calendar = new GregorianCalendar(l);
+ int newFirstDayOfWeek = calendar.getFirstDayOfWeek();
+
+ // we are showing 1 week, and the first day of the week has changed
+ // update start and end dates so that the same week is showing
+ if (viewMode == Mode.WEEK && oldFirstDayOfWeek != newFirstDayOfWeek) {
+ calendar.setTime(calendarComponent.getStartDate());
+ calendar.add(java.util.Calendar.DAY_OF_WEEK, 2);
+ // starting at the beginning of the week
+ calendar.set(GregorianCalendar.DAY_OF_WEEK, newFirstDayOfWeek);
+ Date start = calendar.getTime();
+
+ // ending at the end of the week
+ calendar.add(GregorianCalendar.DATE, 6);
+ Date end = calendar.getTime();
+
+ calendarComponent.setStartDate(start);
+ calendarComponent.setEndDate(end);
+
+ // Week days depend on locale so this must be refreshed
+ setWeekendsHidden(hideWeekendsButton.getValue());
+ }
+
+ }
+
+ private void handleNextButtonClick() {
+ switch (viewMode) {
+ case MONTH:
+ nextMonth();
+ break;
+ case WEEK:
+ nextWeek();
+ break;
+ case DAY:
+ nextDay();
+ break;
+ }
+ }
+
+ private void handlePreviousButtonClick() {
+ switch (viewMode) {
+ case MONTH:
+ previousMonth();
+ break;
+ case WEEK:
+ previousWeek();
+ break;
+ case DAY:
+ previousDay();
+ break;
+ }
+ }
+
+ private void handleRangeSelect(RangeSelectEvent event) {
+ Date start = event.getStart();
+ Date end = event.getEnd();
+
+ /*
+ * If a range of dates is selected in monthly mode, we want it to end at
+ * the end of the last day.
+ */
+ if (event.isMonthlyMode()) {
+ end = getEndOfDay(calendar, end);
+ }
+
+ showEventPopup(createNewEvent(start, end), true);
+ }
+
+ private void showEventPopup(CalendarEvent event, boolean newEvent) {
+ if (event == null) {
+ return;
+ }
+
+ updateCalendarEventPopup(newEvent);
+ updateCalendarEventForm(event);
+
+ if (!getWindows().contains(scheduleEventPopup)) {
+ addWindow(scheduleEventPopup);
+ }
+ }
+
+ /* Initializes a modal window to edit schedule event. */
+ private void createCalendarEventPopup() {
+ VerticalLayout layout = new VerticalLayout();
+ layout.setMargin(true);
+ layout.setSpacing(true);
+
+ scheduleEventPopup = new Window(null, layout);
+ scheduleEventPopup.setWidth("400px");
+ scheduleEventPopup.setModal(true);
+ scheduleEventPopup.center();
+
+ layout.addComponent(scheduleEventFieldLayout);
+
+ applyEventButton = new Button("Apply", new ClickListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ try {
+ commitCalendarEvent();
+ } catch (CommitException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+ Button cancel = new Button("Cancel", new ClickListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ discardCalendarEvent();
+ }
+ });
+ deleteEventButton = new Button("Delete", new ClickListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ deleteCalendarEvent();
+ }
+ });
+ scheduleEventPopup.addCloseListener(new Window.CloseListener() {
+
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void windowClose(Window.CloseEvent e) {
+ discardCalendarEvent();
+ }
+ });
+
+ HorizontalLayout buttons = new HorizontalLayout();
+ buttons.setSpacing(true);
+ buttons.addComponent(deleteEventButton);
+ buttons.addComponent(applyEventButton);
+ buttons.addComponent(cancel);
+ layout.addComponent(buttons);
+ layout.setComponentAlignment(buttons, Alignment.BOTTOM_RIGHT);
+ }
+
+ private void updateCalendarEventPopup(boolean newEvent) {
+ if (scheduleEventPopup == null) {
+ createCalendarEventPopup();
+ }
+
+ if (newEvent) {
+ scheduleEventPopup.setCaption("New event");
+ } else {
+ scheduleEventPopup.setCaption("Edit event");
+ }
+
+ deleteEventButton.setVisible(!newEvent);
+ deleteEventButton.setEnabled(!calendarComponent.isReadOnly());
+ applyEventButton.setEnabled(!calendarComponent.isReadOnly());
+ }
+
+ private void updateCalendarEventForm(CalendarEvent event) {
+ BeanItem<CalendarEvent> item = new BeanItem<CalendarEvent>(event);
+ scheduleEventFieldLayout.removeAllComponents();
+ scheduleEventFieldGroup = new FieldGroup();
+ initFormFields(scheduleEventFieldLayout, event.getClass());
+ scheduleEventFieldGroup.setBuffered(true);
+ scheduleEventFieldGroup.setItemDataSource(item);
+ }
+
+ private void setFormDateResolution(Resolution resolution) {
+ if (startDateField != null && endDateField != null) {
+ startDateField.setResolution(resolution);
+ endDateField.setResolution(resolution);
+ }
+ }
+
+ private CalendarEvent createNewEvent(Date startDate, Date endDate) {
+
+ BasicEvent event = new BasicEvent();
+ event.setCaption("");
+ event.setStart(startDate);
+ event.setEnd(endDate);
+ event.setStyleName("color1");
+ return event;
+ }
+
+ /* Removes the event from the data source and fires change event. */
+ private void deleteCalendarEvent() {
+ BasicEvent event = getFormCalendarEvent();
+ if (dataSource.containsEvent(event)) {
+ dataSource.removeEvent(event);
+ }
+ removeWindow(scheduleEventPopup);
+ }
+
+ /* Adds/updates the event in the data source and fires change event. */
+ private void commitCalendarEvent() throws CommitException {
+ scheduleEventFieldGroup.commit();
+ BasicEvent event = getFormCalendarEvent();
+ if (event.getEnd() == null) {
+ event.setEnd(event.getStart());
+ }
+ if (!dataSource.containsEvent(event)) {
+ dataSource.addEvent(event);
+ }
+
+ removeWindow(scheduleEventPopup);
+ }
+
+ private void discardCalendarEvent() {
+ scheduleEventFieldGroup.discard();
+ removeWindow(scheduleEventPopup);
+ }
+
+ @SuppressWarnings("unchecked")
+ private BasicEvent getFormCalendarEvent() {
+ BeanItem<CalendarEvent> item = (BeanItem<CalendarEvent>) scheduleEventFieldGroup
+ .getItemDataSource();
+ CalendarEvent event = item.getBean();
+ return (BasicEvent) event;
+ }
+
+ private void nextMonth() {
+ rollMonth(1);
+ }
+
+ private void previousMonth() {
+ rollMonth(-1);
+ }
+
+ private void nextWeek() {
+ rollWeek(1);
+ }
+
+ private void previousWeek() {
+ rollWeek(-1);
+ }
+
+ private void nextDay() {
+ rollDate(1);
+ }
+
+ private void previousDay() {
+ rollDate(-1);
+ }
+
+ private void rollMonth(int direction) {
+ calendar.setTime(currentMonthsFirstDate);
+ calendar.add(GregorianCalendar.MONTH, direction);
+ resetTime(false);
+ currentMonthsFirstDate = calendar.getTime();
+ calendarComponent.setStartDate(currentMonthsFirstDate);
+
+ updateCaptionLabel();
+
+ calendar.add(GregorianCalendar.MONTH, 1);
+ calendar.add(GregorianCalendar.DATE, -1);
+ resetCalendarTime(true);
+ }
+
+ private void rollWeek(int direction) {
+ calendar.add(GregorianCalendar.WEEK_OF_YEAR, direction);
+ calendar.set(GregorianCalendar.DAY_OF_WEEK,
+ calendar.getFirstDayOfWeek());
+ resetCalendarTime(false);
+ resetTime(true);
+ calendar.add(GregorianCalendar.DATE, 6);
+ calendarComponent.setEndDate(calendar.getTime());
+ }
+
+ private void rollDate(int direction) {
+ calendar.add(GregorianCalendar.DATE, direction);
+ resetCalendarTime(false);
+ resetCalendarTime(true);
+ }
+
+ private void updateCaptionLabel() {
+ DateFormatSymbols s = new DateFormatSymbols(getLocale());
+ String month = s.getShortMonths()[calendar.get(GregorianCalendar.MONTH)];
+ captionLabel.setValue(month + " "
+ + calendar.get(GregorianCalendar.YEAR));
+ }
+
+ private CalendarTestEvent getNewEvent(String caption, Date start, Date end) {
+ CalendarTestEvent event = new CalendarTestEvent();
+ event.setCaption(caption);
+ event.setStart(start);
+ event.setEnd(end);
+
+ return event;
+ }
+
+ /*
+ * Switch the view to week view.
+ */
+ public void switchToWeekView() {
+ viewMode = Mode.WEEK;
+ weekButton.setVisible(false);
+ monthButton.setVisible(true);
+ }
+
+ /*
+ * Switch the Calendar component's start and end date range to the target
+ * month only. (sample range: 01.01.2010 00:00.000 - 31.01.2010 23:59.999)
+ */
+ public void switchToMonthView() {
+ viewMode = Mode.MONTH;
+ monthButton.setVisible(false);
+ weekButton.setVisible(false);
+
+ calendar.setTime(currentMonthsFirstDate);
+ calendarComponent.setStartDate(currentMonthsFirstDate);
+
+ updateCaptionLabel();
+
+ calendar.add(GregorianCalendar.MONTH, 1);
+ calendar.add(GregorianCalendar.DATE, -1);
+ resetCalendarTime(true);
+ }
+
+ /*
+ * Switch to day view (week view with a single day visible).
+ */
+ public void switchToDayView() {
+ viewMode = Mode.DAY;
+ monthButton.setVisible(true);
+ weekButton.setVisible(true);
+ }
+
+ private void resetCalendarTime(boolean resetEndTime) {
+ resetTime(resetEndTime);
+ if (resetEndTime) {
+ calendarComponent.setEndDate(calendar.getTime());
+ } else {
+ calendarComponent.setStartDate(calendar.getTime());
+ updateCaptionLabel();
+ }
+ }
+
+ /*
+ * Resets the calendar time (hour, minute second and millisecond) either to
+ * zero or maximum value.
+ */
+ private void resetTime(boolean max) {
+ if (max) {
+ calendar.set(GregorianCalendar.HOUR_OF_DAY,
+ calendar.getMaximum(GregorianCalendar.HOUR_OF_DAY));
+ calendar.set(GregorianCalendar.MINUTE,
+ calendar.getMaximum(GregorianCalendar.MINUTE));
+ calendar.set(GregorianCalendar.SECOND,
+ calendar.getMaximum(GregorianCalendar.SECOND));
+ calendar.set(GregorianCalendar.MILLISECOND,
+ calendar.getMaximum(GregorianCalendar.MILLISECOND));
+ } else {
+ calendar.set(GregorianCalendar.HOUR_OF_DAY, 0);
+ calendar.set(GregorianCalendar.MINUTE, 0);
+ calendar.set(GregorianCalendar.SECOND, 0);
+ calendar.set(GregorianCalendar.MILLISECOND, 0);
+ }
+ }
+
+ private static Date getEndOfDay(java.util.Calendar calendar, Date date) {
+ java.util.Calendar calendarClone = (java.util.Calendar) calendar
+ .clone();
+
+ calendarClone.setTime(date);
+ calendarClone.set(java.util.Calendar.MILLISECOND,
+ calendarClone.getActualMaximum(java.util.Calendar.MILLISECOND));
+ calendarClone.set(java.util.Calendar.SECOND,
+ calendarClone.getActualMaximum(java.util.Calendar.SECOND));
+ calendarClone.set(java.util.Calendar.MINUTE,
+ calendarClone.getActualMaximum(java.util.Calendar.MINUTE));
+ calendarClone.set(java.util.Calendar.HOUR,
+ calendarClone.getActualMaximum(java.util.Calendar.HOUR));
+ calendarClone.set(java.util.Calendar.HOUR_OF_DAY,
+ calendarClone.getActualMaximum(java.util.Calendar.HOUR_OF_DAY));
+
+ return calendarClone.getTime();
+ }
+
+ private static Date getStartOfDay(java.util.Calendar calendar, Date date) {
+ java.util.Calendar calendarClone = (java.util.Calendar) calendar
+ .clone();
+
+ calendarClone.setTime(date);
+ calendarClone.set(java.util.Calendar.MILLISECOND, 0);
+ calendarClone.set(java.util.Calendar.SECOND, 0);
+ calendarClone.set(java.util.Calendar.MINUTE, 0);
+ calendarClone.set(java.util.Calendar.HOUR, 0);
+ calendarClone.set(java.util.Calendar.HOUR_OF_DAY, 0);
+
+ return calendarClone.getTime();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarTestEvent.java b/uitest/src/com/vaadin/tests/components/calendar/CalendarTestEvent.java
new file mode 100644
index 0000000000..29b8f62403
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarTestEvent.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+
+/**
+ * Test CalendarEvent implementation.
+ *
+ * @see com.vaadin.addon.calendar.test.ui.Calendar.Event
+ */
+public class CalendarTestEvent extends BasicEvent {
+
+ private static final long serialVersionUID = 2820133201983036866L;
+ private String where;
+ private Object data;
+
+ public String getWhere() {
+ return where;
+ }
+
+ public void setWhere(String where) {
+ this.where = where;
+ fireEventChange();
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void setData(Object data) {
+ this.data = data;
+ fireEventChange();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarVisibleHours24H.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarVisibleHours24H.html
new file mode 100644
index 0000000000..6b7bb26b76
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarVisibleHours24H.html
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>visibleHours24H</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">visibleHours24H</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;firstDay=1&amp;lastDay=5&amp;firstHour=8&amp;lastHour=16&amp;restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[1]/domChild[1]/domChild[0]/domChild[0]</td>
+ <td>9,55</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[2]/VFilterSelect[0]#button</td>
+ <td>14,5</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='VAADIN_COMBOBOX_OPTIONLIST']/div/div[2]/table/tbody/tr[4]/td</td>
+ <td>120,15</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>9:00</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[8]</td>
+ <td>16:00</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/CalendarWeeklyViewNewEvents.html b/uitest/src/com/vaadin/tests/components/calendar/CalendarWeeklyViewNewEvents.html
new file mode 100644
index 0000000000..fd51a0daad
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/CalendarWeeklyViewNewEvents.html
@@ -0,0 +1,657 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>weeklyViewNewEvents</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">weeklyViewNewEvents</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.calendar.CalendarTest?testBench&amp;width=1000px&amp;height=600px&amp;restartApplication</td>
+ <td></td>
+</tr>
+<!--Go to weekly view-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[1]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>3,49</td>
+</tr>
+<!--Assert the default event contents-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]/domChild[0]/domChild[48]/domChild[0]/domChild[0]</td>
+ <td>26,5</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/10/00 09:30 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/10/00 02:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>off</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Appointment</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[1]</td>
+ <td>Office</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>A longer description, which should display correctly.</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Green</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[48]/domChild[0]/domChild[0]</td>
+ <td>21,12</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 11:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 07:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Training</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Blue</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[7]/domChild[0]/domChild[48]/domChild[0]/domChild[0]</td>
+ <td>19,9</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/15/00 09:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/15/00 06:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Free time</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[6]/domChild[0]/domChild[0]</td>
+ <td>22,6</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/9/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/15/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VCheckBox[0]/domChild[0]</td>
+ <td>on</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Whole week event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Description for the whole week event.</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Orange</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Assert the all-day events-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[1]</td>
+ <td>78,3</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/12/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/12/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Allday event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Some description.</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Red</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[4]/domChild[0]/domChild[1]</td>
+ <td>57,7</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/13/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/13/00</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Second allday event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Some description.</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Blue</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Enter new event-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/13/00 9:00 AM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/13/00 2:00 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Test event description</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[1]</td>
+ <td>3,15</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item4</td>
+ <td>36,6</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Assert previously created event-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[5]/domChild[0]/domChild[48]/domChild[0]</td>
+ <td>47,21</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/13/00 09:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/13/00 02:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Test event description</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VFilterSelect[0]/domChild[0]</td>
+ <td>Orange</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>8,9</td>
+</tr>
+<!--Edit previously created events and change properties-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[5]/domChild[0]/domChild[48]/domChild[0]</td>
+ <td>33,16</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#popupButton</td>
+ <td>10,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::Root/VOverlay[0]/VCalendarPanel[0]#day11</td>
+ <td>16,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#popupButton</td>
+ <td>14,14</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::Root/VOverlay[0]/VCalendarPanel[0]#day11</td>
+ <td>14,10</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Assert the edited values-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[49]/domChild[0]</td>
+ <td>34,21</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 09:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 02:00 PM</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Create new event-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[0]/Slot[6]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 10:00 AM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 8:00 PM</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event 2</td>
+</tr>
+<tr>
+ <td>enterCharacter</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextArea[0]</td>
+ <td>Second test event</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Assert previously created event still exists in the right place (as multiple events occupy the same time)-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[50]/domChild[0]</td>
+ <td>7,73</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 09:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 02:00 PM</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Assert previously created event still exists in the right place (as multiple events occupy the same time)-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[49]/domChild[0]/domChild[0]</td>
+ <td>12,32</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 11:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 07:00 PM</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>11,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[48]/domChild[1]</td>
+ <td>4,9</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 10:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 08:00 PM</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[50]/domChild[0]</td>
+ <td>14,71</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 09:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 02:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[48]/domChild[0]</td>
+ <td>16,111</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 10:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 08:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event 2</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[48]/domChild[0]</td>
+ <td>14,209</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 10:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 08:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event 2</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[49]/domChild[0]/domChild[0]</td>
+ <td>20,113</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 11:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 07:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Training</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>7,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[3]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]/domChild[50]/domChild[0]</td>
+ <td>21,87</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[0]#field</td>
+ <td>1/11/00 09:00 AM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VPopupCalendar[1]#field</td>
+ <td>1/11/00 02:00 PM</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>12,10</td>
+</tr>
+<!--Go to monthly view and assert inserted events-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VHorizontalLayout[1]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[2]/domChild[2]/domChild[0]/domChild[4]</td>
+ <td>36,10</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[2]/domChild[2]/domChild[0]/domChild[3]</td>
+ <td>53,6</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Training</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[2]/domChild[2]/domChild[0]/domChild[2]/domChild[0]</td>
+ <td>48,7</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Test event 2</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VGridLayout[0]/VCalendar[0]/domChild[0]/domChild[1]/domChild[1]/domChild[0]/domChild[1]/domChild[2]/domChild[4]/domChild[0]/domChild[1]</td>
+ <td>50,6</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VFormLayout[0]/VFormLayout$VFormLayoutTable[0]/VTextField[0]</td>
+ <td>Whole week event</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentscalendarCalendarTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/calendar/HiddenFwdBackButtons.java b/uitest/src/com/vaadin/tests/components/calendar/HiddenFwdBackButtons.java
new file mode 100644
index 0000000000..8b789098e6
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/HiddenFwdBackButtons.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import java.util.Date;
+import java.util.Locale;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.BackwardHandler;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.ForwardHandler;
+
+public class HiddenFwdBackButtons extends UI {
+
+ @SuppressWarnings("deprecation")
+ @Override
+ protected void init(VaadinRequest request) {
+ GridLayout content = new GridLayout(1, 2);
+ content.setSizeFull();
+ setContent(content);
+
+ final Calendar calendar = new Calendar();
+ calendar.setLocale(new Locale("fi", "FI"));
+
+ calendar.setSizeFull();
+ calendar.setStartDate(new Date(100, 1, 1));
+ calendar.setEndDate(new Date(100, 1, 7));
+ content.addComponent(calendar);
+ Button button = new Button("Hide forward and back buttons");
+ button.addClickListener(new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ // This should hide the forward and back navigation buttons
+ calendar.setHandler((BackwardHandler) null);
+ calendar.setHandler((ForwardHandler) null);
+ }
+ });
+ content.addComponent(button);
+
+ content.setRowExpandRatio(0, 1);
+
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/calendar/NotificationTestUI.java b/uitest/src/com/vaadin/tests/components/calendar/NotificationTestUI.java
new file mode 100644
index 0000000000..6e5718a652
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/calendar/NotificationTestUI.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.calendar;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Calendar;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
+import com.vaadin.ui.components.calendar.CalendarComponentEvents.DateClickHandler;
+import com.vaadin.ui.components.calendar.event.BasicEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEvent;
+import com.vaadin.ui.components.calendar.event.CalendarEventProvider;
+
+public class NotificationTestUI extends UI {
+
+ private DummyEventProvider provider;
+
+ private static class DummyEventProvider implements CalendarEventProvider {
+
+ private int index;
+ private List<CalendarEvent> events = new ArrayList<CalendarEvent>();
+
+ public void addEvent(Date date) {
+ BasicEvent e = new BasicEvent();
+ e.setAllDay(true);
+ e.setStart(date);
+ e.setEnd(date);
+ e.setCaption("Some event " + ++index);
+ events.add(e);
+ }
+
+ @Override
+ public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
+ return events;
+ }
+
+ }
+
+ @Override
+ protected void init(com.vaadin.server.VaadinRequest request) {
+ GridLayout content = new GridLayout(1, 2);
+ content.setSizeFull();
+ content.setRowExpandRatio(1, 1.0f);
+ setContent(content);
+ final Button btn = new Button("Show working notification",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Notification
+ .show("This will disappear when you move your mouse!");
+ }
+ });
+ content.addComponent(btn);
+
+ provider = new DummyEventProvider();
+ final Calendar cal = new Calendar(provider);
+ cal.setLocale(Locale.US);
+ cal.setSizeFull();
+ cal.setHandler(new DateClickHandler() {
+ @Override
+ public void dateClick(DateClickEvent event) {
+ provider.addEvent(event.getDate());
+ Notification
+ .show("This should disappear, but if wont unless clicked.");
+
+ // this requestRepaint call interferes with the notification
+ cal.markAsDirty();
+ }
+ });
+ content.addComponent(cal);
+
+ java.util.Calendar javaCal = java.util.Calendar.getInstance();
+ javaCal.set(java.util.Calendar.YEAR, 2000);
+ javaCal.set(java.util.Calendar.MONTH, 0);
+ javaCal.set(java.util.Calendar.DAY_OF_MONTH, 1);
+ Date start = javaCal.getTime();
+ javaCal.set(java.util.Calendar.DAY_OF_MONTH, 31);
+ Date end = javaCal.getTime();
+
+ cal.setStartDate(start);
+ cal.setEndDate(end);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRevertValueChange.java b/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRevertValueChange.java
index 5b086fb935..cc26cf8845 100644
--- a/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRevertValueChange.java
+++ b/uitest/src/com/vaadin/tests/components/checkbox/CheckBoxRevertValueChange.java
@@ -29,6 +29,7 @@ public class CheckBoxRevertValueChange extends AbstractTestUIWithLog {
final CheckBox alwaysUnchecked = new CheckBox("You may not check me");
alwaysUnchecked
.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
public void valueChange(Property.ValueChangeEvent event) {
if (alwaysUnchecked.getValue()) {
log("I said no checking!");
@@ -40,6 +41,7 @@ public class CheckBoxRevertValueChange extends AbstractTestUIWithLog {
alwaysChecked.setValue(true);
alwaysChecked
.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
public void valueChange(Property.ValueChangeEvent event) {
if (!alwaysChecked.getValue()) {
log("I said no unchecking!");
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxDuplicateCaption.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxDuplicateCaption.java
index 3c1e8a27d6..bd71850a89 100644
--- a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxDuplicateCaption.java
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxDuplicateCaption.java
@@ -38,6 +38,7 @@ public class ComboBoxDuplicateCaption extends TestBase {
box.setImmediate(true);
box.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(
com.vaadin.data.Property.ValueChangeEvent event) {
Person p = (Person) event.getProperty().getValue();
diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.java
index 23a75ae56e..75010f0ea9 100644
--- a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.java
+++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxSQLContainerFilteredValueChange.java
@@ -53,6 +53,7 @@ public class ComboBoxSQLContainerFilteredValueChange extends TestBase {
myCombo.setWidth("100.0%");
myCombo.setHeight("-1px");
myCombo.addListener(new Property.ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
selectedLabel.setValue("Selected: "
+ event.getProperty().getValue());
@@ -72,6 +73,7 @@ public class ComboBoxSQLContainerFilteredValueChange extends TestBase {
/**
* (Re)creates the test table
+ *
* @param connectionPool
*/
private void createTestTable(JDBCConnectionPool connectionPool) {
@@ -97,6 +99,7 @@ public class ComboBoxSQLContainerFilteredValueChange extends TestBase {
/**
* Adds test data to the test table
+ *
* @param connectionPool
* @throws SQLException
*/
@@ -111,7 +114,7 @@ public class ComboBoxSQLContainerFilteredValueChange extends TestBase {
statement.executeUpdate("INSERT INTO mytable VALUES(2, 'A1')");
statement.executeUpdate("INSERT INTO mytable VALUES(3, 'B0')");
statement.executeUpdate("INSERT INTO mytable VALUES(4, 'B1')");
-
+
statement.close();
conn.commit();
} catch (SQLException e) {
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java
new file mode 100644
index 0000000000..2daa3e3f96
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges.java
@@ -0,0 +1,270 @@
+package com.vaadin.tests.components.datefield;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.MarginInfo;
+import com.vaadin.shared.ui.datefield.Resolution;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.VerticalLayout;
+
+public class DateFieldRanges extends AbstractTestUI {
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 6241;
+ }
+
+ private Label label = new Label();
+ private NativeSelect resoSelect = new NativeSelect("Resolution");
+ private DateField fromRange = new DateField("Range start");
+ private DateField toRange = new DateField("Range end");
+ private DateField valueDF = new DateField("Value");
+ private CheckBox immediateCB = new CheckBox("Immediate");
+ private Button recreate = new Button("Recreate static datefields");
+ private Button clearRangeButton = new Button("Clear range");
+
+ private GridLayout currentStaticContainer;
+
+ private DateField inlineDynamicDateField;
+ private DateField dynamicDateField;
+
+ private Calendar createCalendar() {
+ Calendar c = Calendar.getInstance();
+ c.set(2013, 3, 26, 6, 1, 12);
+ return c;
+ }
+
+ private Date newDate() {
+ return createCalendar().getTime();
+ }
+
+ private void initializeControlFields() {
+ resoSelect.addItem(Resolution.MINUTE);
+ resoSelect.addItem(Resolution.SECOND);
+ resoSelect.addItem(Resolution.HOUR);
+ resoSelect.addItem(Resolution.DAY);
+ resoSelect.addItem(Resolution.MONTH);
+ resoSelect.addItem(Resolution.YEAR);
+ resoSelect.setImmediate(true);
+ resoSelect.setValue(Resolution.DAY);
+ resoSelect.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ Resolution r = (Resolution) resoSelect.getValue();
+ inlineDynamicDateField.setResolution(r);
+ dynamicDateField.setResolution(r);
+
+ }
+ });
+
+ fromRange.setValue(null);
+ fromRange.setImmediate(true);
+ fromRange.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setRangeStart(fromRange.getValue());
+ dynamicDateField.setRangeStart(fromRange.getValue());
+
+ }
+ });
+
+ toRange.setValue(null);
+ toRange.setImmediate(true);
+ toRange.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setRangeEnd(toRange.getValue());
+ dynamicDateField.setRangeEnd(toRange.getValue());
+
+ }
+ });
+
+ valueDF.setValue(null);
+ valueDF.setImmediate(true);
+ valueDF.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setValue(valueDF.getValue());
+ dynamicDateField.setValue(valueDF.getValue());
+
+ }
+ });
+
+ immediateCB.setValue(true);
+ immediateCB.setImmediate(true);
+ immediateCB.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ inlineDynamicDateField.setImmediate(immediateCB.getValue());
+ dynamicDateField.setImmediate(immediateCB.getValue());
+
+ }
+ });
+
+ recreate.addClickListener(new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ GridLayout newContainer = createStaticFields();
+ replaceComponent(currentStaticContainer, newContainer);
+ currentStaticContainer = newContainer;
+ }
+ });
+
+ clearRangeButton.addClickListener(new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ fromRange.setValue(null);
+ toRange.setValue(null);
+ }
+ });
+
+ Calendar startCal = createCalendar();
+ Calendar endCal = createCalendar();
+ endCal.add(Calendar.DATE, 30);
+
+ dynamicDateField = createDateField(startCal.getTime(),
+ endCal.getTime(), null, Resolution.DAY, false);
+ inlineDynamicDateField = createDateField(startCal.getTime(),
+ endCal.getTime(), null, Resolution.DAY, true);
+
+ resoSelect.setId("resoSelect");
+ fromRange.setId("fromRange");
+ toRange.setId("toRange");
+ valueDF.setId("valueDF");
+ immediateCB.setId("immediateCB");
+ recreate.setId("recreate");
+ clearRangeButton.setId("clearRangeButton");
+ dynamicDateField.setId("dynamicDateField");
+ inlineDynamicDateField.setId("inlineDynamicDateField");
+
+ }
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ setLocale(new Locale("en", "US"));
+ getLayout().setWidth(100, Unit.PERCENTAGE);
+ getLayout().setHeight(null);
+ getLayout().setMargin(new MarginInfo(true, false, false, false));
+ getLayout().setSpacing(true);
+
+ initializeControlFields();
+
+ GridLayout gl = new GridLayout(2, 2);
+ gl.setSpacing(true);
+
+ gl.addComponent(dynamicDateField);
+ gl.addComponent(inlineDynamicDateField);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setSpacing(true);
+ hl.addComponent(resoSelect);
+ hl.addComponent(fromRange);
+ hl.addComponent(toRange);
+ hl.addComponent(valueDF);
+ hl.addComponent(immediateCB);
+ hl.addComponent(recreate);
+ hl.addComponent(clearRangeButton);
+ addComponent(hl);
+ addComponent(new Label("Dynamic DateFields"));
+ addComponent(gl);
+ currentStaticContainer = createStaticFields();
+ addComponent(new Label("Static DateFields"));
+ addComponent(currentStaticContainer);
+
+ addComponent(label);
+
+ }
+
+ private GridLayout createStaticFields() {
+ Calendar startCal = createCalendar();
+ Calendar endCal = createCalendar();
+ endCal.add(Calendar.DATE, 30);
+ GridLayout gl = new GridLayout(2, 2);
+ gl.setSpacing(true);
+ DateField df = createDateField(startCal.getTime(), endCal.getTime(),
+ null, Resolution.DAY, false);
+ gl.addComponent(df);
+ DateField inline = createDateField(startCal.getTime(),
+ endCal.getTime(), null, Resolution.DAY, true);
+ gl.addComponent(inline);
+ inline.setId("staticInline");
+ VerticalLayout vl = new VerticalLayout();
+
+ return gl;
+ }
+
+ private DateField createDateField(Date rangeStart, Date rangeEnd,
+ Date value, Resolution resolution, boolean inline) {
+
+ DateField df = null;
+
+ if (inline) {
+ df = new InlineDateField();
+ } else {
+ df = new DateField();
+ }
+
+ final DateField gg = df;
+ updateValuesForDateField(df);
+
+ df.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ label.setValue((gg.getValue() == null ? "Nothing" : gg
+ .getValue().toString())
+ + " selected. isValid: "
+ + gg.isValid());
+ }
+ });
+ return df;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Not defined yet";
+
+ }
+
+ private void updateValuesForDateField(DateField df) {
+ Date fromVal = fromRange.getValue();
+ Date toVal = toRange.getValue();
+ Date value = valueDF.getValue();
+ Resolution r = (Resolution) resoSelect.getValue();
+ boolean immediate = immediateCB.getValue();
+
+ df.setValue(value);
+ df.setResolution(r);
+ df.setRangeStart(fromVal);
+ df.setRangeEnd(toVal);
+ df.setImmediate(immediate);
+
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html
new file mode 100644
index 0000000000..ca5c006e82
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_ChangingRangeSoValueFallsOutsideRangeCausesOutOfRangeExceptionIfImmediateField.html
@@ -0,0 +1,186 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>59,10</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4/4/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>36,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>2/2/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>48,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5/5/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>50,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>12,14</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::PID_SinlineDynamicDateField/VCalendarPanel[0]#header</td>
+ <td>April 2013</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#popupButton</td>
+ <td>14,15</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[15]</td>
+ <td>14,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[15]</td>
+ <td>14,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[4]/span</td>
+ <td>18,12</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::PID_SinlineDynamicDateField/VCalendarPanel[0]#header</td>
+ <td>March 2013</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertTextNotPresent</td>
+ <td>April 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>15,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>15,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>14,14</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[12]</td>
+ <td>18,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[12]</td>
+ <td>12,10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[11]</td>
+ <td>17,14</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>February 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='staticInline']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[5]/span</td>
+ <td>14,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='inlineDynamicDateField']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[5]/span</td>
+ <td>15,6</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='staticInline']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[8]/span</td>
+ <td>14,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='inlineDynamicDateField']/table/tbody/tr[2]/td/table/tbody/tr[2]/td[8]/span</td>
+ <td>19,4</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+<tr>
+ <td>assertNotCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html
new file mode 100644
index 0000000000..b19f519cb1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_EndRangeEarlierThanStartRangeCausesException.html
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>44,6</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>4/4/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>41,14</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>3/3/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>33,9</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-errorindicator</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html
new file mode 100644
index 0000000000..eeeda5270b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_InitialDatesOutsideRange.html
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>39,14</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1/1/13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>31,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1/2/11</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>111</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1/1/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>52,12</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[5]/VButton[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VGridLayout[0]/domChild[2]/domChild[0]/domChild[0]</td>
+ <td>v-errorindicator</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html
new file mode 100644
index 0000000000..6e1ca024cb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_MonthChangeMeansFocusDayRolledInsideRange.html
@@ -0,0 +1,100 @@
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>27,11</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1/1/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>47,10</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>2/2/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>15,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VGridLayout[0]/VPopupCalendar[0]#popupButton</td>
+ <td>9,14</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>id=PID_VAADIN_POPUPCAL</td>
+ <td>left</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>id=PID_VAADIN_POPUPCAL</td>
+ <td>left</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr/td[3]/span</td>
+ <td>January 2010</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>id=PID_VAADIN_POPUPCAL</td>
+ <td>right</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr/td[3]/span</td>
+ <td>February 2010</td>
+</tr>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html
new file mode 100644
index 0000000000..f5d7ee97ca
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_NextYearClickableIfRangeAcceptsFractionOfNextYear.html
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>37,13</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1/1/15</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>35,7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>12/12/14</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>40,10</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2014</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>11,8</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>13,10</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>6,7</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>15,7</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>8,8</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::PID_SresoSelect/domChild[0]</td>
+ <td>label=MONTH</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>13,11</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2015</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>12,13</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>12,13</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2013</td>
+ <td></td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::PID_SresoSelect/domChild[0]</td>
+ <td>label=YEAR</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>8,12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>8,12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>8,12</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>2015</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html
new file mode 100644
index 0000000000..4c671b266d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_PrevYearClickableIfRangeAcceptsFractionOfPrevYear.html
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>33,10</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>12</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>12/12/10</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>32,9</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>11</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>enter</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>1/1/11</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>January 2011</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>13,12</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2010</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[6]</td>
+ <td>9,7</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2010</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[5]</td>
+ <td>5,0</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>December 2010</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>16,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[7]</td>
+ <td>16,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[8]</td>
+ <td>19,8</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>February 2012</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html
new file mode 100644
index 0000000000..c3f7e021a8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldRanges_SettingValueOutsideRangeCausesException.html
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.datefield.DateFieldRanges</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>36,8</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#field</td>
+ <td>4/4/12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>40,11</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>3</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>3/3/12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>40,5</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5</td>
+</tr>
+<tr>
+ <td>pressSpecialKey</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>shift 7</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>5/5/12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]</td>
+ <td>393,89</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldRanges::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[3]/VPopupCalendar[0]#popupButton</td>
+ <td>10,8</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=(//button[@type='button'])[17]</td>
+ <td>12,11</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//table[@id='PID_VAADIN_POPUPCAL']/tbody/tr[2]/td/table/tbody/tr[4]/td[5]/span</td>
+ <td>13,9</td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>May 2012</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalRelativeSizeWithoutExpand.java b/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalRelativeSizeWithoutExpand.java
index 86525da3ef..0ac9a008d2 100755
--- a/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalRelativeSizeWithoutExpand.java
+++ b/uitest/src/com/vaadin/tests/components/orderedlayout/VerticalRelativeSizeWithoutExpand.java
@@ -1,4 +1,5 @@
package com.vaadin.tests.components.orderedlayout;
+
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Panel;
diff --git a/uitest/src/com/vaadin/tests/components/page/PageReload.html b/uitest/src/com/vaadin/tests/components/page/PageReload.html
new file mode 100644
index 0000000000..20d61a48f1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/page/PageReload.html
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.page.PageReload?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentspagePageReload::PID_SLog_row_0</td>
+ <td>1. UI id: 0</td>
+</tr>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.page.PageReload</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentspagePageReload::PID_SLog_row_0</td>
+ <td>1. UI id: 1</td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>vaadin=runcomvaadintestscomponentspagePageReload::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentspagePageReload::PID_SLog_row_0</td>
+ <td>1. UI id: 2</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/page/PageReload.java b/uitest/src/com/vaadin/tests/components/page/PageReload.java
new file mode 100644
index 0000000000..c1799b29e3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/page/PageReload.java
@@ -0,0 +1,34 @@
+package com.vaadin.tests.components.page;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+
+public class PageReload extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button b = new Button("Press to reload");
+ b.addClickListener(new ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ getPage().reload();
+ }
+ });
+ addComponent(b);
+ log("UI id: " + getUIId());
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests Page.reload(). Click button to refresh the page.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 10250;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/popupview/ClickingWhilePopupOpen.html b/uitest/src/com/vaadin/tests/components/popupview/ClickingWhilePopupOpen.html
index 81676f6599..43f1c2e8ed 100644
--- a/uitest/src/com/vaadin/tests/components/popupview/ClickingWhilePopupOpen.html
+++ b/uitest/src/com/vaadin/tests/components/popupview/ClickingWhilePopupOpen.html
@@ -28,7 +28,7 @@
</tr>
<tr>
<td>assertTextNotPresent</td>
- <td>IllegalStateException: Cannot set a new parent without first clearing the old parent</td>
+ <td>Uncaught client side exception</td>
<td></td>
</tr>
diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaEmptyString.java b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaEmptyString.java
index 5eddf9dc6d..01dc10220f 100644
--- a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaEmptyString.java
+++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaEmptyString.java
@@ -29,6 +29,7 @@ public class RichTextAreaEmptyString extends TestBase {
final Button b = new Button("get area value", new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
l.setValue(area.getValue());
}
diff --git a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaPreventsTextFieldAccess.java b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaPreventsTextFieldAccess.java
index f4ad149dd1..c3433c3054 100644
--- a/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaPreventsTextFieldAccess.java
+++ b/uitest/src/com/vaadin/tests/components/richtextarea/RichTextAreaPreventsTextFieldAccess.java
@@ -50,6 +50,7 @@ public class RichTextAreaPreventsTextFieldAccess extends TestBase {
Button addWindowButton = new Button("Open RichTextArea-Dialog");
addWindowButton.addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
getMainWindow().addWindow(subWindow);
@@ -60,6 +61,7 @@ public class RichTextAreaPreventsTextFieldAccess extends TestBase {
Button removeWindowButton = new Button("removeWindowButton");
removeWindowButton.addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
getMainWindow().removeWindow(subWindow);
@@ -70,6 +72,7 @@ public class RichTextAreaPreventsTextFieldAccess extends TestBase {
Button focusButton = new Button("Set focus on TextField");
focusButton.addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
testField.focus();
@@ -80,6 +83,7 @@ public class RichTextAreaPreventsTextFieldAccess extends TestBase {
Button removeRTA = new Button("Remove RTA");
removeRTA.addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
wLayout.removeComponent(rText);
diff --git a/uitest/src/com/vaadin/tests/components/select/OptionGroupBaseSelects.java b/uitest/src/com/vaadin/tests/components/select/OptionGroupBaseSelects.java
index f2dee69cbf..0df82688d1 100644
--- a/uitest/src/com/vaadin/tests/components/select/OptionGroupBaseSelects.java
+++ b/uitest/src/com/vaadin/tests/components/select/OptionGroupBaseSelects.java
@@ -29,6 +29,7 @@ public class OptionGroupBaseSelects extends ComponentTestCase<HorizontalLayout>
CheckBox cb = new CheckBox("Switch Selects ReadOnly", false);
cb.addListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
for (Iterator<Component> it = layout.getComponentIterator(); it
.hasNext();) {
@@ -42,6 +43,7 @@ public class OptionGroupBaseSelects extends ComponentTestCase<HorizontalLayout>
CheckBox cb2 = new CheckBox("Switch Selects Enabled", true);
cb2.addListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
for (Iterator<Component> it = layout.getComponentIterator(); it
.hasNext();) {
diff --git a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html
index 9e529836b6..4dc63721a1 100644
--- a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html
+++ b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html
@@ -13,12 +13,7 @@
</thead><tbody>
<tr>
<td>open</td>
- <td>/run/com.vaadin.tests.components.table.ColumnCollapsingAndColumnExpansion</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
+ <td>/run/com.vaadin.tests.components.table.ColumnCollapsingAndColumnExpansion?restartApplication</td>
<td></td>
</tr>
<!--Initial state, all 3 columns visible-->
@@ -32,32 +27,17 @@
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[1]</td>
<td></td>
</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
<!--Hide 'col2' through table interface-->
<tr>
- <td>click</td>
- <td>//td[@id='gwt-uid-2']/span/div</td>
- <td></td>
-</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
+ <td>mouseClick</td>
+ <td>//tr[2]/td/span/div</td>
+ <td>23,2</td>
</tr>
<tr>
<td>screenCapture</td>
<td></td>
<td>col2-hidden</td>
</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
<!--Hide 'Col1' using button-->
<tr>
<td>enterCharacter</td>
@@ -65,62 +45,32 @@
<td>Col1</td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>click</td>
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]</td>
<td></td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>screenCapture</td>
<td></td>
<td>col1-col2-hidden</td>
</tr>
<!--Show 'col2' using action handler-->
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>contextmenu</td>
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]</td>
<td></td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>mouseClick</td>
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VContextMenu[0]#option0</td>
<td>11,6</td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>enterCharacter</td>
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]</td>
<td>Col2</td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>screenCapture</td>
<td></td>
<td>col1-hidden</td>
@@ -132,27 +82,16 @@
<td>Col1</td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>click</td>
<td>vaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td>
<td></td>
</tr>
-<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
<!--We should now be back at the initial state, all 3 columns visible-->
<tr>
<td>screenCapture</td>
<td></td>
<td>col1-col2-col3-visible-again</td>
</tr>
-
</tbody></table>
</body>
</html>
diff --git a/uitest/src/com/vaadin/tests/components/table/EmptyRowsWhenScrolling.java b/uitest/src/com/vaadin/tests/components/table/EmptyRowsWhenScrolling.java
index c1ae9b4118..3bc0d3dd1f 100644
--- a/uitest/src/com/vaadin/tests/components/table/EmptyRowsWhenScrolling.java
+++ b/uitest/src/com/vaadin/tests/components/table/EmptyRowsWhenScrolling.java
@@ -93,6 +93,7 @@ public class EmptyRowsWhenScrolling extends UI {
table.setVisibleColumns(new String[] { "image", "id", "col1",
"col2", "col3", "col4" });
table.addGeneratedColumn("image", new ColumnGenerator() {
+ @Override
public Object generateCell(Table source, Object itemId,
Object columnId) {
int imgNum = new Random().nextInt(5) + 1;
@@ -112,6 +113,7 @@ public class EmptyRowsWhenScrolling extends UI {
image.setWidth("50px");
image.setHeight("50px");
image.addClickListener(new com.vaadin.event.MouseEvents.ClickListener() {
+ @Override
public void click(
com.vaadin.event.MouseEvents.ClickEvent event) {
Notification.show("Image clicked!");
@@ -123,6 +125,7 @@ public class EmptyRowsWhenScrolling extends UI {
// Refresh table button
getBtnRefreshTable().addClickListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.refreshRowCache();
}
diff --git a/uitest/src/com/vaadin/tests/components/table/LargeSelectionCausesNPE.java b/uitest/src/com/vaadin/tests/components/table/LargeSelectionCausesNPE.java
index fb782b8ded..b6ee62ea59 100644
--- a/uitest/src/com/vaadin/tests/components/table/LargeSelectionCausesNPE.java
+++ b/uitest/src/com/vaadin/tests/components/table/LargeSelectionCausesNPE.java
@@ -105,6 +105,7 @@ public class LargeSelectionCausesNPE extends TestBase {
}
Table.ValueChangeListener valueChangeListener = new Table.ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
// in multiselect mode, a Set of itemIds is returned,
// in singleselect mode the itemId is returned directly
@@ -119,6 +120,7 @@ public class LargeSelectionCausesNPE extends TestBase {
Button.ClickListener clickListener = new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
Property nameProperty = table.getContainerProperty(0, NAME);
if (("0").equals(nameLabel.getValue())) {
@@ -148,6 +150,7 @@ public class LargeSelectionCausesNPE extends TestBase {
ColumnGenerator columnGenerator = new ColumnGenerator() {
+ @Override
public Object generateCell(Table source, Object itemId,
Object columnId) {
Label label = new Label();
diff --git a/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndExpandRatios.java b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndExpandRatios.java
index 747c99468f..b1ecb3fc10 100644
--- a/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndExpandRatios.java
+++ b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndExpandRatios.java
@@ -38,10 +38,11 @@ public class TableColumnWidthsAndExpandRatios extends TestBase {
return new NativeButton("Reset " + property + " width",
new Button.ClickListener() {
- public void buttonClick(ClickEvent event) {
- table.setColumnWidth(property, -1);
- }
- });
+ @Override
+ public void buttonClick(ClickEvent event) {
+ table.setColumnWidth(property, -1);
+ }
+ });
}
@Override
diff --git a/uitest/src/com/vaadin/tests/components/table/TableInSubWindowMemoryLeak.java b/uitest/src/com/vaadin/tests/components/table/TableInSubWindowMemoryLeak.java
index dcaabf98d6..c0c8876fca 100644
--- a/uitest/src/com/vaadin/tests/components/table/TableInSubWindowMemoryLeak.java
+++ b/uitest/src/com/vaadin/tests/components/table/TableInSubWindowMemoryLeak.java
@@ -20,6 +20,7 @@ public class TableInSubWindowMemoryLeak extends TestBase {
final Button openButton = new Button("open me");
openButton.addClickListener(new ClickListener() {
+ @Override
public void buttonClick(final ClickEvent event) {
final Window window = new Window("Simple Window");
window.setModal(true);
@@ -29,6 +30,7 @@ public class TableInSubWindowMemoryLeak extends TestBase {
window.setContent(table);
UI.getCurrent().addWindow(window);
window.addCloseListener(new CloseListener() {
+ @Override
public void windowClose(final CloseEvent e) {
window.setContent(new Label());
UI.getCurrent().removeWindow(window);
@@ -40,6 +42,7 @@ public class TableInSubWindowMemoryLeak extends TestBase {
final Button openButton2 = new Button("open me without Table");
openButton2.addClickListener(new ClickListener() {
+ @Override
public void buttonClick(final ClickEvent event) {
final Window window = new Window("Simple Window");
window.setModal(true);
@@ -47,6 +50,7 @@ public class TableInSubWindowMemoryLeak extends TestBase {
window.setWidth("200px");
UI.getCurrent().addWindow(window);
window.addCloseListener(new CloseListener() {
+ @Override
public void windowClose(final CloseEvent e) {
UI.getCurrent().removeWindow(window);
}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java b/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java
index 9823fc1859..7d48dfa11e 100644
--- a/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java
+++ b/uitest/src/com/vaadin/tests/components/table/TableRowScrolledBottom.java
@@ -5,7 +5,6 @@ import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Button;
import com.vaadin.ui.Label;
import com.vaadin.ui.Table;
-import com.vaadin.ui.VerticalLayout;
public class TableRowScrolledBottom extends TestBase {
diff --git a/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java b/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java
index 9c5ce9dc0c..efa1b1bdab 100644
--- a/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java
+++ b/uitest/src/com/vaadin/tests/components/table/TableWithBrokenGeneratorAndContainer.java
@@ -78,6 +78,7 @@ public class TableWithBrokenGeneratorAndContainer extends TestBase {
this.brokenInterval = brokenInterval;
}
+ @Override
public Object generateCell(Table source, Object itemId, Object columnId) {
if (counter++ % brokenInterval == 0
&& Boolean.TRUE.equals(brokenGenerator.getValue())) {
@@ -97,6 +98,7 @@ public class TableWithBrokenGeneratorAndContainer extends TestBase {
clearTableOnError.setImmediate(true);
clearTableOnError.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
Boolean value = clearTableOnError.getValue();
setErrorHandler(value != null ? value : false);
@@ -110,6 +112,7 @@ public class TableWithBrokenGeneratorAndContainer extends TestBase {
Button refreshTableCache = new Button("Refresh table cache",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.markAsDirty();
table.refreshRowCache();
diff --git a/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java b/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java
index f378c146ea..b0622e748c 100644
--- a/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java
+++ b/uitest/src/com/vaadin/tests/components/table/ValueAfterClearingContainer.java
@@ -26,6 +26,7 @@ public class ValueAfterClearingContainer extends TestBase {
table.setImmediate(true);
table.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
log.log("Value changed to " + event.getProperty().getValue());
}
@@ -38,6 +39,7 @@ public class ValueAfterClearingContainer extends TestBase {
multiselect.setId("multiselect");
multiselect.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
Boolean value = multiselect.getValue();
table.setMultiSelect(value == null ? false : value);
@@ -46,6 +48,7 @@ public class ValueAfterClearingContainer extends TestBase {
addComponent(multiselect);
Button addItemsButton = new Button("Add table items",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
if (!table.getItemIds().isEmpty()) {
Notification
@@ -65,6 +68,7 @@ public class ValueAfterClearingContainer extends TestBase {
Button showValueButton = new Button("Show value",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
log.log("Table selection: " + table.getValue());
}
@@ -74,6 +78,7 @@ public class ValueAfterClearingContainer extends TestBase {
Button removeItemsFromTableButton = new Button(
"Remove items from table", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.removeAllItems();
}
@@ -83,6 +88,7 @@ public class ValueAfterClearingContainer extends TestBase {
Button removeItemsFromContainerButton = new Button(
"Remove items from container", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.getContainerDataSource().removeAllItems();
}
@@ -92,6 +98,7 @@ public class ValueAfterClearingContainer extends TestBase {
Button removeItemsFromContainerAndSanitizeButton = new Button(
"Remove items from container and sanitize",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.getContainerDataSource().removeAllItems();
table.sanitizeSelection();
@@ -102,6 +109,7 @@ public class ValueAfterClearingContainer extends TestBase {
addComponent(removeItemsFromContainerAndSanitizeButton);
Button removeSelectedFromTableButton = new Button(
"Remove selected item from table", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
Object selection = table.getValue();
if (selection == null) {
@@ -117,6 +125,7 @@ public class ValueAfterClearingContainer extends TestBase {
Button removeSelectedFromContainer = new Button(
"Remove selected item from container",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
Object selection = table.getValue();
if (selection == null) {
diff --git a/uitest/src/com/vaadin/tests/components/table/ViewPortCalculation.java b/uitest/src/com/vaadin/tests/components/table/ViewPortCalculation.java
index 878dd0d3c4..de32ea1fc0 100644
--- a/uitest/src/com/vaadin/tests/components/table/ViewPortCalculation.java
+++ b/uitest/src/com/vaadin/tests/components/table/ViewPortCalculation.java
@@ -43,6 +43,7 @@ public class ViewPortCalculation extends TestBase {
}
table.setCellStyleGenerator(new CellStyleGenerator() {
+ @Override
public String getStyle(Table source, Object itemId,
Object propertyId) {
if (itemId.equals(lastDoubleClickedItemId)) {
@@ -53,6 +54,7 @@ public class ViewPortCalculation extends TestBase {
});
table.addItemClickListener(new ItemClickListener() {
+ @Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
lastDoubleClickedItemId = event.getItemId();
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/ExtraScrollbarsInTabSheet.java b/uitest/src/com/vaadin/tests/components/tabsheet/ExtraScrollbarsInTabSheet.java
index 2917eccbfb..fffc766e7c 100755
--- a/uitest/src/com/vaadin/tests/components/tabsheet/ExtraScrollbarsInTabSheet.java
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/ExtraScrollbarsInTabSheet.java
@@ -1,4 +1,5 @@
package com.vaadin.tests.components.tabsheet;
+
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.HorizontalSplitPanel;
diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/HiddenTabSheetBrowserResize.java b/uitest/src/com/vaadin/tests/components/tabsheet/HiddenTabSheetBrowserResize.java
index 0fdb579997..eac786d9b3 100644
--- a/uitest/src/com/vaadin/tests/components/tabsheet/HiddenTabSheetBrowserResize.java
+++ b/uitest/src/com/vaadin/tests/components/tabsheet/HiddenTabSheetBrowserResize.java
@@ -17,6 +17,7 @@ public class HiddenTabSheetBrowserResize extends TestBase {
Button toggleButton = new Button("Toggle TabSheet",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
tabSheet.setVisible(!tabSheet.isVisible());
}
diff --git a/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java b/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java
index c95731d94f..154a30a64b 100644
--- a/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java
+++ b/uitest/src/com/vaadin/tests/components/textarea/ScrollCursor.java
@@ -27,6 +27,7 @@ public class ScrollCursor extends TestBase {
Button button = new Button("Scroll");
button.addListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
textArea.setCursorPosition(getPosition());
}
@@ -34,6 +35,7 @@ public class ScrollCursor extends TestBase {
Button wrap = new Button("Set wrap");
wrap.addListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
textArea.setWordwrap(false);
}
@@ -42,6 +44,7 @@ public class ScrollCursor extends TestBase {
Button toBegin = new Button("To begin");
toBegin.addListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
position = 3;
}
@@ -50,6 +53,7 @@ public class ScrollCursor extends TestBase {
Button toMiddle = new Button("To middle");
toMiddle.addListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
position = 130;
}
@@ -58,6 +62,7 @@ public class ScrollCursor extends TestBase {
Button toEnd = new Button("To end");
toEnd.addListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
position = textArea.getValue().toString().length();
}
diff --git a/uitest/src/com/vaadin/tests/components/textfield/TextFieldMaxLengthRemovedFromDOM.java b/uitest/src/com/vaadin/tests/components/textfield/TextFieldMaxLengthRemovedFromDOM.java
index 28ff20c174..049b08d4e8 100644
--- a/uitest/src/com/vaadin/tests/components/textfield/TextFieldMaxLengthRemovedFromDOM.java
+++ b/uitest/src/com/vaadin/tests/components/textfield/TextFieldMaxLengthRemovedFromDOM.java
@@ -17,6 +17,7 @@ public class TextFieldMaxLengthRemovedFromDOM extends TestBase {
tf.addFocusListener(new FieldEvents.FocusListener() {
+ @Override
public void focus(FocusEvent event) {
// Resetting Max length should not remove maxlength attribute
tf.setMaxLength(11);
diff --git a/uitest/src/com/vaadin/tests/components/tree/SimpleTree.html b/uitest/src/com/vaadin/tests/components/tree/SimpleTree.html
new file mode 100644
index 0000000000..a446f67726
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tree/SimpleTree.html
@@ -0,0 +1,270 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>SimpleTree</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">SimpleTree</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.tree.SimpleTree?restartApplication</td>
+ <td></td>
+</tr>
+<!--Caption-->
+<tr>
+ <td>verifyElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VTree[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[0]@id</td>
+ <td>captionid</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]@aria-labelledby</td>
+ <td>${captionid}</td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]@id</td>
+ <td>treeid</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[0]@for</td>
+ <td>${treeid}</td>
+</tr>
+<!--Tree-->
+<tr>
+ <td>verifyElementPresent</td>
+ <td>xpath=/html/body/div/div/div[2]/div/div[2]/div/div/div/div[@aria-multiselectable='false']</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementPresent</td>
+ <td>xpath=/html/body/div/div/div[2]/div/div[2]/div/div/div/div[2]/div[@role='tree']</td>
+ <td></td>
+</tr>
+<!--Treeitem-->
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]@id</td>
+ <td>captionid</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]@aria-labelledby</td>
+ <td>${captionid}</td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]@id</td>
+ <td>treeitem10id</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]/domChild[0]@for</td>
+ <td>${treeitem10id}</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-level</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]@role</td>
+ <td>group</td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[1]@id</td>
+ <td>treeitem11id</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem11id}@role</td>
+ <td>treeitem</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem11id}@aria-level</td>
+ <td>2</td>
+</tr>
+<!--Open/Close-->
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-expanded</td>
+ <td>true</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=//div[@id='${treeitem10id}']</td>
+ <td>5,5</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-expanded</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=//div[@id='${treeitem10id}']</td>
+ <td>5,5</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-expanded</td>
+ <td>true</td>
+</tr>
+<!--Root Selected-->
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[1]/div[1]/span[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]@id</td>
+ <td>treeitem10id</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-selected</td>
+ <td>true</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[1]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[2]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[3]@aria-selected</td>
+ <td>false</td>
+</tr>
+<!--First child selected-->
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[1]/div[1]/div[1]/span[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]@id</td>
+ <td>treeitem10id</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[1]@aria-selected</td>
+ <td>true</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[2]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[3]@aria-selected</td>
+ <td>false</td>
+</tr>
+<!--Last child selected-->
+<tr>
+ <td>mouseClick</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[3]/div[1]/div[1]/span[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]@id</td>
+ <td>treeitem10id</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[1]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[2]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[3]@aria-selected</td>
+ <td>true</td>
+</tr>
+<!--Another root selected-->
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[1]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[1]@aria-selected</td>
+ <td>true</td>
+</tr>
+<tr>
+ <td>storeAttribute</td>
+ <td>vaadin=runcomvaadintestscomponentstreeSimpleTree::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]@id</td>
+ <td>treeitem10id</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>${treeitem10id}@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[1]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[2]@aria-selected</td>
+ <td>false</td>
+</tr>
+<tr>
+ <td>assertAttribute</td>
+ <td>xpath=//div[@id='${treeitem10id}']/div[2]/div[3]@aria-selected</td>
+ <td>false</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/tree/SimpleTree.java b/uitest/src/com/vaadin/tests/components/tree/SimpleTree.java
new file mode 100644
index 0000000000..2fd3f05dbb
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/tree/SimpleTree.java
@@ -0,0 +1,122 @@
+package com.vaadin.tests.components.tree;
+
+import java.util.Date;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.util.HierarchicalContainer;
+import com.vaadin.event.Action;
+import com.vaadin.server.ThemeResource;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractSelect;
+import com.vaadin.ui.Tree;
+
+public class SimpleTree extends TestBase implements Action.Handler {
+ private static final String[][] hardware = { //
+ { "Desktops", "Dell OptiPlex GX240", "Dell OptiPlex GX260",
+ "Dell OptiPlex GX280" },
+ { "Monitors", "Benq T190HD", "Benq T220HD", "Benq T240HD" },
+ { "Laptops", "IBM ThinkPad T40", "IBM ThinkPad T43",
+ "IBM ThinkPad T60" } };
+
+ ThemeResource notCachedFolderIconLargeOther = new ThemeResource(
+ "../runo/icons/16/ok.png?" + new Date().getTime());
+ ThemeResource notCachedFolderIconLarge = new ThemeResource(
+ "../runo/icons/16/folder.png?" + new Date().getTime());
+
+ // Actions for the context menu
+ private static final Action ACTION_ADD = new Action("Add child item");
+ private static final Action ACTION_DELETE = new Action("Delete");
+ private static final Action[] ACTIONS = new Action[] { ACTION_ADD,
+ ACTION_DELETE };
+
+ private Tree tree;
+
+ @Override
+ public void setup() {
+ // Create the Tree,a dd to layout
+ tree = new Tree("Hardware Inventory");
+ addComponent(tree);
+
+ // Contents from a (prefilled example) hierarchical container:
+ tree.setContainerDataSource(getHardwareContainer());
+
+ // Add actions (context menu)
+ tree.addActionHandler(this);
+
+ // Cause valueChange immediately when the user selects
+ tree.setImmediate(true);
+
+ // Set tree to show the 'name' property as caption for items
+ tree.setItemCaptionPropertyId("name");
+ tree.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
+
+ tree.setItemIcon(9, notCachedFolderIconLargeOther, "First Choice");
+ tree.setItemIcon(11, notCachedFolderIconLarge);
+
+ // Expand whole tree
+ for (Object id : tree.rootItemIds()) {
+ tree.expandItemsRecursively(id);
+ }
+ }
+
+ public static HierarchicalContainer getHardwareContainer() {
+ Item item = null;
+ int itemId = 0; // Increasing numbering for itemId:s
+
+ // Create new container
+ HierarchicalContainer hwContainer = new HierarchicalContainer();
+ // Create containerproperty for name
+ hwContainer.addContainerProperty("name", String.class, null);
+ // Create containerproperty for icon
+ hwContainer.addContainerProperty("icon", ThemeResource.class,
+ new ThemeResource("../runo/icons/16/document.png"));
+ for (int i = 0; i < hardware.length; i++) {
+ // Add new item
+ item = hwContainer.addItem(itemId);
+ // Add name property for item
+ item.getItemProperty("name").setValue(hardware[i][0]);
+ // Allow children
+ hwContainer.setChildrenAllowed(itemId, true);
+ itemId++;
+ for (int j = 1; j < hardware[i].length; j++) {
+ if (j == 1) {
+ item.getItemProperty("icon").setValue(
+ new ThemeResource("../runo/icons/16/folder.png"));
+ }
+
+ // Add child items
+ item = hwContainer.addItem(itemId);
+ item.getItemProperty("name").setValue(hardware[i][j]);
+ hwContainer.setParent(itemId, itemId - j);
+
+ hwContainer.setChildrenAllowed(itemId, false);
+ if (j == 2) {
+ hwContainer.setChildrenAllowed(itemId, true);
+ }
+
+ itemId++;
+ }
+ }
+ return hwContainer;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Sample Tree for testing WAI-ARIA functionality";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 0;
+ }
+
+ @Override
+ public Action[] getActions(Object target, Object sender) {
+ return ACTIONS;
+ }
+
+ @Override
+ public void handleAction(Action action, Object sender, Object target) {
+ System.out.println("Action: " + action.getCaption());
+ }
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/tree/TreeItemClickAndValueChange.html b/uitest/src/com/vaadin/tests/components/tree/TreeItemClickAndValueChange.html
index bf83a1acdb..83508c9478 100644
--- a/uitest/src/com/vaadin/tests/components/tree/TreeItemClickAndValueChange.html
+++ b/uitest/src/com/vaadin/tests/components/tree/TreeItemClickAndValueChange.html
@@ -64,7 +64,7 @@
<tr>
<td>assertText</td>
<td>vaadin=runTrees::PID_SLog_row_1</td>
- <td>4. left click on source: [Item 1], client: [*];, relative: [-1,-1], itemId: Item 2, propertyId: null</td>
+ <td>4. left click on source: com.vaadin.ui.Tree@*, client: [*];, relative: [-1,-1], itemId: Item 2, propertyId: null</td>
</tr>
<tr>
<td>assertText</td>
@@ -74,9 +74,8 @@
<tr>
<td>assertText</td>
<td>vaadin=runTrees::PID_SLog_row_3</td>
- <td>2. left click on source: [], client: [*];, relative: [-1,-1], itemId: Item 1, propertyId: null</td>
+ <td>2. left click on source: com.vaadin.ui.Tree@*, client: [*];, relative: [-1,-1], itemId: Item 1, propertyId: null</td>
</tr>
-
</tbody></table>
</body>
</html>
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableCacheOnPartialUpdates.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableCacheOnPartialUpdates.java
index f792a32f8f..85a69702a4 100644
--- a/uitest/src/com/vaadin/tests/components/treetable/TreeTableCacheOnPartialUpdates.java
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableCacheOnPartialUpdates.java
@@ -90,6 +90,7 @@ public class TreeTableCacheOnPartialUpdates extends TestBase {
}
public class Col4ColumnGenerator implements ColumnGenerator {
+ @Override
public Component generateCell(final com.vaadin.ui.Table source,
final Object itemId, Object columnId) {
TestBean tb = (TestBean) itemId;
@@ -98,6 +99,7 @@ public class TreeTableCacheOnPartialUpdates extends TestBase {
btnCol4.setId("cacheTestButtonToggle-" + tb.getCol1() + "-"
+ tb.getCol2());
btnCol4.addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
treeTable.setCollapsed(itemId,
!treeTable.isCollapsed(itemId));
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbar.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbar.java
index 4af0da158d..79c967914f 100644
--- a/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbar.java
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbar.java
@@ -49,6 +49,7 @@ public class TreeTableExtraScrollbar extends TestBase {
button.setId("button");
button.addClickListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.addItem(new TestObject("name 6-1", "value 6-1"));
table.addItem(new TestObject("name 6-2", "value 6-2"));
@@ -68,12 +69,14 @@ public class TreeTableExtraScrollbar extends TestBase {
}
private class EmptyColumnGenerator implements Table.ColumnGenerator {
+ @Override
public Object generateCell(Table table, Object itemId, Object columnId) {
return null;
}
}
private class TypeColumnGenerator implements Table.ColumnGenerator {
+ @Override
public Object generateCell(Table table, Object itemId, Object columnId) {
if (itemId instanceof TestObject) {
return new Label(((TestObject) itemId).getValue());
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java
index cad33e242f..0dc98b2c2e 100644
--- a/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableExtraScrollbarWithChildren.java
@@ -62,6 +62,7 @@ public class TreeTableExtraScrollbarWithChildren extends TestBase {
button.setId("button");
button.addClickListener(new ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
table.setCollapsed(parent, !table.isCollapsed(parent));
Notification.show("collapsed: " + table.isCollapsed(parent));
@@ -73,6 +74,7 @@ public class TreeTableExtraScrollbarWithChildren extends TestBase {
}
private class HierarchyColumnGenerator implements Table.ColumnGenerator {
+ @Override
public Object generateCell(Table table, Object itemId, Object columnId) {
Label label = new Label("this should be mostly hidden");
label.setSizeUndefined();
@@ -81,6 +83,7 @@ public class TreeTableExtraScrollbarWithChildren extends TestBase {
}
private class TypeColumnGenerator implements Table.ColumnGenerator {
+ @Override
public Object generateCell(Table table, Object itemId, Object columnId) {
if (itemId instanceof TestObject) {
return new Label(((TestObject) itemId).getValue());
diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableInternalError.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableInternalError.java
index f6d7f11eb7..1b510f1ac5 100644
--- a/uitest/src/com/vaadin/tests/components/treetable/TreeTableInternalError.java
+++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableInternalError.java
@@ -30,6 +30,7 @@ public class TreeTableInternalError extends TestBase {
Button button = new Button("Resize") {
{
addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
t.setHeight("300px");
}
@@ -64,12 +65,14 @@ public class TreeTableInternalError extends TestBase {
}
public class ButtonColumnGenerator implements ColumnGenerator {
+ @Override
public Component generateCell(final com.vaadin.ui.Table source,
final Object itemId, Object columnId) {
String identifier = "Expand/Collapse";
Button btnCol = new NativeButton(identifier);
btnCol.setId("cacheTestButtonToggle-" + itemId);
btnCol.addClickListener(new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
t.setCollapsed(itemId, !t.isCollapsed(itemId));
}
diff --git a/uitest/src/com/vaadin/tests/components/ui/LoadingIndicatorConfigurationTest.java b/uitest/src/com/vaadin/tests/components/ui/LoadingIndicatorConfigurationTest.java
new file mode 100644
index 0000000000..3c857a8753
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/LoadingIndicatorConfigurationTest.java
@@ -0,0 +1,96 @@
+package com.vaadin.tests.components.ui;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.TextField;
+
+public class LoadingIndicatorConfigurationTest extends AbstractTestUIWithLog {
+
+ private TextField firstDelay;
+ private TextField secondDelay;
+ private TextField thirdDelay;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final TextField delayField = new TextField("Delay (ms)");
+ delayField.setConverter(Integer.class);
+ delayField.setConvertedValue(1000);
+
+ NativeButton delayButton = new NativeButton("Wait");
+ delayButton.addClickListener(new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ try {
+ Thread.sleep((Integer) delayField.getConvertedValue());
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ firstDelay = createIntegerTextField("First delay (ms)",
+ getState().loadingIndicatorConfiguration.firstDelay);
+ firstDelay.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getLoadingIndicatorConfiguration().setFirstDelay(
+ (Integer) firstDelay.getConvertedValue());
+ }
+ });
+ secondDelay = createIntegerTextField("Second delay (ms)",
+ getState().loadingIndicatorConfiguration.secondDelay);
+ secondDelay.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getLoadingIndicatorConfiguration().setSecondDelay(
+ (Integer) secondDelay.getConvertedValue());
+ }
+ });
+ thirdDelay = createIntegerTextField("Third delay (ms)",
+ getState().loadingIndicatorConfiguration.thirdDelay);
+ thirdDelay.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getLoadingIndicatorConfiguration().setThirdDelay(
+ (Integer) thirdDelay.getConvertedValue());
+ }
+ });
+
+ getLayout().addComponents(firstDelay, secondDelay, thirdDelay);
+
+ HorizontalLayout hl = new HorizontalLayout();
+ hl.setMargin(true);
+ hl.setDefaultComponentAlignment(Alignment.BOTTOM_RIGHT);
+ hl.addComponents(delayField, delayButton);
+ addComponent(hl);
+
+ }
+
+ private TextField createIntegerTextField(String caption, int initialValue) {
+ TextField tf = new TextField(caption);
+ tf.setId(caption);
+ tf.setConverter(Integer.class);
+ tf.setImmediate(true);
+ tf.setConvertedValue(initialValue);
+ return tf;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests that loading indicator delay can be configured";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 7448;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html b/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html
new file mode 100644
index 0000000000..e41cf5e176
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.html
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.ui.TooltipConfiguration?restartApplication</td>
+ <td></td>
+</tr>
+<!--Short close delay-->
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SClose timeout</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SshortTooltip</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td>This is a short tooltip</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementNotPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<!--Long close delay-->
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SClose timeout</td>
+ <td>3000</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SshortTooltip</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td>This is a short tooltip</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SClose timeout</td>
+ <td>60,9</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SClose timeout</td>
+ <td>0</td>
+</tr>
+<!--Max width 500-->
+<tr>
+ <td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SlongTooltip</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementWidth</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td>500</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td></td>
+</tr>
+<!--Max width 100-->
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SMax width</td>
+ <td>100</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>mouseMoveAt</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::PID_SlongTooltip</td>
+ <td>0,0</td>
+</tr>
+<tr>
+ <td>waitForElementPresent</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertElementWidth</td>
+ <td>vaadin=runcomvaadintestscomponentsuiTooltipConfiguration::Root/VTooltip[0]/FlowPanel[0]/domChild[1]</td>
+ <td>100</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.java b/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.java
new file mode 100644
index 0000000000..4d201d2a1a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/TooltipConfiguration.java
@@ -0,0 +1,107 @@
+package com.vaadin.tests.components.ui;
+
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.tests.util.LoremIpsum;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.TextField;
+
+public class TooltipConfiguration extends AbstractTestUIWithLog {
+
+ private TextField closeTimeout;
+ private TextField quickOpenTimeout;
+ private TextField maxWidth;
+ private TextField openDelay;
+ private TextField quickOpenDelay;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ NativeButton componentWithShortTooltip = new NativeButton(
+ "Short tooltip");
+ componentWithShortTooltip.setDescription("This is a short tooltip");
+ componentWithShortTooltip.setId("shortTooltip");
+
+ NativeButton componentWithLongTooltip = new NativeButton("Long tooltip");
+ componentWithLongTooltip.setId("longTooltip");
+ componentWithLongTooltip.setDescription(LoremIpsum.get(5000));
+
+ closeTimeout = createIntegerTextField("Close timeout",
+ getState().tooltipConfiguration.closeTimeout);
+ closeTimeout.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getTooltipConfiguration().setCloseTimeout(
+ (Integer) closeTimeout.getConvertedValue());
+ }
+ });
+ maxWidth = createIntegerTextField("Max width",
+ getState().tooltipConfiguration.maxWidth);
+ maxWidth.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getTooltipConfiguration().setMaxWidth(
+ (Integer) maxWidth.getConvertedValue());
+ }
+ });
+ openDelay = createIntegerTextField("Open delay",
+ getState().tooltipConfiguration.openDelay);
+ openDelay.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getTooltipConfiguration().setOpenDelay(
+ (Integer) openDelay.getConvertedValue());
+ }
+ });
+
+ quickOpenDelay = createIntegerTextField("Quick open delay",
+ getState().tooltipConfiguration.quickOpenDelay);
+ quickOpenDelay
+ .addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getTooltipConfiguration().setQuickOpenDelay(
+ (Integer) quickOpenDelay.getConvertedValue());
+ }
+ });
+
+ quickOpenTimeout = createIntegerTextField("Quick open timeout",
+ getState().tooltipConfiguration.quickOpenTimeout);
+ quickOpenTimeout
+ .addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ getTooltipConfiguration().setQuickOpenTimeout(
+ (Integer) quickOpenTimeout.getConvertedValue());
+ }
+ });
+
+ getLayout().addComponents(closeTimeout, openDelay, quickOpenDelay,
+ quickOpenTimeout, maxWidth);
+
+ getLayout().addComponents(componentWithShortTooltip,
+ componentWithLongTooltip);
+
+ }
+
+ private TextField createIntegerTextField(String caption, int initialValue) {
+ TextField tf = new TextField(caption);
+ tf.setId(caption);
+ tf.setConverter(Integer.class);
+ tf.setImmediate(true);
+ tf.setConvertedValue(initialValue);
+ return tf;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests that tooltip delays can be configured";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8065;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/ui/UIInitException.html b/uitest/src/com/vaadin/tests/components/ui/UIInitException.html
index c2b1b33059..68b11e7942 100644
--- a/uitest/src/com/vaadin/tests/components/ui/UIInitException.html
+++ b/uitest/src/com/vaadin/tests/components/ui/UIInitException.html
@@ -17,9 +17,9 @@
<td></td>
</tr>
<tr>
- <td>assertText</td>
- <td>//html/body/div/pre</td>
+ <td>assertTextPresent</td>
<td>Catch me if you can</td>
+ <td></td>
</tr>
</tbody></table>
</body>
diff --git a/uitest/src/com/vaadin/tests/components/ui/UIPolling.html b/uitest/src/com/vaadin/tests/components/ui/UIPolling.html
new file mode 100644
index 0000000000..f770bae009
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/UIPolling.html
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/run/" />
+<title>WindowMaximizeRestoreTest</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">WindowMaximizeRestoreTest</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/UIPolling?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runUIPolling::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VTextField[0]</td>
+ <td>500</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<!--Ensure polling has taken place-->
+<tr>
+ <td>assertTextPresent</td>
+ <td>2. 1000ms has passed</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runUIPolling::/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot[0]/VTextField[0]</td>
+ <td>-1</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<!--Ensure polling has stopped-->
+<tr>
+ <td>assertTextNotPresent</td>
+ <td>8. 4000ms has passed</td>
+ <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/ui/UIPolling.java b/uitest/src/com/vaadin/tests/components/ui/UIPolling.java
new file mode 100644
index 0000000000..48671191ca
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/UIPolling.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.components.ui;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.data.util.MethodProperty;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.TextField;
+
+public class UIPolling extends AbstractTestUIWithLog {
+
+ protected static final long SLEEP_TIME = 500;
+
+ private class BackgroundLogger extends Thread {
+
+ @Override
+ public void run() {
+ int i = 0;
+ while (true) {
+ i++;
+ try {
+ Thread.sleep(SLEEP_TIME);
+ } catch (InterruptedException e) {
+ }
+ final int iteration = i;
+ access(new Runnable() {
+ @Override
+ public void run() {
+ log.log((iteration * SLEEP_TIME) + "ms has passed");
+ }
+ });
+ }
+ }
+ }
+
+ private BackgroundLogger logger = null;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ log = new Log(20);
+ log.setNumberLogRows(true);
+ TextField pollingInterval = new TextField("Poll interval",
+ new MethodProperty<Integer>(this, "pollInterval"));
+ pollingInterval.setImmediate(true);
+ pollingInterval.setValue("-1");
+ pollingInterval.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ if (logger != null) {
+ logger.stop();
+ logger = null;
+ }
+ if (getPollInterval() >= 0) {
+ logger = new BackgroundLogger();
+ logger.start();
+ }
+ }
+ });
+ addComponent(pollingInterval);
+
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests the polling feature of UI. Set the polling interval using the text field. Enabling polling will at the same time start a background thread which logs every 500ms";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 11495;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/ui/UISerialization.java b/uitest/src/com/vaadin/tests/components/ui/UISerialization.java
index 5f3d8d97de..90021a0bf4 100644
--- a/uitest/src/com/vaadin/tests/components/ui/UISerialization.java
+++ b/uitest/src/com/vaadin/tests/components/ui/UISerialization.java
@@ -20,15 +20,19 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.PrintWriter;
import java.io.Serializable;
+import java.io.StringWriter;
import java.util.Date;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.label.ContentMode;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.tests.util.Log;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Label;
public class UISerialization extends AbstractTestUI {
@@ -42,21 +46,29 @@ public class UISerialization extends AbstractTestUI {
@Override
public void buttonClick(ClickEvent event) {
Date d = new Date();
- byte[] result = serialize(UISerialization.this);
- long elapsed = new Date().getTime() - d.getTime();
- log.log("Serialized UI in " + elapsed + "ms into "
- + result.length + " bytes");
- Object diffStateBefore = getConnectorTracker().getDiffState(
- UISerialization.this);
- UISerialization app = (UISerialization) deserialize(result);
- log.log("Deserialized UI in " + elapsed + "ms");
- Object diffStateAfter = getConnectorTracker().getDiffState(
- UISerialization.this);
- if (diffStateBefore.equals(diffStateAfter)) {
- log.log("Diff states match, size: "
- + diffStateBefore.toString().length());
- } else {
- log.log("Diff states do not match");
+ try {
+ byte[] result = serialize(UISerialization.this);
+ long elapsed = new Date().getTime() - d.getTime();
+ log.log("Serialized UI in " + elapsed + "ms into "
+ + result.length + " bytes");
+ Object diffStateBefore = getConnectorTracker()
+ .getDiffState(UISerialization.this);
+ UISerialization app = (UISerialization) deserialize(result);
+ log.log("Deserialized UI in " + elapsed + "ms");
+ Object diffStateAfter = getConnectorTracker().getDiffState(
+ UISerialization.this);
+ if (diffStateBefore.equals(diffStateAfter)) {
+ log.log("Diff states match, size: "
+ + diffStateBefore.toString().length());
+ } else {
+ log.log("Diff states do not match");
+ }
+ } catch (Exception e) {
+ log.log("Exception caught: " + e.getMessage());
+ StringWriter sw = new StringWriter();
+ e.printStackTrace(new PrintWriter(sw));
+ addComponent(new Label(sw.toString(),
+ ContentMode.PREFORMATTED));
}
}
@@ -64,20 +76,16 @@ public class UISerialization extends AbstractTestUI {
}
protected void serializeInstance(Class<?> cls)
- throws InstantiationException, IllegalAccessException {
+ throws InstantiationException, IllegalAccessException, IOException {
serialize((Serializable) cls.newInstance());
}
- protected byte[] serialize(Serializable serializable) {
+ protected byte[] serialize(Serializable serializable) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
ObjectOutputStream oos;
- try {
- oos = new ObjectOutputStream(os);
- oos.writeObject(serializable);
- return os.toByteArray();
- } catch (IOException e) {
- throw new RuntimeException("Serialization failed", e);
- }
+ oos = new ObjectOutputStream(os);
+ oos.writeObject(serializable);
+ return os.toByteArray();
}
protected Object deserialize(byte[] result) {
diff --git a/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java b/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java
index d5bac0d509..7e7a084eed 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java
+++ b/uitest/src/com/vaadin/tests/components/uitest/BackButtonTest.java
@@ -57,6 +57,7 @@ public class BackButtonTest extends AbstractTestUI {
addComponent(l);
Button b = new Button("Go to Page 2", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
l.setCaption("Data from Page 1 : " + value);
getPage().setUriFragment("page2");
@@ -85,6 +86,7 @@ public class BackButtonTest extends AbstractTestUI {
addComponent(f);
f.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
value = f.getValue();
p1.l.setCaption("Data from Page 2 : " + value);
@@ -92,6 +94,7 @@ public class BackButtonTest extends AbstractTestUI {
});
Button b = new Button("Go Back", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
getPage().setUriFragment("page1");
}
diff --git a/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html
index 0308a09a16..614ae7bcda 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/base_theme_test.html
@@ -289,7 +289,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,8</td>
</tr>
<tr>
@@ -304,7 +304,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>11,6</td>
</tr>
<tr>
@@ -319,7 +319,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>8,5</td>
</tr>
<tr>
@@ -334,7 +334,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,6</td>
</tr>
<tr>
@@ -349,7 +349,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>10,7</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html
index fb00029d8f..7d9ffc65b8 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/chameleon_theme_test.html
@@ -289,7 +289,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,8</td>
</tr>
<tr>
@@ -304,7 +304,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>11,6</td>
</tr>
<tr>
@@ -319,7 +319,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>8,5</td>
</tr>
<tr>
@@ -334,7 +334,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,6</td>
</tr>
<tr>
@@ -349,7 +349,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>10,7</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html
index 193c648916..d0ee96c7ef 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/liferay_theme_test.html
@@ -289,7 +289,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,8</td>
</tr>
<tr>
@@ -304,7 +304,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>11,6</td>
</tr>
<tr>
@@ -319,7 +319,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>8,5</td>
</tr>
<tr>
@@ -334,7 +334,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,6</td>
</tr>
<tr>
@@ -349,7 +349,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>10,7</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html
index b1340831bc..a330f5bf61 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/reindeer_theme_test.html
@@ -289,7 +289,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,8</td>
</tr>
<tr>
@@ -304,7 +304,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>11,6</td>
</tr>
<tr>
@@ -319,7 +319,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>8,5</td>
</tr>
<tr>
@@ -334,7 +334,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,6</td>
</tr>
<tr>
@@ -349,7 +349,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>10,7</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html b/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html
index fadc503abd..61ba58a0e6 100644
--- a/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html
+++ b/uitest/src/com/vaadin/tests/components/uitest/runo_theme_test.html
@@ -289,7 +289,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,8</td>
</tr>
<tr>
@@ -304,7 +304,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>11,6</td>
</tr>
<tr>
@@ -319,7 +319,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>8,5</td>
</tr>
<tr>
@@ -334,7 +334,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>9,6</td>
</tr>
<tr>
@@ -349,7 +349,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runThemeTestUI::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>10,7</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/upload/TestFileUploadSize.java b/uitest/src/com/vaadin/tests/components/upload/TestFileUploadSize.java
index 32f5c93bfd..178f8f9393 100644
--- a/uitest/src/com/vaadin/tests/components/upload/TestFileUploadSize.java
+++ b/uitest/src/com/vaadin/tests/components/upload/TestFileUploadSize.java
@@ -28,6 +28,7 @@ public class TestFileUploadSize extends TestBase implements Receiver {
Upload u = new Upload("Upload", new Upload.Receiver() {
+ @Override
public OutputStream receiveUpload(String filename, String mimeType) {
return baos;
}
@@ -35,12 +36,14 @@ public class TestFileUploadSize extends TestBase implements Receiver {
u.setId("UPL");
u.addStartedListener(new Upload.StartedListener() {
+ @Override
public void uploadStarted(StartedEvent event) {
expectedSize.setValue(String.valueOf(event.getContentLength()));
}
});
u.addFinishedListener(new Upload.FinishedListener() {
+ @Override
public void uploadFinished(FinishedEvent event) {
label.setValue("Upload finished. Name: " + event.getFilename());
receivedSize.setValue(String.valueOf(baos.size()));
@@ -62,6 +65,7 @@ public class TestFileUploadSize extends TestBase implements Receiver {
addComponent(u);
}
+ @Override
public OutputStream receiveUpload(String filename, String MIMEType) {
Notification.show("Receiving upload");
return new ByteArrayOutputStream();
diff --git a/uitest/src/com/vaadin/tests/components/window/CenteredWindowWithUndefinedSize.java b/uitest/src/com/vaadin/tests/components/window/CenteredWindowWithUndefinedSize.java
index efe7eb20bf..42fab79376 100644
--- a/uitest/src/com/vaadin/tests/components/window/CenteredWindowWithUndefinedSize.java
+++ b/uitest/src/com/vaadin/tests/components/window/CenteredWindowWithUndefinedSize.java
@@ -9,7 +9,7 @@ public class CenteredWindowWithUndefinedSize extends TestBase {
@Override
protected String getDescription() {
- return "The centered sub-window with undefined height and a 100% high layout should be rendered in the center of the screen and not in the top-left corner.";
+ return "The centered sub-window with undefined height and a undefined high layout should be rendered in the center of the screen and not in the top-left corner.";
}
@Override
@@ -23,7 +23,7 @@ public class CenteredWindowWithUndefinedSize extends TestBase {
layout.setMargin(true);
Window centered = new Window("A window", layout);
centered.setSizeUndefined();
- layout.setSizeFull();
+ layout.setSizeUndefined();
centered.center();
Label l = new Label("This window should be centered");
diff --git a/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.html b/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.html
index 6e3eb906b7..ac81dfdefb 100644
--- a/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.html
+++ b/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.html
@@ -17,11 +17,6 @@
<td></td>
</tr>
<tr>
- <td>waitForVaadin</td>
- <td></td>
- <td></td>
-</tr>
-<tr>
<td>click</td>
<td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::PID_Sopensub/domChild[0]/domChild[0]</td>
<td></td>
@@ -45,7 +40,7 @@
<!--Click close in title bar-->
<tr>
<td>click</td>
- <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runcomvaadintestscomponentswindowCloseSubWindow::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td></td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.java b/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.java
index e2a59b6005..6aad3e9170 100644
--- a/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.java
+++ b/uitest/src/com/vaadin/tests/components/window/CloseSubWindow.java
@@ -33,7 +33,7 @@ public class CloseSubWindow extends TestBase {
private Window createClosableSubWindow(final String title) {
VerticalLayout layout = new VerticalLayout();
layout.setMargin(true);
- layout.setSizeFull();
+ layout.setSizeUndefined();
final Window window = new Window(title, layout);
window.setSizeUndefined();
window.setClosable(true);
diff --git a/uitest/src/com/vaadin/tests/components/window/LegacyWindowOpenTest.java b/uitest/src/com/vaadin/tests/components/window/LegacyWindowOpenTest.java
index 175c3f6d8a..ad36e04d88 100644
--- a/uitest/src/com/vaadin/tests/components/window/LegacyWindowOpenTest.java
+++ b/uitest/src/com/vaadin/tests/components/window/LegacyWindowOpenTest.java
@@ -19,6 +19,7 @@ public class LegacyWindowOpenTest extends TestBase {
addComponent(new Button("Window.open _blank always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
win.open(r, "_blank", true);
}
@@ -26,6 +27,7 @@ public class LegacyWindowOpenTest extends TestBase {
addComponent(new Button("Window.open _blank NOT always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
win.open(r, "_blank", false);
}
@@ -33,6 +35,7 @@ public class LegacyWindowOpenTest extends TestBase {
addComponent(new Button("Window.open _new always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
win.open(r, "_new", true);
}
@@ -40,6 +43,7 @@ public class LegacyWindowOpenTest extends TestBase {
addComponent(new Button("Window.open _new NOT always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
win.open(r, "_new", false);
}
@@ -47,6 +51,7 @@ public class LegacyWindowOpenTest extends TestBase {
addComponent(new Button(
"Window execute Javascript window.open(www.google.com, _blank)",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
win.executeJavaScript("window.open(\"http://www.google.com\", \"_blank\");");
}
@@ -54,6 +59,7 @@ public class LegacyWindowOpenTest extends TestBase {
addComponent(new Button(
"Window execute Javascript window.open(www.google.com, _blank, resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes)",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
win.executeJavaScript("window.open(\"http://www.google.com\", \"_blank\", \"resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes\");");
}
diff --git a/uitest/src/com/vaadin/tests/components/window/PageOpenTest.java b/uitest/src/com/vaadin/tests/components/window/PageOpenTest.java
index 2dbc24cb66..a566b09cdc 100644
--- a/uitest/src/com/vaadin/tests/components/window/PageOpenTest.java
+++ b/uitest/src/com/vaadin/tests/components/window/PageOpenTest.java
@@ -20,6 +20,7 @@ public class PageOpenTest extends AbstractTestUI {
addComponent(new Button("Page.open _blank always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
page.open(url, "_blank", true);
}
@@ -27,6 +28,7 @@ public class PageOpenTest extends AbstractTestUI {
addComponent(new Button("Page.open _blank NOT always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
page.open(url, "_blank", false);
}
@@ -34,6 +36,7 @@ public class PageOpenTest extends AbstractTestUI {
addComponent(new Button("Page.open _new always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
page.open(url, "_new", true);
}
@@ -41,6 +44,7 @@ public class PageOpenTest extends AbstractTestUI {
addComponent(new Button("Page.open _new NOT always as popup",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
page.open(url, "_new", false);
}
@@ -48,6 +52,7 @@ public class PageOpenTest extends AbstractTestUI {
addComponent(new Button(
"Execute Javascript window.open(www.google.com, _blank)",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
JavaScript
.getCurrent()
@@ -58,6 +63,7 @@ public class PageOpenTest extends AbstractTestUI {
addComponent(new Button(
"Execute Javascript window.open(www.google.com, _blank, resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes)",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
JavaScript
.getCurrent()
diff --git a/uitest/src/com/vaadin/tests/components/window/SubWindowOrder.html b/uitest/src/com/vaadin/tests/components/window/SubWindowOrder.html
index 0476de6c35..8374a90b52 100644
--- a/uitest/src/com/vaadin/tests/components/window/SubWindowOrder.html
+++ b/uitest/src/com/vaadin/tests/components/window/SubWindowOrder.html
@@ -90,7 +90,7 @@
<!--Close window 4, which is the topmost window-->
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[3]/domChild[0]/domChild[0]/domChild[2]</td>
<td>11,15</td>
</tr>
<tr>
@@ -101,7 +101,7 @@
<!--Close Dialog 3 (topmost)-->
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[2]</td>
<td>6,8</td>
</tr>
<!--Make Dialog 5 (topmost) non-modal-->
@@ -139,7 +139,7 @@
<!--Close dialog 5-->
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runcomvaadintestscomponentswindowSubWindowOrder::/VWindow[2]/domChild[0]/domChild[0]/domChild[2]</td>
<td>10,5</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html b/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html
new file mode 100644
index 0000000000..945564f298
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.html
@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/run/" />
+<title>WindowMaximizeRestoreTest</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">WindowMaximizeRestoreTest</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.components.window.WindowMaximizeRestoreTest?restartApplication</td>
+ <td></td>
+</tr>
+<!--Test maximize-restore button-->
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-maximizebox</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>Window 1</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>7,8</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-restorebox</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>9,7</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-maximizebox</td>
+</tr>
+<!--test double click on header-->
+<tr>
+ <td>doubleClickAt</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-restorebox</td>
+</tr>
+<tr>
+ <td>doubleClickAt</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-maximizebox</td>
+</tr>
+<!--Resizable = false should hide max-restore button-->
+<tr>
+ <td>assertVisible</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td>
+ <td>8,3</td>
+</tr>
+<tr>
+ <td>assertNotVisible</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td></td>
+</tr>
+<!--Test server side max-restore-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0]</td>
+ <td>34,6</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-restorebox</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0]</td>
+ <td>34,6</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-maximizebox</td>
+</tr>
+<!--test double click on header doesn't work-->
+<tr>
+ <td>doubleClickAt</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-maximizebox</td>
+</tr>
+<tr>
+ <td>doubleClickAt</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>v-window-maximizebox</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td>
+ <td>8,3</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[4]/VNativeButton[0]</td>
+ <td>26,9</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--test two windows with screen shot-->
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-2-original-pos-window-1-centered</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>10,8</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-1-maximized-on-top-of-window-2</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0]</td>
+ <td>43,12</td>
+</tr>
+<!--Remove the following two commands once #11737 is fixed-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0]</td>
+ <td>43,12</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[0]/VNativeButton[0]</td>
+ <td>43,12</td>
+</tr>
+<!--maximize window 2 content-->
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[1]/FocusableScrollPanel[0]/VVerticalLayout[0]/Slot[3]/VNativeButton[0]</td>
+ <td>100,9</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-2-original-pos-window-1-centered-again</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[1]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>6,11</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-2-maximized-on-top-of-window-1</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[1]/domChild[0]/domChild[0]/domChild[2]</td>
+ <td>7,5</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-2-closed-window-1-centered</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VFilterSelect[0]/domChild[1]</td>
+ <td>1,17</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>//div[@id='VAADIN_COMBOBOX_OPTIONLIST']/div/div[2]/table/tbody/tr[2]/td</td>
+ <td>122,6</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-2-added-maximized-on-top-of-window-1</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[1]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>6,11</td>
+</tr>
+<tr>
+ <td>doubleClickAt</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowMaximizeRestoreTest::/VWindow[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td>
+ <td>113,10</td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>window-1-maximized-with-doubleclick</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.java b/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.java
new file mode 100644
index 0000000000..a8102a7d1a
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/WindowMaximizeRestoreTest.java
@@ -0,0 +1,165 @@
+package com.vaadin.tests.components.window;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.window.WindowMode;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.ComponentContainer;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Window.CloseEvent;
+import com.vaadin.ui.Window.CloseListener;
+import com.vaadin.ui.Window.WindowModeChangeEvent;
+import com.vaadin.ui.Window.WindowModeChangeListener;
+
+public class WindowMaximizeRestoreTest extends AbstractTestUI {
+ Button.ClickListener addListener = new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ addWindow(createNewWindow());
+ }
+ };
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button addButton = new Button("Add new Window");
+ addButton.addListener(addListener);
+ addComponent(addButton);
+
+ addWindowAgain = new ComboBox("Add Window Again");
+ addWindowAgain.setBuffered(false);
+ addWindowAgain.setImmediate(true);
+ addWindowAgain.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+
+ Object value = event.getProperty().getValue();
+ if (value != null && value instanceof Window) {
+ UI.getCurrent().addWindow((Window) value);
+ addWindowAgain.removeItem(value);
+ }
+ }
+ });
+ addComponent(addWindowAgain);
+
+ addWindow(createNewWindow());
+ }
+
+ private int windowCount = 0;
+ private ComboBox addWindowAgain;
+
+ private Window createNewWindow() {
+ final Window w = new Window("Window " + (++windowCount));
+ final VerticalLayout content = new VerticalLayout();
+ w.setContent(content);
+ w.setData(windowCount);
+ w.setWidth("200px");
+ w.setHeight("300px");
+ w.setPositionX(200);
+ w.setPositionY(200);
+ final NativeButton maximize = new NativeButton("Maximize");
+ Button.ClickListener listener = new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ if (w.getWindowMode() == WindowMode.MAXIMIZED) {
+ w.setWindowMode(WindowMode.NORMAL);
+ maximize.setCaption("Maximize");
+ } else {
+ w.setWindowMode(WindowMode.MAXIMIZED);
+ maximize.setCaption("Restore");
+ }
+ }
+
+ };
+ maximize.addClickListener(listener);
+ ((ComponentContainer) w.getContent()).addComponent(maximize);
+
+ w.addWindowModeChangeListener(new WindowModeChangeListener() {
+
+ @Override
+ public void windowModeChanged(WindowModeChangeEvent event) {
+ WindowMode state = (event.getWindow().getWindowMode());
+ if (state == WindowMode.NORMAL) {
+ w.setCaption("Window " + w.getData() + " Normal");
+ maximize.setCaption("Maximize");
+ } else if (state == WindowMode.MAXIMIZED) {
+ w.setCaption("Window " + w.getData() + " Maximized");
+ maximize.setCaption("Restore");
+ }
+ }
+ });
+ final CheckBox resizeable = new CheckBox("Resizeable");
+ resizeable.setValue(w.isResizable());
+ resizeable.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ w.setResizable(resizeable.getValue());
+ }
+ });
+ ((ComponentContainer) w.getContent()).addComponent(resizeable);
+ final CheckBox closeable = new CheckBox("Closeable");
+ closeable.setValue(w.isClosable());
+ closeable.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ w.setClosable(closeable.getValue());
+ }
+ });
+ ((ComponentContainer) w.getContent()).addComponent(closeable);
+ NativeButton contentFull = new NativeButton("Set Content Size Full",
+ new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ w.getContent().setSizeFull();
+ }
+ });
+ contentFull.setWidth("100%");
+ ((ComponentContainer) w.getContent()).addComponent(contentFull);
+
+ NativeButton center = new NativeButton("Center");
+ center.addClickListener(new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ w.center();
+ }
+ });
+ ((ComponentContainer) w.getContent()).addComponent(center);
+
+ w.addCloseListener(new CloseListener() {
+
+ @Override
+ public void windowClose(CloseEvent e) {
+ Item item = addWindowAgain.addItem(w);
+ addWindowAgain.setItemCaption(w, "Window "
+ + w.getData().toString());
+ }
+ });
+
+ return w;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 3400;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests the default maximize & restore funtionality. Max. makes window 100%*100% and pos(0, 0), and restore returns it to the values that are set in windows state.";
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/WindowWithInvalidCloseListener.html b/uitest/src/com/vaadin/tests/components/window/WindowWithInvalidCloseListener.html
index 923276b613..fa63e5e1e6 100644
--- a/uitest/src/com/vaadin/tests/components/window/WindowWithInvalidCloseListener.html
+++ b/uitest/src/com/vaadin/tests/components/window/WindowWithInvalidCloseListener.html
@@ -18,7 +18,7 @@
</tr>
<tr>
<td>mouseClick</td>
- <td>vaadin=runcomvaadintestscomponentswindowWindowWithInvalidCloseListener::/VWindow[0]/domChild[0]/domChild[0]/domChild[1]</td>
+ <td>vaadin=runcomvaadintestscomponentswindowWindowWithInvalidCloseListener::/VWindow[0]/domChild[0]/domChild[0]/domChild[2]</td>
<td>6,7</td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/containers/sqlcontainer/TableQueryWithNonUniqueFirstPrimaryKey.java b/uitest/src/com/vaadin/tests/containers/sqlcontainer/TableQueryWithNonUniqueFirstPrimaryKey.java
index fa84c7cbb8..da3476610b 100644
--- a/uitest/src/com/vaadin/tests/containers/sqlcontainer/TableQueryWithNonUniqueFirstPrimaryKey.java
+++ b/uitest/src/com/vaadin/tests/containers/sqlcontainer/TableQueryWithNonUniqueFirstPrimaryKey.java
@@ -53,6 +53,7 @@ public class TableQueryWithNonUniqueFirstPrimaryKey extends LegacyApplication {
myCombo.setWidth("100.0%");
myCombo.setHeight("-1px");
myCombo.addValueChangeListener(new Property.ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
if (myCombo.getValue() != null) {
Item item = myCombo.getItem(event.getProperty()
diff --git a/uitest/src/com/vaadin/tests/debug/DebugWindowPresent.html b/uitest/src/com/vaadin/tests/debug/DebugWindowPresent.html
index 11640ef6c3..ff5c731e5c 100644
--- a/uitest/src/com/vaadin/tests/debug/DebugWindowPresent.html
+++ b/uitest/src/com/vaadin/tests/debug/DebugWindowPresent.html
@@ -18,7 +18,7 @@
</tr>
<tr>
<td>assertElementPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -28,7 +28,7 @@
</tr>
<tr>
<td>assertElementPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -38,7 +38,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -48,7 +48,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -58,7 +58,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -68,7 +68,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -78,7 +78,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -88,7 +88,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
<tr>
@@ -98,7 +98,7 @@
</tr>
<tr>
<td>assertElementNotPresent</td>
- <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugConsole[0]</td>
+ <td>vaadin=runcomvaadintestsdebugDebugWindowPresent::Root/VDebugWindow[0]</td>
<td></td>
</tr>
</tbody></table>
diff --git a/uitest/src/com/vaadin/tests/debug/HierarchyAfterAnalyzeLayouts.html b/uitest/src/com/vaadin/tests/debug/HierarchyAfterAnalyzeLayouts.html
index 03d8f34651..a0ebb3bf27 100644
--- a/uitest/src/com/vaadin/tests/debug/HierarchyAfterAnalyzeLayouts.html
+++ b/uitest/src/com/vaadin/tests/debug/HierarchyAfterAnalyzeLayouts.html
@@ -17,14 +17,19 @@
<td></td>
</tr>
<tr>
- <td>mouseClick</td>
- <td>vaadin=runcomvaadintestsdebugHierarchyAfterAnalyzeLayouts::Root/VDebugConsole[0]/FlowPanel[0]/HorizontalPanel[0]/domChild[0]/domChild[0]/domChild[3]/domChild[0]</td>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestsdebugHierarchyAfterAnalyzeLayouts::Root/VDebugWindow[0]/FlowPanel[0]/FlowPanel[0]/FlowPanel[0]/domChild[1]</td>
<td>18,9</td>
</tr>
<tr>
- <td>assertTextPresent</td>
- <td>Layouts analyzed on server, total top level problems: 0</td>
- <td></td>
+ <td>click</td>
+ <td>vaadin=runcomvaadintestsdebugHierarchyAfterAnalyzeLayouts::Root/VDebugWindow[0]/FlowPanel[0]/FlowPanel[0]/FlowPanel[2]/FlowPanel[0]/domChild[2]</td>
+ <td>18,9</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runcomvaadintestsdebugHierarchyAfterAnalyzeLayouts::Root/VDebugWindow[0]/FlowPanel[0]/SimplePanel[0]/FlowPanel[0]/domChild[0]</td>
+ <td>Layouts analyzed, no top level problems</td>
</tr>
<tr>
<td>assertElementPresent</td>
diff --git a/uitest/src/com/vaadin/tests/fieldgroup/DateForm.html b/uitest/src/com/vaadin/tests/fieldgroup/DateForm.html
new file mode 100644
index 0000000000..f141091805
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/fieldgroup/DateForm.html
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.fieldgroup.DateForm?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestsfieldgroupDateForm::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VPopupCalendar[0]#field</td>
+ <td>1/20/84</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestsfieldgroupDateForm::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VPopupCalendar[0]#field</td>
+ <td>1/20/84</td>
+</tr>
+<tr>
+ <td>assertCSSClass</td>
+ <td>vaadin=runcomvaadintestsfieldgroupDateForm::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VDateFieldCalendar[0]/VCalendarPanel[0]#day20</td>
+ <td>v-inline-datefield-calendarpanel-day-selected</td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runcomvaadintestsfieldgroupDateForm::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VTextField[0]</td>
+ <td>Jan 20, 1984 4:34:49 PM</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/fieldgroup/DateForm.java b/uitest/src/com/vaadin/tests/fieldgroup/DateForm.java
new file mode 100644
index 0000000000..3064856db9
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/fieldgroup/DateForm.java
@@ -0,0 +1,152 @@
+package com.vaadin.tests.fieldgroup;
+
+import java.util.Date;
+import java.util.Locale;
+
+import com.vaadin.data.fieldgroup.BeanFieldGroup;
+import com.vaadin.data.fieldgroup.FieldGroup;
+import com.vaadin.data.fieldgroup.FieldGroup.CommitException;
+import com.vaadin.data.fieldgroup.PropertyId;
+import com.vaadin.data.util.BeanItem;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.data.bean.Person;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.InlineDateField;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.PopupDateField;
+import com.vaadin.ui.TextField;
+
+public class DateForm extends TestBase {
+
+ private Log log = new Log(5);
+ @PropertyId("date1")
+ private DateField dateField;
+ @PropertyId("date2")
+ private PopupDateField popupDateField;
+ @PropertyId("date3")
+ private InlineDateField inlineDateField;
+ @PropertyId("date4")
+ private TextField textField;
+
+ public static class DateObject {
+ private Date date1, date2, date3, date4;
+
+ public DateObject(Date date1, Date date2, Date date3, Date date4) {
+ super();
+ this.date1 = date1;
+ this.date2 = date2;
+ this.date3 = date3;
+ this.date4 = date4;
+ }
+
+ public Date getDate1() {
+ return date1;
+ }
+
+ public void setDate1(Date date1) {
+ this.date1 = date1;
+ }
+
+ public Date getDate2() {
+ return date2;
+ }
+
+ public void setDate2(Date date2) {
+ this.date2 = date2;
+ }
+
+ public Date getDate3() {
+ return date3;
+ }
+
+ public void setDate3(Date date3) {
+ this.date3 = date3;
+ }
+
+ public Date getDate4() {
+ return date4;
+ }
+
+ public void setDate4(Date date4) {
+ this.date4 = date4;
+ }
+
+ }
+
+ @Override
+ protected void setup() {
+ getMainWindow().setLocale(Locale.US);
+ addComponent(log);
+ final FieldGroup fieldGroup = new BeanFieldGroup<DateObject>(
+ DateObject.class);
+ fieldGroup.setBuffered(true);
+
+ fieldGroup.buildAndBindMemberFields(this);
+ textField.setWidth("20em");
+ addComponent(dateField);
+ addComponent(popupDateField);
+ addComponent(inlineDateField);
+ addComponent(textField);
+
+ Button commitButton = new Button("Commit", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ String msg = "Commit succesful";
+ try {
+ fieldGroup.commit();
+ } catch (CommitException e) {
+ msg = "Commit failed: " + e.getMessage();
+ }
+ Notification.show(msg);
+ log.log(msg);
+
+ }
+ });
+ Button discardButton = new Button("Discard",
+ new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ fieldGroup.discard();
+ log.log("Discarded changes");
+
+ }
+ });
+ Button showBean = new Button("Show bean values",
+ new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ log.log(getPerson(fieldGroup).toString());
+
+ }
+ });
+ addComponent(commitButton);
+ addComponent(discardButton);
+ addComponent(showBean);
+
+ DateObject d = new DateObject(new Date(443457289789L), new Date(
+ 443457289789L), new Date(443457289789L),
+ new Date(443457289789L));
+ fieldGroup.setItemDataSource(new BeanItem<DateObject>(d));
+ }
+
+ public static Person getPerson(FieldGroup binder) {
+ return ((BeanItem<Person>) binder.getItemDataSource()).getBean();
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Ensure FieldGroupFieldFactory supports Dates";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 8539;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java b/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java
new file mode 100644
index 0000000000..ec323f2db2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/layouts/CaptionsInLayoutsWaiAria.java
@@ -0,0 +1,375 @@
+package com.vaadin.tests.layouts;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.server.ThemeResource;
+import com.vaadin.server.UserError;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractField;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.DateField;
+import com.vaadin.ui.FormLayout;
+import com.vaadin.ui.GridLayout;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.NativeSelect;
+import com.vaadin.ui.OptionGroup;
+import com.vaadin.ui.PasswordField;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+
+public class CaptionsInLayoutsWaiAria extends TestBase {
+
+ private static final Object CAPTION = "CAPTION";
+ private static final Object CLASS = "C";
+ private static final Object WIDTH = "W";
+
+ private NativeSelect layoutSelect;
+ private Layout layout;
+ private VerticalLayout verticalLayout;
+ private HorizontalLayout horizontalLayout;
+ private GridLayout gridLayout;
+ private FormLayout formLayout;
+ private List<AbstractField<?>> components = new ArrayList<AbstractField<?>>();
+ private CssLayout cssLayout;
+ private HorizontalLayout layoutParent = new HorizontalLayout();
+
+ @Override
+ protected void setup() {
+ // setTheme("tests-tickets");
+ addComponent(createLayoutSelect());
+ addComponent(toggleRequired());
+ // addComponent(toggleCaptions());
+ // addComponent(toggleError());
+ addComponent(toggleIcon());
+ addComponent(toggleReadOnly());
+ addComponent(toggleInvalid());
+ addComponent(toggleEnabled());
+ addComponent(addCaptionText());
+ // layoutParent.addComponent(new
+ // NativeButton("Button right of layout"));
+ addComponent(layoutParent);
+ // addComponent(new NativeButton("Button below layout"));
+ createComponents();
+ layoutSelect.setValue(layoutSelect.getItemIds().iterator().next());
+ }
+
+ private Component addCaptionText() {
+ Button b = new Button("Add caption text");
+ b.addListener(new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ prependCaptions("a");
+ }
+ });
+ return b;
+ }
+
+ protected void prependCaptions(String prepend) {
+ for (AbstractField<?> c : components) {
+ c.setCaption(prepend + c.getCaption());
+ }
+
+ }
+
+ private Component toggleRequired() {
+ CheckBox requiredToggle = new CheckBox();
+ requiredToggle.setImmediate(true);
+ requiredToggle.setCaption("Required");
+ requiredToggle.addListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setRequired((Boolean) event.getProperty().getValue());
+ }
+ });
+ return requiredToggle;
+ }
+
+ private Component toggleIcon() {
+ CheckBox iconToggle = new CheckBox();
+ iconToggle.setImmediate(true);
+ iconToggle.setCaption("Icons");
+ iconToggle.addListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setIcon((Boolean) event.getProperty().getValue());
+ }
+ });
+ return iconToggle;
+ }
+
+ private Component toggleReadOnly() {
+ CheckBox readOnlyToggle = new CheckBox();
+ readOnlyToggle.setImmediate(true);
+ readOnlyToggle.setCaption("Read only");
+ readOnlyToggle.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setReadOnly((Boolean) event.getProperty().getValue());
+ }
+ });
+
+ return readOnlyToggle;
+ }
+
+ private Component toggleEnabled() {
+ CheckBox enabledToggle = new CheckBox();
+ enabledToggle.setImmediate(true);
+ enabledToggle.setValue(true);
+ enabledToggle.setCaption("Enabled");
+ enabledToggle.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setEnabled((Boolean) event.getProperty().getValue());
+ }
+ });
+
+ return enabledToggle;
+ }
+
+ private Component toggleInvalid() {
+ CheckBox invalid = new CheckBox("Invalid");
+ invalid.setImmediate(true);
+ invalid.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setInvalid((Boolean) event.getProperty().getValue());
+ }
+ });
+
+ return invalid;
+ }
+
+ protected void setInvalid(boolean value) {
+ UserError userError = null;
+ if (value) {
+ userError = new UserError(
+ "Der eingegebene Wert ist nicht zulässig!");
+ }
+
+ for (AbstractField<?> c : components) {
+ c.setComponentError(userError);
+ }
+ }
+
+ protected void setRequired(boolean value) {
+ for (AbstractField<?> c : components) {
+ c.setRequired(value);
+ }
+
+ }
+
+ protected void setIcon(boolean value) {
+ for (AbstractField<?> c : components) {
+ if (!value) {
+ c.setIcon(null);
+ } else {
+ c.setIcon(new ThemeResource("../runo/icons/16/ok.png"));
+ }
+ }
+
+ }
+
+ protected void setReadOnly(boolean value) {
+ for (AbstractField<?> c : components) {
+ c.setReadOnly(value);
+ }
+ }
+
+ protected void setEnabled(boolean value) {
+ for (AbstractField<?> c : components) {
+ c.setEnabled(value);
+ }
+ }
+
+ private Component toggleError() {
+ CheckBox errorToggle = new CheckBox();
+ errorToggle.setImmediate(true);
+ errorToggle.setCaption("Error");
+ errorToggle.addListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ setError((Boolean) event.getProperty().getValue());
+ }
+ });
+ return errorToggle;
+ }
+
+ protected void setError(boolean value) {
+ for (AbstractField<?> c : components) {
+ if (value) {
+ c.setComponentError(new UserError("error"));
+ } else {
+ c.setComponentError(null);
+
+ }
+ }
+
+ }
+
+ private void createComponents() {
+ components.add(new TextField("Default TextBox"));
+ components.add(new TextArea("Default TextArea."));
+ // components.add(new RichTextArea("Default RichtTextArea"));
+ components.add(new PasswordField("Default Password"));
+ components.add(new DateField("Default DateField"));
+
+ // PopupDateField popupDateField = new
+ // PopupDateField("Default DateField");
+ // popupDateField.setTextFieldEnabled(false);
+ // components.add(popupDateField);
+
+ components.add(new CheckBox("Default CheckBox"));
+
+ ComboBox comboBox = new ComboBox("Default ComboBox");
+ comboBox.addItem("Item1");
+ components.add(comboBox);
+
+ OptionGroup radioGroup = new OptionGroup("Single Items");
+ radioGroup.addItem("Single Item 1");
+ radioGroup.addItem("Single Item 2");
+ radioGroup.setMultiSelect(false);
+ components.add(radioGroup);
+
+ OptionGroup checkGroup = new OptionGroup("Multi Items");
+ checkGroup.addItem("Multi Item 1");
+ checkGroup.addItem("Multi Item 2");
+ checkGroup.setMultiSelect(true);
+ components.add(checkGroup);
+
+ // Tree tree = new Tree();
+ // tree.setCaption("tree");
+ // tree.addItem("single item");
+ // components.add(tree);
+ }
+
+ private void setLayout(Layout newLayout) {
+ if (layout == null) {
+ layoutParent.addComponent(newLayout, 0);
+ } else {
+ layoutParent.replaceComponent(layout, newLayout);
+ }
+ layout = newLayout;
+
+ for (Component c : components) {
+ if (c.getParent() != layout) {
+ layout.addComponent(c);
+ }
+ }
+
+ }
+
+ private Layout getLayout(String caption,
+ Class<? extends Layout> layoutClass, String width) {
+ Layout l;
+ if (layoutClass == VerticalLayout.class) {
+ if (verticalLayout == null) {
+ verticalLayout = new VerticalLayout();
+ verticalLayout.setStyleName("borders");
+ }
+ l = verticalLayout;
+ } else if (layoutClass == HorizontalLayout.class) {
+ if (horizontalLayout == null) {
+ horizontalLayout = new HorizontalLayout();
+ horizontalLayout.setStyleName("borders");
+ }
+ l = horizontalLayout;
+ } else if (layoutClass == GridLayout.class) {
+ if (gridLayout == null) {
+ gridLayout = new GridLayout();
+ gridLayout.setStyleName("borders");
+ }
+ l = gridLayout;
+ } else if (layoutClass == CssLayout.class) {
+ if (cssLayout == null) {
+ cssLayout = new CssLayout();
+ cssLayout.setStyleName("borders");
+ }
+ l = cssLayout;
+ } else if (layoutClass == FormLayout.class) {
+ if (formLayout == null) {
+ formLayout = new FormLayout();
+ formLayout.setStyleName("borders");
+ }
+ l = formLayout;
+ } else {
+ return null;
+ }
+
+ l.setCaption(caption);
+ if (width.equals("auto")) {
+ width = null;
+ }
+
+ l.setWidth(width);
+
+ // addComponent(l);
+
+ return l;
+ }
+
+ private Component createLayoutSelect() {
+ layoutSelect = new NativeSelect("Layout");
+ layoutSelect.addContainerProperty(CAPTION, String.class, "");
+ layoutSelect.addContainerProperty(CLASS, Class.class, "");
+ layoutSelect.addContainerProperty(WIDTH, String.class, "");
+ layoutSelect.setItemCaptionPropertyId(CAPTION);
+ layoutSelect.setNullSelectionAllowed(false);
+
+ for (Class<?> cls : new Class[] { HorizontalLayout.class,
+ VerticalLayout.class, GridLayout.class, CssLayout.class,
+ FormLayout.class }) {
+ for (String width : new String[] { "auto" }) {
+ Object id = layoutSelect.addItem();
+ Item i = layoutSelect.getItem(id);
+ i.getItemProperty(CAPTION).setValue(
+ cls.getSimpleName() + ", " + width);
+ i.getItemProperty(CLASS).setValue(cls);
+ i.getItemProperty(WIDTH).setValue(width);
+ }
+
+ }
+ layoutSelect.setImmediate(true);
+ layoutSelect.addListener(new ValueChangeListener() {
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void valueChange(ValueChangeEvent event) {
+ Item i = layoutSelect.getItem(event.getProperty().getValue());
+
+ setLayout(getLayout((String) i.getItemProperty(CAPTION)
+ .getValue(), (Class<? extends Layout>) i
+ .getItemProperty(CLASS).getValue(), (String) i
+ .getItemProperty(WIDTH).getValue()));
+ }
+ });
+
+ return layoutSelect;
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Tests what happens when the caption changes in various layouts. Behavior should be consistent.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 5424;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/layouts/VerticalLayoutSlotExpansionAndAlignment.java b/uitest/src/com/vaadin/tests/layouts/VerticalLayoutSlotExpansionAndAlignment.java
index bba8ccf120..fe2dd6cea8 100644
--- a/uitest/src/com/vaadin/tests/layouts/VerticalLayoutSlotExpansionAndAlignment.java
+++ b/uitest/src/com/vaadin/tests/layouts/VerticalLayoutSlotExpansionAndAlignment.java
@@ -1,6 +1,5 @@
package com.vaadin.tests.layouts;
-import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.HorizontalLayout;
diff --git a/uitest/src/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java b/uitest/src/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java
index 2294b1909b..72863895a1 100644
--- a/uitest/src/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java
+++ b/uitest/src/com/vaadin/tests/layouts/layouttester/LayoutTesterApplication.java
@@ -19,9 +19,14 @@ import com.vaadin.ui.themes.Reindeer;
public class LayoutTesterApplication extends AbstractTestCase {
Button nextButton = new Button("Next");
private int layoutIndex = -1;
- private int layoutCount = 1;
- private Method[] layoutGetters;
+ private static final String[] layoutGetters = new String[] {
+ "getCaptionsTests", "getIconsTests",
+ "getRequiredErrorIndicatorsTests", "getAlignmentTests",
+ "getExpandRatiosTests", "getMarginSpacingTests",
+ "getComponentAddReplaceMoveTests", "getComponentSizingTests",
+ "getLayoutSizingTests" };
+
private LegacyWindow mainWindow;
private NativeSelect layoutSelector;
@@ -29,33 +34,32 @@ public class LayoutTesterApplication extends AbstractTestCase {
public void init() {
mainWindow = new LegacyWindow("LayoutTesterApplication");
setMainWindow(mainWindow);
- loadLayoutGetters();
- nextLaytout();
+ nextLayout();
nextButton.addListener(new Button.ClickListener() {
private static final long serialVersionUID = -1577298910202253538L;
@Override
public void buttonClick(ClickEvent event) {
- nextLaytout();
+ nextLayout();
}
});
}
- private void nextLaytout() {
+ private void nextLayout() {
try {
mainWindow.removeAllComponents();
HorizontalLayout vlo = new HorizontalLayout();
vlo.setSpacing(true);
++layoutIndex;
- if (layoutIndex >= layoutCount) {
+ if (layoutIndex >= layoutGetters.length) {
layoutIndex = 0;
}
mainWindow.addComponent(vlo);
vlo.addComponent(nextButton);
vlo.addComponent(getLayoutTypeSelect());
- vlo.addComponent(new UndefWideLabel(layoutGetters[layoutIndex]
- .getName()));
+ vlo.addComponent(new UndefWideLabel(getLayoutGetterMethod(
+ layoutGetters[layoutIndex]).getName()));
Layout lo = null;
if (layoutSelector.getValue() == VerticalLayout.class) {
@@ -75,24 +79,34 @@ public class LayoutTesterApplication extends AbstractTestCase {
}
}
- public void loadLayoutGetters() {
- layoutGetters = AbstractLayoutTests.class.getDeclaredMethods();
- layoutCount = layoutGetters.length;
+ private Method getLayoutGetterMethod(String method) {
+ try {
+ return AbstractLayoutTests.class.getDeclaredMethod(method);
+ } catch (SecurityException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ throw new RuntimeException(e);
+ }
}
public Layout getVerticalTestLayout(int index) throws Exception {
VerticalLayoutTests vlotest = new VerticalLayoutTests(this);
- return (Layout) layoutGetters[index].invoke(vlotest, (Object[]) null);
+ return (Layout) getLayoutGetterMethod(layoutGetters[index]).invoke(
+ vlotest, (Object[]) null);
}
public Layout getHorizontalTestLayout(int index) throws Exception {
HorizontalLayoutTests hlotest = new HorizontalLayoutTests(this);
- return (Layout) layoutGetters[index].invoke(hlotest, (Object[]) null);
+ return (Layout) getLayoutGetterMethod(layoutGetters[index]).invoke(
+ hlotest, (Object[]) null);
}
public Layout getGridTestLayout(int index) throws Exception {
GridLayoutTests hlotest = new GridLayoutTests(this);
- return (Layout) layoutGetters[index].invoke(hlotest, (Object[]) null);
+ return (Layout) getLayoutGetterMethod(layoutGetters[index]).invoke(
+ hlotest, (Object[]) null);
}
private NativeSelect getLayoutTypeSelect() {
@@ -110,7 +124,7 @@ public class LayoutTesterApplication extends AbstractTestCase {
@Override
public void valueChange(ValueChangeEvent event) {
layoutIndex = -1;
- nextLaytout();
+ nextLayout();
}
});
}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java
new file mode 100644
index 0000000000..57ad0d97ba
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/Broadcaster.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.tests.minitutorials.broadcastingmessages;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Broadcaster {
+
+ private static List<BroadcastListener> listeners = new ArrayList<BroadcastListener>();
+
+ public synchronized static void register(BroadcastListener listener) {
+ listeners.add(listener);
+ }
+
+ public synchronized static void unregister(BroadcastListener listener) {
+ listeners.remove(listener);
+ }
+
+ private synchronized static List<BroadcastListener> getListeners() {
+ List<BroadcastListener> listenerCopy = new ArrayList<BroadcastListener>();
+ listenerCopy.addAll(listeners);
+ return listenerCopy;
+ }
+
+ public static void broadcast(final String message) {
+ // Make a copy of the listener list while synchronized, can't be
+ // synchronized while firing the event or we would have to fire each
+ // event in a separate thread.
+ final List<BroadcastListener> listenerCopy = getListeners();
+
+ // We spawn another thread to avoid potential deadlocks with
+ // multiple UIs locked simultaneously
+ Thread eventThread = new Thread() {
+ @Override
+ public void run() {
+ for (BroadcastListener listener : listenerCopy) {
+ listener.receiveBroadcast(message);
+ }
+ }
+ };
+ eventThread.start();
+ }
+
+ public interface BroadcastListener {
+ public void receiveBroadcast(String message);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java
new file mode 100644
index 0000000000..06ead20db3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/minitutorials/broadcastingmessages/BroadcasterUI.java
@@ -0,0 +1,57 @@
+package com.vaadin.tests.minitutorials.broadcastingmessages;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.minitutorials.broadcastingmessages.Broadcaster.BroadcastListener;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Notification;
+import com.vaadin.ui.Notification.Type;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+
+public class BroadcasterUI extends UI implements BroadcastListener {
+
+ @Override
+ protected void init(VaadinRequest request) {
+ final VerticalLayout layout = new VerticalLayout();
+ layout.setMargin(true);
+ setContent(layout);
+
+ final TextArea message = new TextArea("",
+ "The system is going down for maintenance in 10 minutes");
+ layout.addComponent(message);
+
+ final Button button = new Button("Broadcast");
+ layout.addComponent(button);
+ button.addClickListener(new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ Broadcaster.broadcast(message.getValue());
+ }
+ });
+
+ // Register broadcast listener
+ Broadcaster.register(this);
+ }
+
+ @Override
+ public void detach() {
+ Broadcaster.unregister(this);
+ super.detach();
+ }
+
+ @Override
+ public void receiveBroadcast(final String message) {
+ access(new Runnable() {
+ @Override
+ public void run() {
+ Notification n = new Notification("Message received", message,
+ Type.TRAY_NOTIFICATION);
+ n.show(getPage());
+ }
+ });
+
+ }
+
+} \ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginMainView.java b/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginMainView.java
new file mode 100644
index 0000000000..cb59aa1608
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginMainView.java
@@ -0,0 +1,42 @@
+package com.vaadin.tests.minitutorials.v70;
+
+import com.vaadin.navigator.View;
+import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CssLayout;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.Label;
+
+public class SimpleLoginMainView extends CustomComponent implements View {
+
+ public static final String NAME = "";
+
+ Label text = new Label();
+
+ Button logout = new Button("Logout", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+
+ // "Logout" the user
+ getSession().setAttribute("user", null);
+
+ // Refresh this view, should redirect to login view
+ getUI().getNavigator().navigateTo(NAME);
+ }
+ });
+
+ public SimpleLoginMainView() {
+ setCompositionRoot(new CssLayout(text, logout));
+ }
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ // Get the user name from the session
+ String username = String.valueOf(getSession().getAttribute("user"));
+
+ // And show the username
+ text.setValue("Hello " + username);
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginUI.java b/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginUI.java
new file mode 100644
index 0000000000..1f94d43abe
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginUI.java
@@ -0,0 +1,64 @@
+package com.vaadin.tests.minitutorials.v70;
+
+import com.vaadin.navigator.Navigator;
+import com.vaadin.navigator.ViewChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.ui.UI;
+
+public class SimpleLoginUI extends UI {
+
+ @Override
+ protected void init(VaadinRequest request) {
+
+ /*
+ * Create a new instance of the navigator. The navigator will attach
+ * itself automatically to this view.
+ */
+ new Navigator(this, this);
+
+ /*
+ * The initial log view where the user can login to the application
+ */
+ getNavigator().addView(SimpleLoginView.NAME, SimpleLoginView.class);
+
+ /*
+ * Add the main view of the application
+ */
+ getNavigator().addView(SimpleLoginMainView.NAME,
+ SimpleLoginMainView.class);
+
+ /*
+ * We use a view change handler to ensure the user is always redirected
+ * to the login view if the user is not logged in.
+ */
+ getNavigator().addViewChangeListener(new ViewChangeListener() {
+
+ @Override
+ public boolean beforeViewChange(ViewChangeEvent event) {
+
+ // Check if a user has logged in
+ boolean isLoggedIn = getSession().getAttribute("user") != null;
+ boolean isLoginView = event.getNewView() instanceof SimpleLoginView;
+
+ if (!isLoggedIn && !isLoginView) {
+ // Redirect to login view always if a user has not yet
+ // logged in
+ getNavigator().navigateTo(SimpleLoginView.NAME);
+ return false;
+
+ } else if (isLoggedIn && isLoginView) {
+ // If someone tries to access to login view while logged in,
+ // then cancel
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void afterViewChange(ViewChangeEvent event) {
+
+ }
+ });
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginView.java b/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginView.java
new file mode 100644
index 0000000000..3ff1c2df40
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/minitutorials/v70/SimpleLoginView.java
@@ -0,0 +1,137 @@
+package com.vaadin.tests.minitutorials.v70;
+
+import com.vaadin.data.validator.AbstractValidator;
+import com.vaadin.data.validator.EmailValidator;
+import com.vaadin.navigator.View;
+import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent;
+import com.vaadin.shared.ui.MarginInfo;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CustomComponent;
+import com.vaadin.ui.PasswordField;
+import com.vaadin.ui.TextField;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.themes.Reindeer;
+
+public class SimpleLoginView extends CustomComponent implements View,
+ Button.ClickListener {
+
+ public static final String NAME = "login";
+
+ private final TextField user;
+
+ private final PasswordField password;
+
+ private final Button loginButton;
+
+ public SimpleLoginView() {
+ setSizeFull();
+
+ // Create the user input field
+ user = new TextField("User:");
+ user.setWidth("300px");
+ user.setRequired(true);
+ user.setInputPrompt("Your username (eg. joe@email.com)");
+ user.addValidator(new EmailValidator(
+ "Username must be an email address"));
+ user.setInvalidAllowed(false);
+
+ // Create the password input field
+ password = new PasswordField("Password:");
+ password.setWidth("300px");
+ password.addValidator(new PasswordValidator());
+ password.setRequired(true);
+ password.setValue("");
+ password.setNullRepresentation("");
+
+ // Create login button
+ loginButton = new Button("Login", this);
+
+ // Add both to a panel
+ VerticalLayout fields = new VerticalLayout(user, password, loginButton);
+ fields.setCaption("Please login to access the application. (test@test.com/passw0rd)");
+ fields.setSpacing(true);
+ fields.setMargin(new MarginInfo(true, true, true, false));
+ fields.setSizeUndefined();
+
+ // The view root layout
+ VerticalLayout viewLayout = new VerticalLayout(fields);
+ viewLayout.setSizeFull();
+ viewLayout.setComponentAlignment(fields, Alignment.MIDDLE_CENTER);
+ viewLayout.setStyleName(Reindeer.LAYOUT_BLUE);
+ setCompositionRoot(viewLayout);
+ }
+
+ @Override
+ public void enter(ViewChangeEvent event) {
+ // focus the username field when user arrives to the login view
+ user.focus();
+ }
+
+ /*
+ * Validator for validating the passwords
+ */
+ private static final class PasswordValidator extends
+ AbstractValidator<String> {
+
+ public PasswordValidator() {
+ super("The password provided is not valid");
+ }
+
+ @Override
+ protected boolean isValidValue(String value) {
+ /*
+ * Password must be at least 8 characters long and contain at least
+ * one number
+ */
+ if (value != null
+ && (value.length() < 8 || !value.matches(".*\\d.*"))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public Class<String> getType() {
+ return String.class;
+ }
+ }
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+
+ /*
+ * Validate the fields using the navigator. By using validors for the
+ * fields we reduce the amount of queries we have to use to the database
+ * for wrongly entered passwords
+ */
+ if (!user.isValid() || !password.isValid()) {
+ return;
+ }
+
+ String username = user.getValue();
+ String password = this.password.getValue();
+
+ /*
+ * Validate username and password with database here. For examples sake
+ * I use a dummy username and password.
+ */
+ boolean isValid = username.equals("test@test.com")
+ && password.equals("passw0rd");
+
+ if (isValid) {
+ // Store the current user in the service session
+ getSession().setAttribute("user", username);
+
+ // Navigate to main view
+ getUI().getNavigator().navigateTo(SimpleLoginMainView.NAME);
+
+ } else {
+
+ // Wrong password clear the password field and refocuses it
+ this.password.setValue(null);
+ this.password.focus();
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v71beta/CSSInjectWithColorpicker.java b/uitest/src/com/vaadin/tests/minitutorials/v71beta/CSSInjectWithColorpicker.java
new file mode 100644
index 0000000000..63e43b29f1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/minitutorials/v71beta/CSSInjectWithColorpicker.java
@@ -0,0 +1,234 @@
+package com.vaadin.tests.minitutorials.v71beta;
+
+import java.util.Arrays;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.server.Page;
+import com.vaadin.server.Page.Styles;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.MarginInfo;
+import com.vaadin.shared.ui.colorpicker.Color;
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.ColorPicker;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Component;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.UI;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.components.colorpicker.ColorChangeEvent;
+import com.vaadin.ui.components.colorpicker.ColorChangeListener;
+
+public class CSSInjectWithColorpicker extends UI {
+
+ @Override
+ protected void init(VaadinRequest request) {
+
+ // Create a text editor
+ Component editor = createEditor("Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
+ + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
+ + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
+ + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
+ + "quam, ac urna eros est cras id cras, eleifend eu mattis nec."
+ + "Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
+ + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
+ + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
+ + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
+ + "quam, ac urna eros est cras id cras, eleifend eu mattis nec."
+ + "Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
+ + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
+ + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
+ + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
+ + "quam, ac urna eros est cras id cras, eleifend eu mattis nec."
+ + "Lorem ipsum dolor sit amet, lacus pharetra sed, sit a "
+ + "tortor. Id aliquam lorem pede, orci ut enim metus, diam nulla mi "
+ + "suspendisse tempor tortor. Eleifend lorem proin, morbi vel diam ut. "
+ + "Tempor est tellus vitae, pretium condimentum facilisis sit. Sagittis "
+ + "quam, ac urna eros est cras id cras, eleifend eu mattis nec.");
+
+ VerticalLayout content = new VerticalLayout(editor);
+ content.setMargin(true);
+ setContent(content);
+ }
+
+ /**
+ * Creates a text editor for visually editing text
+ *
+ * @param text
+ * The text editor
+ * @return
+ */
+ private Component createEditor(String text) {
+
+ Panel editor = new Panel("Text Editor");
+ editor.setWidth("580px");
+
+ VerticalLayout panelContent = new VerticalLayout();
+ panelContent.setSpacing(true);
+ panelContent.setMargin(new MarginInfo(true, false, false, false));
+ editor.setContent(panelContent);
+
+ // Create the toolbar
+ HorizontalLayout toolbar = new HorizontalLayout();
+ toolbar.setSpacing(true);
+ toolbar.setMargin(new MarginInfo(false, false, false, true));
+
+ // Create the font family selector
+ toolbar.addComponent(createFontSelect());
+
+ // Create the font size selector
+ toolbar.addComponent(createFontSizeSelect());
+
+ // Create the text color selector
+ toolbar.addComponent(createTextColorSelect());
+
+ // Create the background color selector
+ toolbar.addComponent(createBackgroundColorSelect());
+
+ panelContent.addComponent(toolbar);
+ panelContent.setComponentAlignment(toolbar, Alignment.MIDDLE_LEFT);
+
+ // Spacer between toolbar and text
+ panelContent.addComponent(new Label("<hr/>", ContentMode.HTML));
+
+ // The text to edit
+ TextArea textLabel = new TextArea(null, text);
+ textLabel.setWidth("100%");
+ textLabel.setHeight("200px");
+
+ // IMPORTANT: We are here setting the style name of the label, we are
+ // going to use this in our injected styles to target the label
+ textLabel.setStyleName("text-label");
+
+ panelContent.addComponent(textLabel);
+
+ return editor;
+ }
+
+ /**
+ * Creates a background color select dialog
+ */
+ private Component createBackgroundColorSelect() {
+ ColorPicker bgColor = new ColorPicker("Background", Color.WHITE);
+ bgColor.setWidth("110px");
+ bgColor.setCaption("Background");
+ bgColor.addColorChangeListener(new ColorChangeListener() {
+
+ @Override
+ public void colorChanged(ColorChangeEvent event) {
+
+ // Get the new background color
+ Color color = event.getColor();
+
+ // Get the stylesheet of the page
+ Styles styles = Page.getCurrent().getStyles();
+
+ // inject the new background color
+ styles.add(".v-app .v-textarea.text-label { background-color:"
+ + color.getCSS() + "; }");
+ }
+ });
+ return bgColor;
+ }
+
+ /**
+ * Create a text color selction dialog
+ */
+ private Component createTextColorSelect() {
+
+ // Colorpicker for changing text color
+ ColorPicker textColor = new ColorPicker("Color", Color.BLACK);
+ textColor.setWidth("110px");
+ textColor.setCaption("Color");
+ textColor.addColorChangeListener(new ColorChangeListener() {
+
+ @Override
+ public void colorChanged(ColorChangeEvent event) {
+
+ // Get the new text color
+ Color color = event.getColor();
+
+ // Get the stylesheet of the page
+ Styles styles = Page.getCurrent().getStyles();
+
+ // inject the new color as a style
+ styles.add(".v-app .v-textarea.text-label { color:"
+ + color.getCSS() + "; }");
+ }
+ });
+
+ return textColor;
+ }
+
+ /**
+ * Creates a font family selection dialog
+ */
+ private Component createFontSelect() {
+ final ComboBox select = new ComboBox(null, Arrays.asList("Arial",
+ "Helvetica", "Verdana", "Courier", "Times", "sans-serif"));
+ select.setValue("Arial");
+ select.setWidth("200px");
+ select.setInputPrompt("Font");
+ select.setDescription("Font");
+ select.setImmediate(true);
+ select.setNullSelectionAllowed(false);
+ select.setNewItemsAllowed(false);
+
+ select.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ // Get the new font family
+ String fontFamily = select.getValue().toString();
+
+ // Get the stylesheet of the page
+ Styles styles = Page.getCurrent().getStyles();
+
+ // inject the new font size as a style. We need .v-app to
+ // override Vaadin's default styles here
+ styles.add(".v-app .v-textarea.text-label { font-family:"
+ + fontFamily + "; }");
+ }
+ });
+
+ return select;
+ }
+
+ /**
+ * Creates a font size selection control
+ */
+ private Component createFontSizeSelect() {
+
+ final ComboBox select = new ComboBox(null, Arrays.asList(8, 9, 10, 12,
+ 14, 16, 20, 25, 30, 40, 50));
+ select.setWidth("100px");
+ select.setValue(12);
+ select.setInputPrompt("Font size");
+ select.setDescription("Font size");
+ select.setImmediate(true);
+ select.setNullSelectionAllowed(false);
+ select.setNewItemsAllowed(false);
+ select.addValueChangeListener(new ValueChangeListener() {
+
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ // Get the new font size
+ Integer fontSize = (Integer) select.getValue();
+
+ // Get the stylesheet of the page
+ Styles styles = Page.getCurrent().getStyles();
+
+ // inject the new font size as a style. We need .v-app to
+ // override Vaadin's default styles here
+ styles.add(".v-app .v-textarea.text-label { font-size:"
+ + String.valueOf(fontSize) + "px; }");
+ }
+ });
+
+ return select;
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7a1/AutoGeneratingForm.java b/uitest/src/com/vaadin/tests/minitutorials/v7a1/AutoGeneratingForm.java
index 5547c1077e..a2723beab3 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7a1/AutoGeneratingForm.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7a1/AutoGeneratingForm.java
@@ -46,7 +46,7 @@ public class AutoGeneratingForm extends UI {
fieldGroup.setItemDataSource(new BeanItem<Person>(new Person("John",
"Doe", 34)));
- // Loop through the properties, build fields for them and add the fields
+ // Loop through the properties, build fields for them and add the fields
// to this root
for (Object propertyId : fieldGroup.getUnboundPropertyIds()) {
layout.addComponent(fieldGroup.buildAndBind(propertyId));
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7b6/OpeningUIInPopup.java b/uitest/src/com/vaadin/tests/minitutorials/v7b6/OpeningUIInPopup.java
index 2152e05f14..da9c73dd94 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7b6/OpeningUIInPopup.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7b6/OpeningUIInPopup.java
@@ -27,16 +27,17 @@ public class OpeningUIInPopup extends UI {
protected void init(VaadinRequest request) {
Button popupButton = new Button("Open popup with MyPopupUI");
- BrowserWindowOpener popupOpener = new BrowserWindowOpener(MyPopupUI.class);
+ BrowserWindowOpener popupOpener = new BrowserWindowOpener(
+ MyPopupUI.class);
popupOpener.setFeatures("height=300,width=300");
popupOpener.extend(popupButton);
-
+
// Add a parameter
popupOpener.setParameter("foo", "bar");
// Set a fragment
popupOpener.setUriFragment("myfragment");
-
+
setContent(popupButton);
}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7b9/CountView.java b/uitest/src/com/vaadin/tests/minitutorials/v7b9/CountView.java
index 7aaf810355..59708f2bc7 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7b9/CountView.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7b9/CountView.java
@@ -14,6 +14,7 @@ public class CountView extends Panel implements View {
setContent(new Label("Created: " + count++));
}
+ @Override
public void enter(ViewChangeEvent event) {
}
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7b9/LoginView.java b/uitest/src/com/vaadin/tests/minitutorials/v7b9/LoginView.java
index 3aa3e42a58..28f8443440 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7b9/LoginView.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7b9/LoginView.java
@@ -28,6 +28,7 @@ public class LoginView extends Panel implements View {
layout.addComponent(password);
final Button login = new Button("Login", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
Notification.show("Ok, let's pretend you're " + email);
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainView.java b/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainView.java
index 3a1a685bbe..d37a39345f 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainView.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainView.java
@@ -42,6 +42,7 @@ public class MainView extends Panel implements View {
layout.addComponent(lnk);
logOut = new Button("Logout", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
((NavigationtestUI) UI.getCurrent()).setLoggedInUser(null);
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainViewEarlierExample.java b/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainViewEarlierExample.java
index 0eac6a042e..861fd9f8a4 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainViewEarlierExample.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7b9/MainViewEarlierExample.java
@@ -41,6 +41,7 @@ public class MainViewEarlierExample extends Panel implements View {
// login/logout toggle so we can test this
Button logInOut = new Button("Toggle login",
new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
Object user = ((NavigationtestUI) UI.getCurrent())
.getLoggedInUser();
diff --git a/uitest/src/com/vaadin/tests/minitutorials/v7b9/SettingsView.java b/uitest/src/com/vaadin/tests/minitutorials/v7b9/SettingsView.java
index 61492adc39..74c4e68b93 100644
--- a/uitest/src/com/vaadin/tests/minitutorials/v7b9/SettingsView.java
+++ b/uitest/src/com/vaadin/tests/minitutorials/v7b9/SettingsView.java
@@ -43,6 +43,7 @@ public class SettingsView extends Panel implements View {
date.setBuffered(true);
// show buttons when date is changed
date.addValueChangeListener(new ValueChangeListener() {
+ @Override
public void valueChange(ValueChangeEvent event) {
hideOrShowButtons();
pendingViewAndParameters = null;
@@ -51,6 +52,7 @@ public class SettingsView extends Panel implements View {
// commit the TextField changes when "Save" is clicked
apply = new Button("Apply", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
date.commit();
hideOrShowButtons();
@@ -61,6 +63,7 @@ public class SettingsView extends Panel implements View {
// Discard the TextField changes when "Cancel" is clicked
cancel = new Button("Cancel", new Button.ClickListener() {
+ @Override
public void buttonClick(ClickEvent event) {
date.discard();
hideOrShowButtons();
@@ -72,6 +75,7 @@ public class SettingsView extends Panel implements View {
// attach a listener so that we'll get asked isViewChangeAllowed?
navigator.addViewChangeListener(new ViewChangeListener() {
+ @Override
public boolean beforeViewChange(ViewChangeEvent event) {
if (event.getOldView() == SettingsView.this
&& date.isModified()) {
@@ -93,6 +97,7 @@ public class SettingsView extends Panel implements View {
}
}
+ @Override
public void afterViewChange(ViewChangeEvent event) {
pendingViewAndParameters = null;
}
diff --git a/uitest/src/com/vaadin/tests/push/BasicPush.html b/uitest/src/com/vaadin/tests/push/BasicPush.html
new file mode 100644
index 0000000000..173ec90674
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/BasicPush.html
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.push.BasicPush?restartApplication&amp;debug</td>
+ <td></td>
+</tr>
+<!--Test client initiated push -->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td>
+ <td>4</td>
+</tr>
+<!--Test server initiated push-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>3000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>3000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td>
+ <td>2</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/push/BasicPush.java b/uitest/src/com/vaadin/tests/push/BasicPush.java
new file mode 100644
index 0000000000..b80d287a1d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/BasicPush.java
@@ -0,0 +1,105 @@
+package com.vaadin.tests.push;
+
+import java.util.Date;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.data.util.ObjectProperty;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Label;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class BasicPush extends AbstractTestUI {
+
+ private ObjectProperty<Integer> counter = new ObjectProperty<Integer>(0);
+
+ private ObjectProperty<Integer> counter2 = new ObjectProperty<Integer>(0);
+
+ private final Timer timer = new Timer(true);
+
+ private final TimerTask task = new TimerTask() {
+
+ @Override
+ public void run() {
+ access(new Runnable() {
+ @Override
+ public void run() {
+ counter2.setValue(counter2.getValue() + 1);
+ }
+ });
+ }
+ };
+
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ spacer();
+
+ /*
+ * Client initiated push.
+ */
+ Label lbl = new Label(counter);
+ lbl.setCaption("Client counter (click 'increment' to update):");
+ addComponent(lbl);
+
+ addComponent(new Button("Increment", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ counter.setValue(counter.getValue() + 1);
+ }
+ }));
+
+ spacer();
+
+ /*
+ * Server initiated push.
+ */
+ lbl = new Label(counter2);
+ lbl.setCaption("Server counter (updates each 3s by server thread) :");
+ addComponent(lbl);
+
+ addComponent(new Button("Reset", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ counter2.setValue(0);
+ }
+ }));
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "This test tests the very basic operations of push. "
+ + "It tests that client initiated changes are "
+ + "recieved back to the client as well as server "
+ + "initiated changes are correctly updated to the client.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 11494;
+ }
+
+ private void spacer() {
+ addComponent(new Label("<hr/>", ContentMode.HTML));
+ }
+
+ @Override
+ public void attach() {
+ super.attach();
+ timer.scheduleAtFixedRate(task, new Date(), 3000);
+ }
+
+ @Override
+ public void detach() {
+ super.detach();
+ timer.cancel();
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.html b/uitest/src/com/vaadin/tests/push/PushFromInit.html
new file mode 100644
index 0000000000..d009eb3baf
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/PushFromInit.html
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.push.PushFromInit?debug&amp;restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>waitForText</td>
+ <td>vaadin=runpushcomvaadintestspushPushFromInit::PID_SLog_row_1</td>
+ <td>1. Logged in init</td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushPushFromInit::PID_SLog_row_0</td>
+ <td>2. Logged from background thread started in init</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/push/PushFromInit.java b/uitest/src/com/vaadin/tests/push/PushFromInit.java
new file mode 100644
index 0000000000..4b442de499
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/PushFromInit.java
@@ -0,0 +1,36 @@
+package com.vaadin.tests.push;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.Button;
+
+public class PushFromInit extends AbstractTestUIWithLog {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ new Thread() {
+ @Override
+ public void run() {
+ access(new Runnable() {
+ @Override
+ public void run() {
+ log("Logged from background thread started in init");
+ }
+ });
+ }
+ }.start();
+ log("Logged in init");
+ addComponent(new Button("Sync"));
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Pusing something to a newly created UI should not cause race conditions";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(11529);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/push/PushReattachedComponent.html b/uitest/src/com/vaadin/tests/push/PushReattachedComponent.html
new file mode 100644
index 0000000000..e1f6a5f048
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/PushReattachedComponent.html
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://192.168.2.162:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.components.panel.PanelChangeContents?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>stats</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[1]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>companies</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[0]/VHorizontalLayout[0]/Slot[0]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestscomponentspanelPanelChangeContents::/VVerticalLayout[0]/Slot[1]/VPanel[0]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>stats</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/push/RoundTripTest.java b/uitest/src/com/vaadin/tests/push/RoundTripTest.java
new file mode 100644
index 0000000000..ee0bf6dcb1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/RoundTripTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.push;
+
+import com.vaadin.annotations.Widgetset;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.tests.widgetset.TestingWidgetSet;
+import com.vaadin.tests.widgetset.server.RoundTripTester;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.TextField;
+
+@Widgetset(TestingWidgetSet.NAME)
+public class RoundTripTest extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final RoundTripTester roundTripTester = new RoundTripTester();
+ final TextField payloadSize = new TextField("Payload size (bytes)");
+ payloadSize.setConverter(Integer.class);
+ payloadSize.setConvertedValue(10000);
+ if (request.getParameter("payload") != null) {
+ payloadSize.setValue(request.getParameter("payload"));
+ }
+ addComponent(payloadSize);
+ final TextField testDuration = new TextField("Test duration (ms)");
+ testDuration.setConverter(Integer.class);
+ testDuration.setConvertedValue(10000);
+ addComponent(testDuration);
+ if (request.getParameter("duration") != null) {
+ testDuration.setValue(request.getParameter("duration"));
+ }
+
+ Button start = new Button("Start test");
+ start.addClickListener(new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ roundTripTester.start(
+ (Integer) testDuration.getConvertedValue(),
+ (Integer) payloadSize.getConvertedValue());
+ }
+ });
+ addComponent(roundTripTester);
+ addComponent(start);
+
+ if (request.getParameter("go") != null) {
+ start.click();
+ }
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests how many roundtrips per second you can get using the given package size";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 11370;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/push/StreamingPush.html b/uitest/src/com/vaadin/tests/push/StreamingPush.html
new file mode 100644
index 0000000000..cf94a09c63
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/StreamingPush.html
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.push.BasicPush?restartApplication&amp;debug&amp;transport=streaming</td>
+ <td></td>
+</tr>
+<!--Test client initiated push -->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VLabel[0]</td>
+ <td>4</td>
+</tr>
+<!--Test server initiated push-->
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[5]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>3000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td>
+ <td>1</td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>3000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushBasicPush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[4]/VLabel[0]</td>
+ <td>2</td>
+</tr>
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/push/TogglePush.html b/uitest/src/com/vaadin/tests/push/TogglePush.html
new file mode 100644
index 0000000000..b752d2120c
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/TogglePush.html
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.push.TogglePush?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<!--Push is enabled, so text gets updated-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Counter has been updated 1 times</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td>
+ <td>61,6</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<!--Push is disabled, so text is not updated-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Counter has been updated 1 times</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<!--Direct update is visible, and includes previous update-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Counter has been updated 3 times</td>
+</tr>
+<tr>
+ <td>mouseClick</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td>
+ <td>61,3</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<!--Push is enabled again, so text gets updated-->
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Counter has been updated 4 times</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/push/TogglePush.java b/uitest/src/com/vaadin/tests/push/TogglePush.java
new file mode 100644
index 0000000000..37687260dd
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/TogglePush.java
@@ -0,0 +1,85 @@
+package com.vaadin.tests.push;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.shared.communication.PushMode;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.Label;
+
+public class TogglePush extends AbstractTestUI {
+ private final Label counterLabel = new Label();
+ private int counter = 0;
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ updateCounter();
+ addComponent(counterLabel);
+
+ setPushMode("disabled".equals(request.getParameter("push")) ? PushMode.DISABLED
+ : PushMode.AUTOMATIC);
+
+ CheckBox pushSetting = new CheckBox("Push enabled");
+ pushSetting.setValue(Boolean.valueOf(getPushMode().isEnabled()));
+ pushSetting.setImmediate(true);
+ pushSetting.addValueChangeListener(new ValueChangeListener() {
+ @Override
+ public void valueChange(ValueChangeEvent event) {
+ if (event.getProperty().getValue() == Boolean.TRUE) {
+ setPushMode(PushMode.AUTOMATIC);
+ } else {
+ setPushMode(PushMode.DISABLED);
+ }
+ }
+ });
+ addComponent(pushSetting);
+
+ addComponent(new Button("Update counter now",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ updateCounter();
+ }
+ }));
+
+ addComponent(new Button("Update counter in 1 sec",
+ new Button.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ new Timer().schedule(new TimerTask() {
+ @Override
+ public void run() {
+ access(new Runnable() {
+ @Override
+ public void run() {
+ updateCounter();
+ }
+ });
+ }
+ }, 1000);
+ }
+ }));
+ }
+
+ public void updateCounter() {
+ counterLabel.setValue("Counter has been updated " + counter++
+ + " times");
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Basic test for enabling and disabling push on the fly.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return Integer.valueOf(11506);
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/push/TogglePushInInit.html b/uitest/src/com/vaadin/tests/push/TogglePushInInit.html
new file mode 100644
index 0000000000..c735f225e1
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/push/TogglePushInInit.html
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8071/" />
+<title>TogglePushInInit</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">TogglePushInInit</td></tr>
+</thead><tbody>
+<!--Open with push disabled-->
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.push.TogglePush?restartApplication&push=disabled</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td>
+ <td>off</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Counter has been updated 0 times</td>
+</tr>
+<!--Open with push enabled-->
+<tr>
+ <td>open</td>
+ <td>/run-push/com.vaadin.tests.push.TogglePush?restartApplication&amp;push=enabled</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertValue</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VCheckBox[0]/domChild[0]</td>
+ <td>on</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[3]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>pause</td>
+ <td>2000</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertText</td>
+ <td>vaadin=runpushcomvaadintestspushTogglePush::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[0]/VLabel[0]</td>
+ <td>Counter has been updated 1 times</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.html b/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.html
index 16f3db6a1a..543faa30dd 100644
--- a/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.html
+++ b/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.html
@@ -53,7 +53,12 @@
</tr>
<tr>
<td>assertTextPresent</td>
- <td>/APP can not be found</td>
+ <td>HTTP ERROR 404</td>
+ <td></td>
+</tr>
+<tr>
+ <td>assertTextPresent</td>
+ <td>Problem accessing /run/APP/</td>
<td></td>
</tr>
<tr>
diff --git a/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.java b/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.java
index dfd664c9cf..a6a5a5a084 100644
--- a/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.java
+++ b/uitest/src/com/vaadin/tests/requesthandlers/AppResource404.java
@@ -23,8 +23,8 @@ public class AppResource404 extends TestBase {
addComponent(new Link("Existing resource", resource));
addComponent(new Link("Non-existing resource", new ExternalResource(
baseUrl + "/APP/connector/0/4/asdfasdf")));
- addComponent(new Link("/APP url that should give 404",
- new ExternalResource(baseUrl + "/APP")));
+ addComponent(new Link("/APP/ url that should give 404",
+ new ExternalResource(baseUrl + "/APP/")));
addComponent(new Link("/APPLE url that should go to UI providers",
new ExternalResource(baseUrl + "/APPLE")));
}
diff --git a/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html
new file mode 100644
index 0000000000..05a0f256c2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.html
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8888/" />
+<title>New Test</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Test</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/run/com.vaadin.tests.themes.CSSInjectTest?restartApplication</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>hello-world-gray</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadinteststhemesCSSInjectTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VTextArea[0]</td>
+ <td>.hello{color:blue;}</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadinteststhemesCSSInjectTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>hello-blue</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>vaadin=runcomvaadinteststhemesCSSInjectTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[1]/VTextArea[0]</td>
+ <td>.world{color:red;}</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>vaadin=runcomvaadinteststhemesCSSInjectTest::/VVerticalLayout[0]/Slot[1]/VVerticalLayout[0]/Slot[2]/VButton[0]/domChild[0]/domChild[0]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>screenCapture</td>
+ <td></td>
+ <td>world-red</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java
new file mode 100644
index 0000000000..f4448bf326
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/themes/CSSInjectTest.java
@@ -0,0 +1,87 @@
+package com.vaadin.tests.themes;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.UUID;
+
+import com.vaadin.server.Page;
+import com.vaadin.server.Page.Styles;
+import com.vaadin.server.StreamResource;
+import com.vaadin.shared.ui.label.ContentMode;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TextArea;
+
+public class CSSInjectTest extends TestBase {
+
+ @Override
+ protected void setup() {
+
+ final Styles stylesheet = Page.getCurrent().getStyles();
+
+ // Inject some resources initially
+ stylesheet.add(new StreamResource(new StreamResource.StreamSource() {
+
+ @Override
+ public InputStream getStream() {
+ return new ByteArrayInputStream(
+ ".hello, .world { color:silver; }".getBytes());
+ }
+ }, "mystyles-" + System.currentTimeMillis() + ".css"));
+
+ Label hello = new Label(
+ "<span class='hello'>Hello</span> <span class='world'>world</span>",
+ ContentMode.HTML);
+ addComponent(hello);
+
+ final TextArea cssToInject = new TextArea();
+ cssToInject.setImmediate(true);
+ addComponent(cssToInject);
+
+ Button inject = new Button("Inject!", new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ stylesheet.add(cssToInject.getValue());
+ cssToInject.setValue("");
+ }
+ });
+ addComponent(inject);
+
+ Button injectRandom = new Button("Inject as resource!",
+ new Button.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+
+ final String css = cssToInject.getValue();
+
+ stylesheet.add(new StreamResource(
+ new StreamResource.StreamSource() {
+
+ @Override
+ public InputStream getStream() {
+ return new ByteArrayInputStream(css
+ .getBytes());
+ }
+ }, UUID.randomUUID().toString() + ".css"));
+
+ cssToInject.setValue("");
+ }
+ });
+ addComponent(injectRandom);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Demonstrates how CSS injections can be used to theme the \"Hello world\" label below";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 5500;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
index 919a4a5d69..1b47a86113 100644
--- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
+++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml
@@ -7,5 +7,9 @@
<replace-with class="com.vaadin.tests.widgetset.client.CustomUIConnector">
<when-type-is class="com.vaadin.client.ui.ui.UIConnector" />
</replace-with>
+
+ <replace-with class="com.vaadin.tests.widgetset.client.TestingPushConnection">
+ <when-type-is class="com.vaadin.client.communication.PushConnection" />
+ </replace-with>
</module>
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterConnector.java b/uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterConnector.java
new file mode 100644
index 0000000000..94972d92f4
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterConnector.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.widgetset.client;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.core.client.Duration;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.client.ui.AbstractComponentConnector;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.tests.widgetset.server.RoundTripTester;
+
+@Connect(RoundTripTester.class)
+public class RoundTripTesterConnector extends AbstractComponentConnector {
+
+ private double lastPrintedTime = -1;
+ private int receivedPings = 0;
+ private List<Double> throughputData = new ArrayList<Double>();
+ private int payloadSize = 0;
+
+ @Override
+ protected void init() {
+ super.init();
+ registerRpc(RoundTripTesterRpc.class, new RoundTripTesterRpc() {
+
+ @Override
+ public void ping(int nr, String payload) {
+ getRpcProxy(RoundTripTesterRpc.class).ping(nr + 1, payload);
+ payloadSize = payload.length();
+
+ double now = Duration.currentTimeMillis();
+ if (lastPrintedTime == -1) {
+ lastPrintedTime = now;
+ return;
+ }
+ receivedPings++;
+
+ if (now - lastPrintedTime > 1000) {
+ double roundtripsPerSecond = receivedPings
+ / (now - lastPrintedTime) * 1000;
+ throughputData.add(roundtripsPerSecond);
+ getWidget().setText(
+ roundtripsPerSecond + " roundtrips/second");
+
+ lastPrintedTime = now;
+ receivedPings = 0;
+ }
+
+ }
+
+ @Override
+ public void done() {
+ String result = "Test results for payload of size "
+ + payloadSize + ":";
+ double max = -1;
+ double min = 1239482038939.0;
+ double avg = 0;
+
+ for (Double throughput : throughputData) {
+ if (throughput > max) {
+ max = throughput;
+ }
+ if (throughput < min) {
+ min = throughput;
+ }
+
+ avg += throughput;
+ }
+ avg /= throughputData.size();
+
+ for (Double throughput : throughputData) {
+ result += "<br/>" + formatThroughput(throughput);
+ }
+ result += "<br/>Max: " + formatThroughput(max);
+ result += "<br/>Min: " + formatThroughput(min);
+ result += "<br/>Average: " + formatThroughput(avg);
+ getWidget().setHTML(result);
+ getRpcProxy(RoundTripTesterRpc.class).done();
+ }
+
+ private String formatThroughput(double throughput) {
+ return throughput + " roundtrips / second";
+ }
+ });
+ }
+
+ @Override
+ public HTML getWidget() {
+ return (HTML) super.getWidget();
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterRpc.java b/uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterRpc.java
new file mode 100644
index 0000000000..24c981e0c2
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/RoundTripTesterRpc.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.widgetset.client;
+
+import com.vaadin.shared.communication.ClientRpc;
+import com.vaadin.shared.communication.ServerRpc;
+
+public interface RoundTripTesterRpc extends ServerRpc, ClientRpc {
+ public void ping(int nr, String payload);
+
+ public void done();
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java b/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java
new file mode 100644
index 0000000000..8d00598907
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/client/TestingPushConnection.java
@@ -0,0 +1,30 @@
+package com.vaadin.tests.widgetset.client;
+
+import com.google.gwt.user.client.Window;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.communication.AtmospherePushConnection;
+
+public class TestingPushConnection extends AtmospherePushConnection {
+
+ private String transport;
+
+ @Override
+ public void init(ApplicationConnection connection) {
+ super.init(connection);
+ transport = Window.Location.getParameter("transport");
+ }
+
+ /*
+ * Force transport
+ */
+ @Override
+ protected AtmosphereConfiguration createConfig() {
+ AtmosphereConfiguration conf = super.createConfig();
+ if (transport != null) {
+ conf.setTransport(transport);
+ conf.setFallbackTransport(transport);
+ }
+ return conf;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/widgetset/server/RoundTripTester.java b/uitest/src/com/vaadin/tests/widgetset/server/RoundTripTester.java
new file mode 100644
index 0000000000..c8e561e665
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/widgetset/server/RoundTripTester.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2000-2013 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.tests.widgetset.server;
+
+import com.vaadin.tests.util.LoremIpsum;
+import com.vaadin.tests.widgetset.client.RoundTripTesterRpc;
+import com.vaadin.ui.AbstractComponent;
+
+public class RoundTripTester extends AbstractComponent {
+ private long testStart = 0;
+ private long testEnd = 0;
+
+ public RoundTripTester() {
+ registerRpc(new RoundTripTesterRpc() {
+ @Override
+ public void ping(int nr, String payload) {
+ if (System.currentTimeMillis() < testEnd) {
+ getRpcProxy(RoundTripTesterRpc.class).ping(nr + 1, payload);
+ } else {
+ getRpcProxy(RoundTripTesterRpc.class).done();
+ }
+ }
+
+ @Override
+ public void done() {
+ }
+ });
+ }
+
+ public void start(long testDuration, int payloadSize) {
+ testStart = System.currentTimeMillis();
+ testEnd = testStart + testDuration;
+ getRpcProxy(RoundTripTesterRpc.class).ping(1,
+ generatePayload(payloadSize));
+ }
+
+ private String generatePayload(int payloadSize) {
+ StringBuilder sb = new StringBuilder();
+ while (payloadSize > 10000) {
+ payloadSize -= 10000;
+ sb.append(LoremIpsum.get(10000));
+ }
+ sb.append(LoremIpsum.get(payloadSize));
+ return sb.toString();
+ }
+
+}
diff --git a/uitest/test.xml b/uitest/test.xml
index f3cf2f0884..8228bd9d70 100644
--- a/uitest/test.xml
+++ b/uitest/test.xml
@@ -8,7 +8,7 @@
<!-- Configuration -->
<!-- ================================================================== -->
<!-- Browsers to use for testing -->
- <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox17-esr,winxp-safari5,winxp-googlechrome21,winxp-opera12" />
+ <property name="browsers-windows" value="winxp-ie8,win7-ie9,win7-ie10,winxp-firefox17-esr,winxp-safari5,winxp-googlechrome21,winxp-opera12" />
<property name="browsers-linux" value="linux-firefox3,linux-opera10,linux-googlechrome8" />
<property name="browsers-mac" value="osx-firefox3,osx-opera10,osx-googlechrome8,osx-safari4,osx-safari5" />