json.getValueMap("typeMappings"), widgetSet);
}
+ handleUIDLDuration.logDuration(
+ " * Handling type mappings from server completed", 10);
/*
- * Hook for TestBench to get details about server status
+ * Hook for e.g. TestBench to get details about server peformance
*/
- if (json.containsKey("tbss")) {
- testBenchServerStatus = json.getValueMap("tbss");
+ if (json.containsKey("timings")) {
+ serverTimingInfo = json.getValueMap("timings");
}
Command c = new Command() {
}
/**
- * Returns the current date and time of the browser. This will not be
- * entirely accurate due to varying network latencies, but should provide a
- * close-enough value for most cases.
+ * Indicates whether the browser might require juggling to properly update
+ * sizes inside elements with overflow: auto.
*
- * @return the current date and time of the browser.
+ * @return <code>true</code> if the browser requires the workaround,
+ * otherwise <code>false</code>
*/
- public Date getCurrentDate() {
- return new Date();
- }
-
- /**
- * @return true if the browser runs on a touch based device.
- */
- public boolean isTouchDevice() {
- return touchDevice;
+ public boolean requiresOverflowAutoFix() {
+ return (getWebkitVersion() > 0 || getOperaVersion() >= 11)
+ && Util.getNativeScrollbarSize() > 0;
}
+ /**
+ * Checks if the browser is run on iOS
+ *
+ * @return true if the browser is run on iOS, false otherwise
+ */
+ public boolean isIOS() {
+ return browserDetails.isIOS();
+ }
+
+ /**
+ * Checks if the browser is run on Android
+ *
+ * @return true if the browser is run on Android, false otherwise
+ */
+ public boolean isAndroid() {
+ return browserDetails.isAndroid();
+ }
+
+ /**
+ * Checks if the browser is capable of handling scrolling natively or if a
+ * touch scroll helper is needed for scrolling.
+ *
+ * @return true if browser needs a touch scroll helper, false if the browser
+ * can handle scrolling natively
+ */
+ public boolean requiresTouchScrollDelegate() {
+ if (!isTouchDevice()) {
+ return false;
+ }
+
+ if (isAndroid() && isWebkit() && getWebkitVersion() < 534) {
+ return true;
+ }
+ // if (isIOS() && isWebkit() && getWebkitVersion() < ???) {
+ // return true;
+ // }
+
+ return false;
+ }
+
+ /**
+ * Tests if this is an Android devices with a broken scrollTop
+ * implementation
+ *
+ * @return true if scrollTop cannot be trusted on this device, false
+ * otherwise
+ */
+ public boolean isAndroidWithBrokenScrollTop() {
+ return isAndroid()
+ && (getOperatingSystemMajorVersion() == 3 || getOperatingSystemMajorVersion() == 4);
+ }
+
+ private int getOperatingSystemMajorVersion() {
+ return browserDetails.getOperatingSystemMajorVersion();
+ }
}
* @return true if run on Linux, false otherwise
*/
public boolean isLinux() {
- return isLinux;
+ return os == OperatingSystem.LINUX;
+ }
+
+ /**
+ * Tests if the browser is run on Android.
+ *
+ * @return true if run on Android, false otherwise
+ */
+ public boolean isAndroid() {
+ return os == OperatingSystem.ANDROID;
+ }
+
+ /**
+ * Tests if the browser is run in iOS.
+ *
+ * @return true if run in iOS, false otherwise
+ */
+ public boolean isIOS() {
+ return os == OperatingSystem.IOS;
+ }
+
+ /**
+ * Returns the major version of the operating system. Currently only
+ * supported for mobile devices (iOS/Android)
+ *
+ * @return The major version or -1 if unknown
+ */
+ public int getOperatingSystemMajorVersion() {
+ return osMajorVersion;
+ }
+
+ /**
+ * Returns the minor version of the operating system. Currently only
+ * supported for mobile devices (iOS/Android)
+ *
+ * @return The minor version or -1 if unknown
+ */
+ public int getOperatingSystemMinorVersion() {
+ return osMinorVersion;
}
+ /**
+ * Checks if the browser is so old that it simply won't work with a Vaadin
+ * application. NOTE that the browser might still be capable of running
+ * Crome Frame, so you might still want to check
+ * {@link #isChromeFrameCapable()} if this returns true.
+ *
+ * @return true if the browser won't work, false if not the browser is
+ * supported or might work
+ */
+ public boolean isTooOldToFunctionProperly() {
+ if (isIE() && getBrowserMajorVersion() < 8) {
+ return true;
+ }
+ if (isSafari() && getBrowserMajorVersion() < 5) {
+ return true;
+ }
+ if (isFirefox() && getBrowserMajorVersion() < 4) {
+ return true;
+ }
+ if (isOpera() && getBrowserMajorVersion() < 11) {
+ return true;
+ }
+
+ return false;
+ }
+
}
--- /dev/null
- getWidget().setText(getState().getCaption());
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.button;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.EventHelper;
+import com.vaadin.terminal.gwt.client.MouseEventDetails;
+import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder;
+import com.vaadin.terminal.gwt.client.communication.FieldRpc.FocusAndBlurServerRpc;
+import com.vaadin.terminal.gwt.client.communication.RpcProxy;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
+import com.vaadin.terminal.gwt.client.ui.Connect;
+import com.vaadin.terminal.gwt.client.ui.Connect.LoadStyle;
+import com.vaadin.terminal.gwt.client.ui.Icon;
+import com.vaadin.ui.Button;
+
+@Connect(value = Button.class, loadStyle = LoadStyle.EAGER)
+public class ButtonConnector extends AbstractComponentConnector implements
+ BlurHandler, FocusHandler, ClickHandler {
+
+ private ButtonServerRpc rpc = RpcProxy.create(ButtonServerRpc.class, this);
+ private FocusAndBlurServerRpc focusBlurProxy = RpcProxy.create(
+ FocusAndBlurServerRpc.class, this);
+
+ private HandlerRegistration focusHandlerRegistration = null;
+ private HandlerRegistration blurHandlerRegistration = null;
+
+ @Override
+ public boolean delegateCaptionHandling() {
+ return false;
+ }
+
+ @Override
+ public void init() {
+ super.init();
+ getWidget().addClickHandler(this);
+ getWidget().client = getConnection();
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+ focusHandlerRegistration = EventHelper.updateFocusHandler(this,
+ focusHandlerRegistration);
+ blurHandlerRegistration = EventHelper.updateBlurHandler(this,
+ blurHandlerRegistration);
+ // Set text
++ if (getState().isHtmlContentAllowed()) {
++ getWidget().setHtml(getState().getCaption());
++ } else {
++ getWidget().setText(getState().getCaption());
++ }
+
+ // handle error
+ if (null != getState().getErrorMessage()) {
+ if (getWidget().errorIndicatorElement == null) {
+ getWidget().errorIndicatorElement = DOM.createSpan();
+ getWidget().errorIndicatorElement
+ .setClassName("v-errorindicator");
+ }
+ getWidget().wrapper.insertBefore(getWidget().errorIndicatorElement,
+ getWidget().captionElement);
+
+ } else if (getWidget().errorIndicatorElement != null) {
+ getWidget().wrapper.removeChild(getWidget().errorIndicatorElement);
+ getWidget().errorIndicatorElement = null;
+ }
+
+ if (getState().getIcon() != null) {
+ if (getWidget().icon == null) {
+ getWidget().icon = new Icon(getConnection());
+ getWidget().wrapper.insertBefore(getWidget().icon.getElement(),
+ getWidget().captionElement);
+ }
+ getWidget().icon.setUri(getState().getIcon().getURL());
+ } else {
+ if (getWidget().icon != null) {
+ getWidget().wrapper.removeChild(getWidget().icon.getElement());
+ getWidget().icon = null;
+ }
+ }
+
+ getWidget().clickShortcut = getState().getClickShortcutKeyCode();
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VButton.class);
+ }
+
+ @Override
+ public VButton getWidget() {
+ return (VButton) super.getWidget();
+ }
+
+ @Override
+ public ButtonState getState() {
+ return (ButtonState) super.getState();
+ }
+
+ public void onFocus(FocusEvent event) {
+ // EventHelper.updateFocusHandler ensures that this is called only when
+ // there is a listener on server side
+ focusBlurProxy.focus();
+ }
+
+ public void onBlur(BlurEvent event) {
+ // EventHelper.updateFocusHandler ensures that this is called only when
+ // there is a listener on server side
+ focusBlurProxy.blur();
+ }
+
+ public void onClick(ClickEvent event) {
+ if (getState().isDisableOnClick()) {
+ getWidget().setEnabled(false);
+ rpc.disableOnClick();
+ }
+
+ // Add mouse details
+ MouseEventDetails details = MouseEventDetailsBuilder
+ .buildMouseEventDetails(event.getNativeEvent(), getWidget()
+ .getElement());
+ rpc.click(details);
+
+ }
+}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.button;
+
+import com.vaadin.terminal.gwt.client.ComponentState;
+import com.vaadin.ui.Button;
+
+/**
+ * Shared state for Button and NativeButton.
+ *
+ * @see ComponentState
+ *
+ * @since 7.0
+ */
+public class ButtonState extends ComponentState {
+ private boolean disableOnClick = false;
+ private int clickShortcutKeyCode = 0;
++ /**
++ * If caption should be rendered in HTML
++ */
++ private boolean htmlContentAllowed = false;
+
+ /**
+ * Checks whether the button should be disabled on the client side on next
+ * click.
+ *
+ * @return true if the button should be disabled on click
+ */
+ public boolean isDisableOnClick() {
+ return disableOnClick;
+ }
+
+ /**
+ * Sets whether the button should be disabled on the client side on next
+ * click.
+ *
+ * @param disableOnClick
+ * true if the button should be disabled on click
+ */
+ public void setDisableOnClick(boolean disableOnClick) {
+ this.disableOnClick = disableOnClick;
+ }
+
+ /**
+ * Returns the key code for activating the button via a keyboard shortcut.
+ *
+ * See {@link Button#setClickShortcut(int, int...)} for more information.
+ *
+ * @return key code or 0 for none
+ */
+ public int getClickShortcutKeyCode() {
+ return clickShortcutKeyCode;
+ }
+
+ /**
+ * Sets the key code for activating the button via a keyboard shortcut.
+ *
+ * See {@link Button#setClickShortcut(int, int...)} for more information.
+ *
+ * @param clickShortcutKeyCode
+ * key code or 0 for none
+ */
+ public void setClickShortcutKeyCode(int clickShortcutKeyCode) {
+ this.clickShortcutKeyCode = clickShortcutKeyCode;
+ }
+
++ /**
++ * 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.
++ *
++ * If set to true, the captions are passed to the browser as html and the
++ * developer is responsible for ensuring no harmful html is used. If set to
++ * false, the content is passed to the browser as plain text.
++ *
++ * @param htmlContentAllowed
++ * <code>true</code> if caption is rendered as HTML,
++ * <code>false</code> otherwise
++ */
++ public void setHtmlContentAllowed(boolean htmlContentAllowed) {
++ this.htmlContentAllowed = htmlContentAllowed;
++ }
++
++ /**
++ * Return HTML rendering setting.
++ *
++ * @return <code>true</code> if the caption text is to be rendered as HTML,
++ * <code>false</code> otherwise
++ */
++ public boolean isHtmlContentAllowed() {
++ return htmlContentAllowed;
++ }
++
+}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.button;
+
+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.KeyCodes;
+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.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.ui.Icon;
+
+public class VButton extends FocusWidget implements ClickHandler {
+
+ public static final String CLASSNAME = "v-button";
+ private static final String CLASSNAME_PRESSED = "v-pressed";
+
+ // mouse movement is checked before synthesizing click event on mouseout
+ protected static int MOVE_THRESHOLD = 3;
+ protected int mousedownX = 0;
+ protected int mousedownY = 0;
+
+ protected ApplicationConnection client;
+
+ protected final Element wrapper = DOM.createSpan();
+
+ protected Element errorIndicatorElement;
+
+ protected final Element captionElement = DOM.createSpan();
+
+ protected Icon icon;
+
+ /**
+ * Helper flag to handle special-case where the button is moved from under
+ * mouse while clicking it. In this case mouse leaves the button without
+ * moving.
+ */
+ protected boolean clickPending;
+
+ private boolean enabled = true;
+
+ private int tabIndex = 0;
+
+ /*
+ * BELOW PRIVATE MEMBERS COPY-PASTED FROM GWT CustomButton
+ */
+
+ /**
+ * If <code>true</code>, this widget is capturing with the mouse held down.
+ */
+ private boolean isCapturing;
+
+ /**
+ * If <code>true</code>, this widget has focus with the space bar down.
+ */
+ private boolean isFocusing;
+
+ /**
+ * Used to decide whether to allow clicks to propagate up to the superclass
+ * or container elements.
+ */
+ private boolean disallowNextClick = false;
+ private boolean isHovering;
+
+ protected int clickShortcut = 0;
+
+ public VButton() {
+ super(DOM.createDiv());
+ setTabIndex(0);
+ sinkEvents(Event.ONCLICK | Event.MOUSEEVENTS | Event.FOCUSEVENTS
+ | Event.KEYEVENTS);
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+
+ setStyleName(CLASSNAME);
+
+ // Add a11y role "button"
+ Accessibility.setRole(getElement(), Accessibility.ROLE_BUTTON);
+
+ wrapper.setClassName(getStylePrimaryName() + "-wrap");
+ getElement().appendChild(wrapper);
+ captionElement.setClassName(getStylePrimaryName() + "-caption");
+ wrapper.appendChild(captionElement);
+
+ addClickHandler(this);
+ }
+
+ public void setText(String text) {
+ captionElement.setInnerText(text);
+ }
+
++ public void setHtml(String html) {
++ captionElement.setInnerHTML(html);
++ }
++
+ @SuppressWarnings("deprecation")
+ @Override
+ /*
+ * Copy-pasted from GWT CustomButton, some minor modifications done:
+ *
+ * -for IE/Opera added CLASSNAME_PRESSED
+ *
+ * -event.preventDefault() commented from ONMOUSEDOWN (Firefox won't apply
+ * :active styles if it is present)
+ *
+ * -Tooltip event handling added
+ *
+ * -onload event handler added (for icon handling)
+ */
+ public void onBrowserEvent(Event event) {
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
+ if (DOM.eventGetType(event) == Event.ONLOAD) {
+ Util.notifyParentOfSizeChange(this, true);
+ }
+ // Should not act on button if disabled.
+ if (!isEnabled()) {
+ // This can happen when events are bubbled up from non-disabled
+ // children
+ return;
+ }
+
+ int type = DOM.eventGetType(event);
+ switch (type) {
+ case Event.ONCLICK:
+ // If clicks are currently disallowed, keep it from bubbling or
+ // being passed to the superclass.
+ if (disallowNextClick) {
+ event.stopPropagation();
+ disallowNextClick = false;
+ return;
+ }
+ break;
+ case Event.ONMOUSEDOWN:
+ if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) {
+ // This was moved from mouseover, which iOS sometimes skips.
+ // We're certainly hovering at this point, and we don't actually
+ // need that information before this point.
+ setHovering(true);
+ }
+ if (event.getButton() == Event.BUTTON_LEFT) {
+ // save mouse position to detect movement before synthesizing
+ // event later
+ mousedownX = event.getClientX();
+ mousedownY = event.getClientY();
+
+ disallowNextClick = true;
+ clickPending = true;
+ setFocus(true);
+ DOM.setCapture(getElement());
+ isCapturing = true;
+ // Prevent dragging (on some browsers);
+ // DOM.eventPreventDefault(event);
+ if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) {
+ addStyleName(CLASSNAME_PRESSED);
+ }
+ }
+ break;
+ case Event.ONMOUSEUP:
+ if (isCapturing) {
+ isCapturing = false;
+ DOM.releaseCapture(getElement());
+ if (isHovering() && event.getButton() == Event.BUTTON_LEFT) {
+ // Click ok
+ disallowNextClick = false;
+ }
+ if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) {
+ removeStyleName(CLASSNAME_PRESSED);
+ }
+ // Explicitly prevent IE 8 from propagating mouseup events
+ // upward (fixes #6753)
+ if (BrowserInfo.get().isIE8()) {
+ event.stopPropagation();
+ }
+ }
+ break;
+ case Event.ONMOUSEMOVE:
+ clickPending = false;
+ if (isCapturing) {
+ // Prevent dragging (on other browsers);
+ DOM.eventPreventDefault(event);
+ }
+ break;
+ case Event.ONMOUSEOUT:
+ Element to = event.getRelatedTarget();
+ if (getElement().isOrHasChild(DOM.eventGetTarget(event))
+ && (to == null || !getElement().isOrHasChild(to))) {
+ if (clickPending
+ && Math.abs(mousedownX - event.getClientX()) < MOVE_THRESHOLD
+ && Math.abs(mousedownY - event.getClientY()) < MOVE_THRESHOLD) {
+ onClick();
+ break;
+ }
+ clickPending = false;
+ if (isCapturing) {
+ }
+ setHovering(false);
+ if (BrowserInfo.get().isIE() || BrowserInfo.get().isOpera()) {
+ removeStyleName(CLASSNAME_PRESSED);
+ }
+ }
+ break;
+ case Event.ONBLUR:
+ if (isFocusing) {
+ isFocusing = false;
+ }
+ break;
+ case Event.ONLOSECAPTURE:
+ if (isCapturing) {
+ isCapturing = false;
+ }
+ break;
+ }
+
+ super.onBrowserEvent(event);
+
+ // Synthesize clicks based on keyboard events AFTER the normal key
+ // handling.
+ if ((event.getTypeInt() & Event.KEYEVENTS) != 0) {
+ switch (type) {
+ case Event.ONKEYDOWN:
+ if (event.getKeyCode() == 32 /* space */) {
+ isFocusing = true;
+ event.preventDefault();
+ }
+ break;
+ case Event.ONKEYUP:
+ if (isFocusing && event.getKeyCode() == 32 /* space */) {
+ isFocusing = false;
+
+ /*
+ * If click shortcut is space then the shortcut handler will
+ * take care of the click.
+ */
+ if (clickShortcut != 32 /* space */) {
+ onClick();
+ }
+
+ event.preventDefault();
+ }
+ break;
+ case Event.ONKEYPRESS:
+ if (event.getKeyCode() == KeyCodes.KEY_ENTER) {
+
+ /*
+ * If click shortcut is enter then the shortcut handler will
+ * take care of the click.
+ */
+ if (clickShortcut != KeyCodes.KEY_ENTER) {
+ onClick();
+ }
+
+ event.preventDefault();
+ }
+ break;
+ }
+ }
+ }
+
+ final void setHovering(boolean hovering) {
+ if (hovering != isHovering()) {
+ isHovering = hovering;
+ }
+ }
+
+ final boolean isHovering() {
+ return isHovering;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event
+ * .dom.client.ClickEvent)
+ */
+ public void onClick(ClickEvent event) {
+ if (BrowserInfo.get().isSafari()) {
+ VButton.this.setFocus(true);
+ }
+
+ clickPending = false;
+ }
+
+ /*
+ * ALL BELOW COPY-PASTED FROM GWT CustomButton
+ */
+
+ /**
+ * Called internally when the user finishes clicking on this button. The
+ * default behavior is to fire the click event to listeners. Subclasses that
+ * override {@link #onClickStart()} should override this method to restore
+ * the normal widget display.
+ * <p>
+ * To add custom code for a click event, override
+ * {@link #onClick(ClickEvent)} instead of this.
+ */
+ protected void onClick() {
+ // Allow the click we're about to synthesize to pass through to the
+ // superclass and containing elements. Element.dispatchEvent() is
+ // synchronous, so we simply set and clear the flag within this method.
+
+ disallowNextClick = false;
+
+ // Mouse coordinates are not always available (e.g., when the click is
+ // caused by a keyboard event).
+ NativeEvent evt = Document.get().createClickEvent(1, 0, 0, 0, 0, false,
+ false, false, false);
+ getElement().dispatchEvent(evt);
+ }
+
+ /**
+ * Sets whether this button is enabled.
+ *
+ * @param enabled
+ * <code>true</code> to enable the button, <code>false</code> to
+ * disable it
+ */
+
+ @Override
+ public final void setEnabled(boolean enabled) {
+ if (isEnabled() != enabled) {
+ this.enabled = enabled;
+ if (!enabled) {
+ cleanupCaptureState();
+ Accessibility.removeState(getElement(),
+ Accessibility.STATE_PRESSED);
+ super.setTabIndex(-1);
+ addStyleName(ApplicationConnection.DISABLED_CLASSNAME);
+ } else {
+ Accessibility.setState(getElement(),
+ Accessibility.STATE_PRESSED, "false");
+ super.setTabIndex(tabIndex);
+ removeStyleName(ApplicationConnection.DISABLED_CLASSNAME);
+ }
+ }
+ }
+
+ @Override
+ public final boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public final void setTabIndex(int index) {
+ super.setTabIndex(index);
+ tabIndex = index;
+ }
+
+ /**
+ * Resets internal state if this button can no longer service events. This
+ * can occur when the widget becomes detached or disabled.
+ */
+ private void cleanupCaptureState() {
+ if (isCapturing || isFocusing) {
+ DOM.releaseCapture(getElement());
+ isCapturing = false;
+ isFocusing = false;
+ }
+ }
+
+ private static native int getHorizontalBorderAndPaddingWidth(Element elem)
+ /*-{
+ // THIS METHOD IS ONLY USED FOR INTERNET EXPLORER, IT DOESN'T WORK WITH OTHERS
+
+ var convertToPixel = function(elem, value) {
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // Remember the original values
+ var left = elem.style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ elem.style.left = value || 0;
+ var ret = elem.style.pixelLeft;
+
+ // Revert the changed values
+ elem.style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+
+ return ret;
+ }
+
+ var ret = 0;
+
+ var sides = ["Right","Left"];
+ for(var i=0; i<2; i++) {
+ var side = sides[i];
+ var value;
+ // Border -------------------------------------------------------
+ if(elem.currentStyle["border"+side+"Style"] != "none") {
+ value = elem.currentStyle["border"+side+"Width"];
+ if ( !/^\d+(px)?$/i.test( value ) && /^\d/.test( value ) ) {
+ ret += convertToPixel(elem, value);
+ } else if(value.length > 2) {
+ ret += parseInt(value.substr(0, value.length-2));
+ }
+ }
+
+ // Padding -------------------------------------------------------
+ value = elem.currentStyle["padding"+side];
+ if ( !/^\d+(px)?$/i.test( value ) && /^\d/.test( value ) ) {
+ ret += convertToPixel(elem, value);
+ } else if(value.length > 2) {
+ ret += parseInt(value.substr(0, value.length-2));
+ }
+ }
+
+ return ret;
+ }-*/;
+
+}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.datefield;
+
+import java.util.Date;
+
+import com.google.gwt.event.dom.client.DomEvent;
+import com.vaadin.terminal.gwt.client.DateTimeService;
+import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.FocusOutListener;
+import com.vaadin.terminal.gwt.client.ui.datefield.VCalendarPanel.SubmitListener;
+
+/**
+ * A client side implementation for InlineDateField
+ */
+public class VDateFieldCalendar extends VDateField {
+
+ protected final VCalendarPanel calendarPanel;
+
+ public VDateFieldCalendar() {
+ super();
+ calendarPanel = new VCalendarPanel();
+ add(calendarPanel);
+ calendarPanel.setSubmitListener(new SubmitListener() {
+ public void onSubmit() {
+ updateValueFromPanel();
+ }
+
+ public void onCancel() {
+ // TODO Auto-generated method stub
+
+ }
+ });
+ calendarPanel.setFocusOutListener(new FocusOutListener() {
+ public boolean onFocusOut(DomEvent<?> event) {
+ updateValueFromPanel();
+ return false;
+ }
+ });
+ }
+
+ /**
+ * TODO refactor: almost same method as in VPopupCalendar.updateValue
+ */
+ @SuppressWarnings("deprecation")
+ protected void updateValueFromPanel() {
++
++ // If field is invisible at the beginning, client can still be null when
++ // this function is called.
++ if (getClient() == null) {
++ return;
++ }
++
+ Date date2 = calendarPanel.getDate();
+ Date currentDate = getCurrentDate();
+ if (currentDate == null || date2.getTime() != currentDate.getTime()) {
+ setCurrentDate((Date) date2.clone());
+ getClient().updateVariable(getId(), "year", date2.getYear() + 1900,
+ false);
+ if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) {
+ getClient().updateVariable(getId(), "month",
+ date2.getMonth() + 1, false);
+ if (getCurrentResolution() > RESOLUTION_MONTH) {
+ getClient().updateVariable(getId(), "day", date2.getDate(),
+ false);
+ if (getCurrentResolution() > RESOLUTION_DAY) {
+ getClient().updateVariable(getId(), "hour",
+ date2.getHours(), false);
+ if (getCurrentResolution() > RESOLUTION_HOUR) {
+ getClient().updateVariable(getId(), "min",
+ date2.getMinutes(), false);
+ if (getCurrentResolution() > RESOLUTION_MIN) {
+ getClient().updateVariable(getId(), "sec",
+ date2.getSeconds(), false);
+ if (getCurrentResolution() > RESOLUTION_SEC) {
+ getClient().updateVariable(
+ getId(),
+ "msec",
+ DateTimeService
+ .getMilliseconds(date2),
+ false);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (isImmediate()) {
+ getClient().sendPendingVariableChanges();
+ }
+ }
+ }
+}
--- /dev/null
- getWidget().setText(getState().getCaption());
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client.ui.nativebutton;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.EventHelper;
+import com.vaadin.terminal.gwt.client.communication.FieldRpc.FocusAndBlurServerRpc;
+import com.vaadin.terminal.gwt.client.communication.RpcProxy;
+import com.vaadin.terminal.gwt.client.communication.StateChangeEvent;
+import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector;
+import com.vaadin.terminal.gwt.client.ui.Connect;
+import com.vaadin.terminal.gwt.client.ui.Icon;
+import com.vaadin.terminal.gwt.client.ui.button.ButtonServerRpc;
+import com.vaadin.terminal.gwt.client.ui.button.ButtonState;
+import com.vaadin.ui.NativeButton;
+
+@Connect(NativeButton.class)
+public class NativeButtonConnector extends AbstractComponentConnector implements
+ BlurHandler, FocusHandler {
+
+ private HandlerRegistration focusHandlerRegistration;
+ private HandlerRegistration blurHandlerRegistration;
+
+ private FocusAndBlurServerRpc focusBlurRpc = RpcProxy.create(
+ FocusAndBlurServerRpc.class, this);
+
+ @Override
+ public void init() {
+ super.init();
+
+ getWidget().buttonRpcProxy = RpcProxy.create(ButtonServerRpc.class,
+ this);
+ getWidget().client = getConnection();
+ getWidget().paintableId = getConnectorId();
+ }
+
+ @Override
+ public boolean delegateCaptionHandling() {
+ return false;
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ getWidget().disableOnClick = getState().isDisableOnClick();
+ focusHandlerRegistration = EventHelper.updateFocusHandler(this,
+ focusHandlerRegistration);
+ blurHandlerRegistration = EventHelper.updateBlurHandler(this,
+ blurHandlerRegistration);
+
+ // Set text
++ if (getState().isHtmlContentAllowed()) {
++ getWidget().setHTML(getState().getCaption());
++ } else {
++ getWidget().setText(getState().getCaption());
++ }
+
+ // handle error
+ if (null != getState().getErrorMessage()) {
+ if (getWidget().errorIndicatorElement == null) {
+ getWidget().errorIndicatorElement = DOM.createSpan();
+ getWidget().errorIndicatorElement
+ .setClassName("v-errorindicator");
+ }
+ getWidget().getElement().insertBefore(
+ getWidget().errorIndicatorElement,
+ getWidget().captionElement);
+
+ } else if (getWidget().errorIndicatorElement != null) {
+ getWidget().getElement().removeChild(
+ getWidget().errorIndicatorElement);
+ getWidget().errorIndicatorElement = null;
+ }
+
+ if (getState().getIcon() != null) {
+ if (getWidget().icon == null) {
+ getWidget().icon = new Icon(getConnection());
+ getWidget().getElement().insertBefore(
+ getWidget().icon.getElement(),
+ getWidget().captionElement);
+ }
+ getWidget().icon.setUri(getState().getIcon().getURL());
+ } else {
+ if (getWidget().icon != null) {
+ getWidget().getElement().removeChild(
+ getWidget().icon.getElement());
+ getWidget().icon = null;
+ }
+ }
+
+ }
+
+ @Override
+ protected Widget createWidget() {
+ return GWT.create(VNativeButton.class);
+ }
+
+ @Override
+ public VNativeButton getWidget() {
+ return (VNativeButton) super.getWidget();
+ }
+
+ @Override
+ public ButtonState getState() {
+ return (ButtonState) super.getState();
+ }
+
+ public void onFocus(FocusEvent event) {
+ // EventHelper.updateFocusHandler ensures that this is called only when
+ // there is a listener on server side
+ focusBlurRpc.focus();
+ }
+
+ public void onBlur(BlurEvent event) {
+ // EventHelper.updateFocusHandler ensures that this is called only when
+ // there is a listener on server side
+ focusBlurRpc.blur();
+ }
+
+}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.nativebutton;
+
+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.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.MouseEventDetails;
+import com.vaadin.terminal.gwt.client.MouseEventDetailsBuilder;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.ui.Icon;
+import com.vaadin.terminal.gwt.client.ui.button.ButtonServerRpc;
+
+public class VNativeButton extends Button implements ClickHandler {
+
+ public static final String CLASSNAME = "v-nativebutton";
+
+ protected String width = null;
+
+ protected String paintableId;
+
+ protected ApplicationConnection client;
+
+ ButtonServerRpc buttonRpcProxy;
+
+ protected Element errorIndicatorElement;
+
+ protected final Element captionElement = DOM.createSpan();
+
+ protected Icon icon;
+
+ /**
+ * Helper flag to handle special-case where the button is moved from under
+ * mouse while clicking it. In this case mouse leaves the button without
+ * moving.
+ */
+ private boolean clickPending;
+
+ protected boolean disableOnClick = false;
+
+ public VNativeButton() {
+ setStyleName(CLASSNAME);
+
+ getElement().appendChild(captionElement);
+ captionElement.setClassName(getStyleName() + "-caption");
+
+ addClickHandler(this);
+
+ sinkEvents(VTooltip.TOOLTIP_EVENTS);
+ sinkEvents(Event.ONMOUSEDOWN);
+ sinkEvents(Event.ONMOUSEUP);
+ }
+
+ @Override
+ public void setText(String text) {
+ captionElement.setInnerText(text);
+ }
+
++ @Override
++ public void setHTML(String html) {
++ captionElement.setInnerHTML(html);
++ }
++
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+
+ if (DOM.eventGetType(event) == Event.ONLOAD) {
+ Util.notifyParentOfSizeChange(this, true);
+
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN
+ && event.getButton() == Event.BUTTON_LEFT) {
+ clickPending = true;
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) {
+ clickPending = false;
+ } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
+ if (clickPending) {
+ click();
+ }
+ clickPending = false;
+ }
+
+ if (client != null) {
+ client.handleTooltipEvent(event, this);
+ }
+ }
+
+ @Override
+ public void setWidth(String width) {
+ this.width = width;
+ super.setWidth(width);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event
+ * .dom.client.ClickEvent)
+ */
+ public void onClick(ClickEvent event) {
+ if (paintableId == null || client == null) {
+ return;
+ }
+
+ if (BrowserInfo.get().isSafari()) {
+ VNativeButton.this.setFocus(true);
+ }
+ if (disableOnClick) {
+ setEnabled(false);
+ buttonRpcProxy.disableOnClick();
+ }
+
+ // Add mouse details
+ MouseEventDetails details = MouseEventDetailsBuilder
+ .buildMouseEventDetails(event.getNativeEvent(), getElement());
+ buttonRpcProxy.click(details);
+
+ clickPending = false;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ if (isEnabled() != enabled) {
+ super.setEnabled(enabled);
+ setStyleName(ApplicationConnection.DISABLED_CLASSNAME, !enabled);
+ }
+ }
+}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.notification;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.EventObject;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.VOverlay;
+import com.vaadin.terminal.gwt.client.ui.root.VRoot;
+
+public class VNotification extends VOverlay {
+
+ public static final int CENTERED = 1;
+ public static final int CENTERED_TOP = 2;
+ public static final int CENTERED_BOTTOM = 3;
+ public static final int TOP_LEFT = 4;
+ public static final int TOP_RIGHT = 5;
+ public static final int BOTTOM_LEFT = 6;
+ public static final int BOTTOM_RIGHT = 7;
+
+ public static final int DELAY_FOREVER = -1;
+ public static final int DELAY_NONE = 0;
+
+ private static final String STYLENAME = "v-Notification";
+ private static final int mouseMoveThreshold = 7;
+ private static final int Z_INDEX_BASE = 20000;
+ public static final String STYLE_SYSTEM = "system";
+ private static final int FADE_ANIMATION_INTERVAL = 50; // == 20 fps
+
+ private int startOpacity = 90;
+ private int fadeMsec = 400;
+ private int delayMsec = 1000;
+
+ private Timer fader;
+ private Timer delay;
+
+ private int x = -1;
+ private int y = -1;
+
+ private String temporaryStyle;
+
+ private ArrayList<EventListener> listeners;
+ private static final int TOUCH_DEVICE_IDLE_DELAY = 1000;
+
+ public static final String ATTRIBUTE_NOTIFICATION_STYLE = "style";
+ public static final String ATTRIBUTE_NOTIFICATION_CAPTION = "caption";
+ public static final String ATTRIBUTE_NOTIFICATION_MESSAGE = "message";
+ public static final String ATTRIBUTE_NOTIFICATION_ICON = "icon";
+ public static final String ATTRIBUTE_NOTIFICATION_POSITION = "position";
+ public static final String ATTRIBUTE_NOTIFICATION_DELAY = "delay";
+
+ /**
+ * Default constructor. You should use GWT.create instead.
+ */
+ public VNotification() {
+ setStyleName(STYLENAME);
+ sinkEvents(Event.ONCLICK);
+ DOM.setStyleAttribute(getElement(), "zIndex", "" + Z_INDEX_BASE);
+ }
+
+ /**
+ * @deprecated Use static {@link #createNotification(int)} instead to enable
+ * GWT deferred binding.
+ *
+ * @param delayMsec
+ */
+ @Deprecated
+ public VNotification(int delayMsec) {
+ this();
+ this.delayMsec = delayMsec;
+ if (BrowserInfo.get().isTouchDevice()) {
+ new Timer() {
+ @Override
+ public void run() {
+ if (isAttached()) {
+ fade();
+ }
+ }
+ }.schedule(delayMsec + TOUCH_DEVICE_IDLE_DELAY);
+ }
+ }
+
+ /**
+ * @deprecated Use static {@link #createNotification(int, int, int)} instead
+ * to enable GWT deferred binding.
+ *
+ * @param delayMsec
+ * @param fadeMsec
+ * @param startOpacity
+ */
+ @Deprecated
+ public VNotification(int delayMsec, int fadeMsec, int startOpacity) {
+ this(delayMsec);
+ this.fadeMsec = fadeMsec;
+ this.startOpacity = startOpacity;
+ }
+
+ public void startDelay() {
+ DOM.removeEventPreview(this);
+ if (delayMsec > 0) {
+ if (delay == null) {
+ delay = new Timer() {
+ @Override
+ public void run() {
+ fade();
+ }
+ };
+ delay.schedule(delayMsec);
+ }
+ } else if (delayMsec == 0) {
+ fade();
+ }
+ }
+
+ @Override
+ public void show() {
+ show(CENTERED);
+ }
+
+ public void show(String style) {
+ show(CENTERED, style);
+ }
+
+ public void show(int position) {
+ show(position, null);
+ }
+
+ public void show(Widget widget, int position, String style) {
+ setWidget(widget);
+ show(position, style);
+ }
+
+ public void show(String html, int position, String style) {
+ setWidget(new HTML(html));
+ show(position, style);
+ }
+
+ public void show(int position, String style) {
+ setOpacity(getElement(), startOpacity);
+ if (style != null) {
+ temporaryStyle = style;
+ addStyleName(style);
+ addStyleDependentName(style);
+ }
+ super.show();
+ setPosition(position);
++ /**
++ * Android 4 fails to render notifications correctly without a little
++ * nudge (#8551)
++ */
++ if (BrowserInfo.get().isAndroid()) {
++ Util.setStyleTemporarily(getElement(), "display", "none");
++ }
+ }
+
+ @Override
+ public void hide() {
+ DOM.removeEventPreview(this);
+ cancelDelay();
+ cancelFade();
+ if (temporaryStyle != null) {
+ removeStyleName(temporaryStyle);
+ removeStyleDependentName(temporaryStyle);
+ temporaryStyle = null;
+ }
+ super.hide();
+ fireEvent(new HideEvent(this));
+ }
+
+ public void fade() {
+ DOM.removeEventPreview(this);
+ cancelDelay();
+ if (fader == null) {
+ fader = new Timer() {
+ private final long start = new Date().getTime();
+
+ @Override
+ public void run() {
+ /*
+ * To make animation smooth, don't count that event happens
+ * on time. Reduce opacity according to the actual time
+ * spent instead of fixed decrement.
+ */
+ long now = new Date().getTime();
+ long timeEplaced = now - start;
+ float remainingFraction = 1 - timeEplaced
+ / (float) fadeMsec;
+ int opacity = (int) (startOpacity * remainingFraction);
+ if (opacity <= 0) {
+ cancel();
+ hide();
+ if (BrowserInfo.get().isOpera()) {
+ // tray notification on opera needs to explicitly
+ // define
+ // size, reset it
+ DOM.setStyleAttribute(getElement(), "width", "");
+ DOM.setStyleAttribute(getElement(), "height", "");
+ }
+ } else {
+ setOpacity(getElement(), opacity);
+ }
+ }
+ };
+ fader.scheduleRepeating(FADE_ANIMATION_INTERVAL);
+ }
+ }
+
+ public void setPosition(int position) {
+ final Element el = getElement();
+ DOM.setStyleAttribute(el, "top", "");
+ DOM.setStyleAttribute(el, "left", "");
+ DOM.setStyleAttribute(el, "bottom", "");
+ DOM.setStyleAttribute(el, "right", "");
+ switch (position) {
+ case TOP_LEFT:
+ DOM.setStyleAttribute(el, "top", "0px");
+ DOM.setStyleAttribute(el, "left", "0px");
+ break;
+ case TOP_RIGHT:
+ DOM.setStyleAttribute(el, "top", "0px");
+ DOM.setStyleAttribute(el, "right", "0px");
+ break;
+ case BOTTOM_RIGHT:
+ DOM.setStyleAttribute(el, "position", "absolute");
+ if (BrowserInfo.get().isOpera()) {
+ // tray notification on opera needs explicitly defined size
+ DOM.setStyleAttribute(el, "width", getOffsetWidth() + "px");
+ DOM.setStyleAttribute(el, "height", getOffsetHeight() + "px");
+ }
+ DOM.setStyleAttribute(el, "bottom", "0px");
+ DOM.setStyleAttribute(el, "right", "0px");
+ break;
+ case BOTTOM_LEFT:
+ DOM.setStyleAttribute(el, "bottom", "0px");
+ DOM.setStyleAttribute(el, "left", "0px");
+ break;
+ case CENTERED_TOP:
+ center();
+ DOM.setStyleAttribute(el, "top", "0px");
+ break;
+ case CENTERED_BOTTOM:
+ center();
+ DOM.setStyleAttribute(el, "top", "");
+ DOM.setStyleAttribute(el, "bottom", "0px");
+ break;
+ default:
+ case CENTERED:
+ center();
+ break;
+ }
+ }
+
+ private void cancelFade() {
+ if (fader != null) {
+ fader.cancel();
+ fader = null;
+ }
+ }
+
+ private void cancelDelay() {
+ if (delay != null) {
+ delay.cancel();
+ delay = null;
+ }
+ }
+
+ private void setOpacity(Element el, int opacity) {
+ DOM.setStyleAttribute(el, "opacity", "" + (opacity / 100.0));
+ if (BrowserInfo.get().isIE()) {
+ DOM.setStyleAttribute(el, "filter", "Alpha(opacity=" + opacity
+ + ")");
+ }
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ DOM.removeEventPreview(this);
+ if (fader == null) {
+ fade();
+ }
+ }
+
+ @Override
+ public boolean onEventPreview(Event event) {
+ int type = DOM.eventGetType(event);
+ // "modal"
+ if (delayMsec == -1 || temporaryStyle == STYLE_SYSTEM) {
+ if (type == Event.ONCLICK) {
+ if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) {
+ fade();
+ return false;
+ }
+ } else if (type == Event.ONKEYDOWN
+ && event.getKeyCode() == KeyCodes.KEY_ESCAPE) {
+ fade();
+ return false;
+ }
+ if (temporaryStyle == STYLE_SYSTEM) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // default
+ switch (type) {
+ case Event.ONMOUSEMOVE:
+
+ if (x < 0) {
+ x = DOM.eventGetClientX(event);
+ y = DOM.eventGetClientY(event);
+ } else if (Math.abs(DOM.eventGetClientX(event) - x) > mouseMoveThreshold
+ || Math.abs(DOM.eventGetClientY(event) - y) > mouseMoveThreshold) {
+ startDelay();
+ }
+ break;
+ case Event.ONMOUSEDOWN:
+ case Event.ONMOUSEWHEEL:
+ case Event.ONSCROLL:
+ startDelay();
+ break;
+ case Event.ONKEYDOWN:
+ if (event.getRepeat()) {
+ return true;
+ }
+ startDelay();
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ public void addEventListener(EventListener listener) {
+ if (listeners == null) {
+ listeners = new ArrayList<EventListener>();
+ }
+ listeners.add(listener);
+ }
+
+ public void removeEventListener(EventListener listener) {
+ if (listeners == null) {
+ return;
+ }
+ listeners.remove(listener);
+ }
+
+ private void fireEvent(HideEvent event) {
+ if (listeners != null) {
+ for (Iterator<EventListener> it = listeners.iterator(); it
+ .hasNext();) {
+ EventListener l = it.next();
+ l.notificationHidden(event);
+ }
+ }
+ }
+
+ public static void showNotification(ApplicationConnection client,
+ final UIDL notification) {
+ boolean onlyPlainText = notification
+ .hasAttribute(VRoot.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED);
+ String html = "";
+ if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_ICON)) {
+ final String parsedUri = client.translateVaadinUri(notification
+ .getStringAttribute(ATTRIBUTE_NOTIFICATION_ICON));
+ html += "<img src=\"" + Util.escapeAttribute(parsedUri) + "\" />";
+ }
+ if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_CAPTION)) {
+ String caption = notification
+ .getStringAttribute(ATTRIBUTE_NOTIFICATION_CAPTION);
+ if (onlyPlainText) {
+ caption = Util.escapeHTML(caption);
+ caption = caption.replaceAll("\\n", "<br />");
+ }
+ html += "<h1>" + caption + "</h1>";
+ }
+ if (notification.hasAttribute(ATTRIBUTE_NOTIFICATION_MESSAGE)) {
+ String message = notification
+ .getStringAttribute(ATTRIBUTE_NOTIFICATION_MESSAGE);
+ if (onlyPlainText) {
+ message = Util.escapeHTML(message);
+ message = message.replaceAll("\\n", "<br />");
+ }
+ html += "<p>" + message + "</p>";
+ }
+
+ final String style = notification
+ .hasAttribute(ATTRIBUTE_NOTIFICATION_STYLE) ? notification
+ .getStringAttribute(ATTRIBUTE_NOTIFICATION_STYLE) : null;
+ final int position = notification
+ .getIntAttribute(ATTRIBUTE_NOTIFICATION_POSITION);
+ final int delay = notification
+ .getIntAttribute(ATTRIBUTE_NOTIFICATION_DELAY);
+ createNotification(delay).show(html, position, style);
+ }
+
+ public static VNotification createNotification(int delayMsec) {
+ final VNotification notification = GWT.create(VNotification.class);
+ notification.delayMsec = delayMsec;
+ if (BrowserInfo.get().isTouchDevice()) {
+ new Timer() {
+ @Override
+ public void run() {
+ if (notification.isAttached()) {
+ notification.fade();
+ }
+ }
+ }.schedule(notification.delayMsec + TOUCH_DEVICE_IDLE_DELAY);
+ }
+ return notification;
+ }
+
+ public class HideEvent extends EventObject {
+
+ public HideEvent(Object source) {
+ super(source);
+ }
+ }
+
+ public interface EventListener extends java.util.EventListener {
+ public void notificationHidden(HideEvent event);
+ }
+}
--- /dev/null
+/*
+@VaadinApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.root;
+
+import java.util.ArrayList;
+
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.event.logical.shared.ResizeEvent;
+import com.google.gwt.event.logical.shared.ResizeHandler;
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.event.shared.HandlerRegistration;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.ComponentConnector;
+import com.vaadin.terminal.gwt.client.ConnectorMap;
+import com.vaadin.terminal.gwt.client.Focusable;
+import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler;
+import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
+import com.vaadin.terminal.gwt.client.ui.VLazyExecutor;
+import com.vaadin.terminal.gwt.client.ui.textfield.VTextField;
+
+/**
+ *
+ */
+public class VRoot extends SimplePanel implements ResizeHandler,
+ Window.ClosingHandler, ShortcutActionHandlerOwner, Focusable {
+
+ public static final String FRAGMENT_VARIABLE = "fragment";
+
+ private static final String CLASSNAME = "v-view";
+
+ public static final String NOTIFICATION_HTML_CONTENT_NOT_ALLOWED = "useplain";
+
+ String theme;
+
+ String id;
+
+ ShortcutActionHandler actionHandler;
+
+ /** stored width for IE resize optimization */
+ private int width;
+
+ /** stored height for IE resize optimization */
+ private int height;
+
+ ApplicationConnection connection;
+
+ /** Identifies the click event */
+ public static final String CLICK_EVENT_ID = "click";
+
+ /**
+ * We are postponing resize process with IE. IE bugs with scrollbars in some
+ * situations, that causes false onWindowResized calls. With Timer we will
+ * give IE some time to decide if it really wants to keep current size
+ * (scrollbars).
+ */
+ private Timer resizeTimer;
+
+ int scrollTop;
+
+ int scrollLeft;
+
+ boolean rendering;
+
+ boolean scrollable;
+
+ boolean immediate;
+
+ boolean resizeLazy = false;
+
+ /**
+ * Attribute name for the lazy resize setting .
+ */
+ public static final String RESIZE_LAZY = "rL";
+
+ private HandlerRegistration historyHandlerRegistration;
+
+ /**
+ * The current URI fragment, used to avoid sending updates if nothing has
+ * changed.
+ */
+ String currentFragment;
+
+ /**
+ * Listener for URI fragment changes. Notifies the server of the new value
+ * whenever the value changes.
+ */
+ private final ValueChangeHandler<String> historyChangeHandler = new ValueChangeHandler<String>() {
+ public void onValueChange(ValueChangeEvent<String> event) {
+ String newFragment = event.getValue();
+
+ // Send the new fragment to the server if it has changed
+ if (!newFragment.equals(currentFragment) && connection != null) {
+ currentFragment = newFragment;
+ connection.updateVariable(id, FRAGMENT_VARIABLE, newFragment,
+ true);
+ }
+ }
+ };
+
+ private VLazyExecutor delayedResizeExecutor = new VLazyExecutor(200,
+ new ScheduledCommand() {
+ public void execute() {
+ windowSizeMaybeChanged(Window.getClientWidth(),
+ Window.getClientHeight());
+ }
+
+ });
+
+ public VRoot() {
+ super();
+ setStyleName(CLASSNAME);
+
+ // Allow focusing the view by using the focus() method, the view
+ // should not be in the document focus flow
+ getElement().setTabIndex(-1);
+ }
+
+ @Override
+ protected void onAttach() {
+ super.onAttach();
+ historyHandlerRegistration = History
+ .addValueChangeHandler(historyChangeHandler);
+ currentFragment = History.getToken();
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+ historyHandlerRegistration.removeHandler();
+ historyHandlerRegistration = null;
+ }
+
+ /**
+ * Called when the window might have been resized.
+ *
+ * @param newWidth
+ * The new width of the window
+ * @param newHeight
+ * The new height of the window
+ */
+ protected void windowSizeMaybeChanged(int newWidth, int newHeight) {
+ boolean changed = false;
+ ComponentConnector connector = ConnectorMap.get(connection)
+ .getConnector(this);
+ if (width != newWidth) {
+ width = newWidth;
+ changed = true;
+ connector.getLayoutManager().reportOuterWidth(connector, newWidth);
+ VConsole.log("New window width: " + width);
+ }
+ if (height != newHeight) {
+ height = newHeight;
+ changed = true;
+ connector.getLayoutManager()
+ .reportOuterHeight(connector, newHeight);
+ VConsole.log("New window height: " + height);
+ }
+ if (changed) {
+ VConsole.log("Running layout functions due to window resize");
+
+ sendClientResized();
+
+ connector.getLayoutManager().layoutNow();
+ }
+ }
+
+ public String getTheme() {
+ return theme;
+ }
+
+ /**
+ * Used to reload host page on theme changes.
+ */
+ static native void reloadHostPage()
+ /*-{
+ $wnd.location.reload();
+ }-*/;
+
+ /**
+ * Evaluate the given script in the browser document.
+ *
+ * @param script
+ * Script to be executed.
+ */
+ static native void eval(String script)
+ /*-{
+ try {
+ if (script == null) return;
+ $wnd.eval(script);
+ } catch (e) {
+ }
+ }-*/;
+
+ /**
+ * Returns true if the body is NOT generated, i.e if someone else has made
+ * the page that we're running in. Otherwise we're in charge of the whole
+ * page.
+ *
+ * @return true if we're running embedded
+ */
+ public boolean isEmbedded() {
+ return !getElement().getOwnerDocument().getBody().getClassName()
+ .contains(ApplicationConnection.GENERATED_BODY_CLASSNAME);
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+ int type = DOM.eventGetType(event);
+ if (type == Event.ONKEYDOWN && actionHandler != null) {
+ actionHandler.handleKeyboardEvent(event);
+ return;
+ } else if (scrollable && type == Event.ONSCROLL) {
+ updateScrollPosition();
+ }
+ }
+
+ /**
+ * Updates scroll position from DOM and saves variables to server.
+ */
+ private void updateScrollPosition() {
+ int oldTop = scrollTop;
+ int oldLeft = scrollLeft;
+ scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
+ scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
+ if (connection != null && !rendering) {
+ if (oldTop != scrollTop) {
+ connection.updateVariable(id, "scrollTop", scrollTop, false);
+ }
+ if (oldLeft != scrollLeft) {
+ connection.updateVariable(id, "scrollLeft", scrollLeft, false);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.logical.shared.ResizeHandler#onResize(com.google
+ * .gwt.event.logical.shared.ResizeEvent)
+ */
+ public void onResize(ResizeEvent event) {
+ onResize();
+ }
+
+ /**
+ * Called when a resize event is received.
+ */
+ void onResize() {
+ /*
+ * IE (pre IE9 at least) will give us some false resize events due to
+ * problems with scrollbars. Firefox 3 might also produce some extra
+ * events. We postpone both the re-layouting and the server side event
+ * for a while to deal with these issues.
+ *
+ * We may also postpone these events to avoid slowness when resizing the
+ * browser window. Constantly recalculating the layout causes the resize
+ * operation to be really slow with complex layouts.
+ */
+ boolean lazy = resizeLazy || BrowserInfo.get().isIE8();
+
+ if (lazy) {
+ delayedResizeExecutor.trigger();
+ } else {
+ windowSizeMaybeChanged(Window.getClientWidth(),
+ Window.getClientHeight());
+ }
+ }
+
+ /**
+ * Send new dimensions to the server.
+ */
+ private void sendClientResized() {
+ connection.updateVariable(id, "height", height, false);
+ connection.updateVariable(id, "width", width, immediate);
+ }
+
+ public native static void goTo(String url)
+ /*-{
+ $wnd.location = url;
+ }-*/;
+
+ public void onWindowClosing(Window.ClosingEvent event) {
+ // Change focus on this window in order to ensure that all state is
+ // collected from textfields
+ // TODO this is a naive hack, that only works with text fields and may
+ // cause some odd issues. Should be replaced with a decent solution, see
+ // also related BeforeShortcutActionListener interface. Same interface
+ // might be usable here.
+ VTextField.flushChangesFromFocusedTextField();
+ }
+
+ private native static void loadAppIdListFromDOM(ArrayList<String> list)
+ /*-{
+ var j;
+ for(j in $wnd.vaadin.vaadinConfigurations) {
++ // $entry not needed as function is not exported
+ list.@java.util.Collection::add(Ljava/lang/Object;)(j);
+ }
+ }-*/;
+
+ public ShortcutActionHandler getShortcutActionHandler() {
+ return actionHandler;
+ }
+
+ public void focus() {
+ getElement().focus();
+ }
+
+}
protected void handleRequest(PortletRequest request,
PortletResponse response) throws PortletException, IOException {
- RequestTimer requestTimer = RequestTimer.get(wrappedRequest);
- requestTimer.start(wrappedRequest);
-
+ RequestTimer requestTimer = new RequestTimer();
+ requestTimer.start();
+
+ AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper(
+ this);
+
+ WrappedPortletRequest wrappedRequest;
+
+ String portalInfo = request.getPortalContext().getPortalInfo()
+ .toLowerCase();
+ if (portalInfo.contains("liferay")) {
+ wrappedRequest = new WrappedLiferayRequest(request,
+ getDeploymentConfiguration());
+ } else if (portalInfo.contains("gatein")) {
+ wrappedRequest = new WrappedGateinRequest(request,
+ getDeploymentConfiguration());
+ } else {
+ wrappedRequest = new WrappedPortletRequest(request,
+ getDeploymentConfiguration());
+ }
+
+ WrappedPortletResponse wrappedResponse = new WrappedPortletResponse(
+ response, getDeploymentConfiguration());
+
RequestType requestType = getRequestType(request);
if (requestType == RequestType.UNKNOWN) {
}
} finally {
- }
+ Root.setCurrentRoot(null);
+ Application.setCurrentApplication(null);
- requestTimer.stop();
- RequestTimer.set(wrappedRequest, requestTimer);
+
+ requestTimer
+ .stop((AbstractWebApplicationContext) application
+ .getContext());
+ }
}
}
}
@Override
protected void service(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
- RequestTimer requestTimer = RequestTimer.get(request);
- requestTimer.start(request);
-
+ service(createWrappedRequest(request), createWrappedResponse(response));
+ }
+
+ private void service(WrappedHttpServletRequest request,
+ WrappedHttpServletResponse response) throws ServletException,
+ IOException {
+ RequestTimer requestTimer = new RequestTimer();
+ requestTimer.start();
+
+ AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper(
+ this);
+
RequestType requestType = getRequestType(request);
if (!ensureCookiesEnabled(requestType, request, response)) {
return;
.onRequestEnd(request, response);
}
} finally {
- }
+ Root.setCurrentRoot(null);
+ Application.setCurrentApplication(null);
- requestTimer.stop();
- RequestTimer.set(request, requestTimer);
+
+ requestTimer
+ .stop((AbstractWebApplicationContext) application
+ .getContext());
+ }
}
}
}
/**
- * Adds the performance timing data used by TestBench 3 to the UIDL
+ * Adds the performance timing data (used by TestBench 3) to the UIDL
* response.
*/
- private void writePerformanceDataForTestBench(final WrappedRequest request,
- final PrintWriter outWriter) {
- Long totalTime = (Long) request.getAttribute("TOTAL");
- Long lastRequestTime = (Long) request.getAttribute("LASTREQUEST");
- outWriter.write(String.format(", \"tbss\":[%d, %d]", totalTime,
- lastRequestTime));
+ private void writePerformanceData(final PrintWriter outWriter) {
+ AbstractWebApplicationContext ctx = (AbstractWebApplicationContext) application
+ .getContext();
+ outWriter.write(String.format(", \"timings\":[%d, %d]",
+ ctx.getTotalSessionTime(), ctx.getLastRequestTime()));
}
+ private void legacyPaint(PaintTarget paintTarget,
+ ArrayList<ClientConnector> dirtyVisibleConnectors)
+ throws PaintException {
+ List<Vaadin6Component> legacyComponents = new ArrayList<Vaadin6Component>();
+ for (Connector connector : dirtyVisibleConnectors) {
+ // All Components that want to use paintContent must implement
+ // Vaadin6Component
+ if (connector instanceof Vaadin6Component) {
+ legacyComponents.add((Vaadin6Component) connector);
+ }
+ }
+ sortByHierarchy((List) legacyComponents);
+ for (Vaadin6Component c : legacyComponents) {
+ logger.fine("Painting Vaadin6Component " + 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>() {
+ 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(Root root) {
+ Integer rootId = Integer.valueOf(root.getRootId());
+ ClientCache cache = rootToClientCache.get(rootId);
+ if (cache == null) {
+ cache = new ClientCache();
+ rootToClientCache.put(rootId, cache);
+ }
+ return cache;
+ }
+
+ /**
+ * Checks if the component is visible in context, i.e. returns false if the
+ * child is hidden, the parent is hidden or the parent says the child should
+ * not be rendered (using
+ * {@link HasComponents#isComponentVisible(Component)}
+ *
+ * @param child
+ * The child to check
+ * @return true if the child is visible to the client, false otherwise
+ */
+ static boolean isVisible(Component child) {
+ HasComponents parent = child.getParent();
+ if (parent == null || !child.isVisible()) {
+ return child.isVisible();
+ }
+
+ return parent.isComponentVisible(child) && isVisible(parent);
+ }
+
+ private static class NullIterator<E> implements Iterator<E> {
+
+ public boolean hasNext() {
+ return false;
+ }
+
+ public E next() {
+ return null;
+ }
+
+ public void remove() {
+ }
+
+ }
+
+ public static Iterable<Component> getChildComponents(HasComponents cc) {
+ // TODO This must be moved to Root/Panel
+ if (cc instanceof Root) {
+ Root root = (Root) cc;
+ List<Component> children = new ArrayList<Component>();
+ if (root.getContent() != null) {
+ children.add(root.getContent());
+ }
+ for (Window w : root.getWindows()) {
+ children.add(w);
+ }
+ return children;
+ } else if (cc instanceof Panel) {
+ // This is so wrong.. (#2924)
+ if (((Panel) cc).getContent() == null) {
+ return Collections.emptyList();
+ } else {
+ return Collections.singleton((Component) ((Panel) cc)
+ .getContent());
+ }
+ }
+ return cc;
+ }
+
+ /**
+ * 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(Root root,
+ String themeName, String resource);
+
private int getTimeoutInterval() {
return maxInactiveInterval;
}
// Measure and store the total handling time. This data can be
// used in TestBench 3 tests.
long time = (System.nanoTime() - requestStartTime) / 1000000;
- lastRequestTime = time;
- totalSessionTime += time;
- }
-
- /**
- * Returns a valid request timer for the specified request. Timers are
- * session bound.
- *
- * @param request
- * the request for which to get a valid timer.
- * @return a valid timer.
- */
- public static RequestTimer get(WrappedRequest request) {
- RequestTimer timer = (RequestTimer) request
- .getSessionAttribute(SESSION_ATTR_ID);
- if (timer == null) {
- timer = new RequestTimer();
- }
- return timer;
- }
+
- /**
- * Associates the specified request timer with the specified request. Since
- * {@link #get(RequestWrapper)} will, at one point or another, return a new
- * instance, this method should be called to keep the request <-> timer
- * association updated.
- *
- * @param request
- * the request for which to set the timer.
- * @param requestTimer
- * the timer.
- */
- public static void set(WrappedRequest request, RequestTimer requestTimer) {
- request.setSessionAttribute(RequestTimer.SESSION_ATTR_ID, requestTimer);
+ // The timings must be stored in the context, since a new
+ // RequestTimer is created for every request.
+ context.setLastRequestTime(time);
}
}
requestRepaint();
}
- if (this.htmlContentAllowed != htmlContentAllowed) {
- this.htmlContentAllowed = htmlContentAllowed;
+ public int getTabIndex() {
+ return tabIndex;
+ }
+
+ public void setTabIndex(int tabIndex) {
+ this.tabIndex = tabIndex;
+
+ }
+
+ @Override
+ public void focus() {
+ // Overridden only to make public
+ super.focus();
+ }
+
+ @Override
+ public ButtonState getState() {
+ return (ButtonState) super.getState();
+ }
+
+ /**
+ * 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.
+ *
+ * If set to true, the captions are passed to the browser as html and the
+ * developer is responsible for ensuring no harmful html is used. If set to
+ * false, the content is passed to the browser as plain text.
+ *
+ * @param htmlContentAllowed
+ * <code>true</code> if caption is rendered as HTML,
+ * <code>false</code> otherwise
+ */
+ public void setHtmlContentAllowed(boolean htmlContentAllowed) {
- return htmlContentAllowed;
++ if (getState().isHtmlContentAllowed() != htmlContentAllowed) {
++ getState().setHtmlContentAllowed(htmlContentAllowed);
+ requestRepaint();
+ }
+ }
+
+ /**
+ * Return HTML rendering setting
+ *
+ * @return <code>true</code> if the caption text is to be rendered as HTML,
+ * <code>false</code> otherwise
+ */
+ public boolean isHtmlContentAllowed() {
++ return getState().isHtmlContentAllowed();
+ }
+
}
<!-- Configuration -->
<!-- ================================================================== -->
<!-- Browsers to use for testing -->
- <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox11,winxp-safari5,winxp-googlechrome18,winxp-opera11" />
- <property name="browsers-windows" value="winxp-ie6,winxp-ie7,winxp-ie8,win7-ie9,winxp-firefox36,winxp-firefox12,winxp-safari4,winxp-safari5,winxp-googlechrome13,winxp-googlechrome18,winxp-opera1060,winxp-opera11" />
++ <property name="browsers-windows" value="winxp-ie8,win7-ie9,winxp-firefox12,winxp-safari5,winxp-googlechrome18,winxp-opera11" />
<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" />
@Override
public void setup() {
- testSelector = new HorizontalLayout();
getLayout().addComponent(testSelector);
+ testSelector.setHeight("500px");
- getLayout().getWindow(),
+ addTest(getPanelTest());
+ addTest(getSimpleTableTest());
+ addTest(getDDSortableTableTest());
+ addTest(getTabSheetTest());
+ addTest(getSplitPanelTest());
+ addTest(getAccordionTest());
+ addTest(getSubWindowTest());
+
+ TestUtils
+ .injectCSS(
- p.setScrollable(true);
++ getLayout().getRoot(),
+ "body * {-webkit-user-select: none;} .v-table-row-drag-middle .v-table-cell-content {"
+ + " background-color: inherit ; border-bottom: 1px solid cyan;"
+ + "}"
+ + ".v-table-row-drag-middle .v-table-cell-wrapper {"
+ + " margin-bottom: -1px;" + "}" + ""
+
+ );
+ }
+
+ private Component getPanelTest() {
+ Layout cssLayout = new CssLayout();
+ cssLayout.setCaption("Panel");
+
+ final Panel p = new Panel();
- getLayout().getWindow().scrollIntoView(l);
+ p.setHeight("400px");
+ Label l50 = null;
+ for (int i = 0; i < 100; i++) {
+ Label c = new Label("Label" + i);
+ p.addComponent(c);
+ if (i == 50) {
+ l50 = c;
+ }
+ }
+
+ final Label l = l50;
+ Button button = new Button("Scroll to label 50",
+ new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
++ getLayout().getRoot().scrollIntoView(l);
+ }
+ });
+ cssLayout.addComponent(button);
+ button = new Button("Scroll to 100px", new Button.ClickListener() {
+ public void buttonClick(ClickEvent event) {
+ p.setScrollTop(100);
+ }
+ });
+ cssLayout.addComponent(button);
+ cssLayout.addComponent(p);
+ return cssLayout;
+ }
+
+ private Component getTabSheetTest() {
+ TabSheet ts = new TabSheet();
+ ts.setCaption("Tabsheet");
+ ts.setHeight("100%");
+ ts.addTab(getBigComponent(), "Tab 1");
+ ts.addTab(getBigComponent(), "Tab 2");
+ return ts;
+ }
+
+ private Component getSplitPanelTest() {
+ HorizontalSplitPanel sp = new HorizontalSplitPanel();
+ sp.setCaption("Splitpanel");
+ sp.addComponent(getBigComponent());
+ sp.addComponent(getBigComponent());
+ return sp;
+ }
+
+ private Component getSimpleTableTest() {
CssLayout cssLayout = new CssLayout();
final Table table = new Table();
--- /dev/null
-import com.vaadin.tests.components.TestBase;
+ package com.vaadin.tests.components.combobox;
+
-import com.vaadin.ui.Window;
++import com.vaadin.tests.components.AbstractTestCase;
+ import com.vaadin.ui.ComboBox;
+ import com.vaadin.ui.GridLayout;
+ import com.vaadin.ui.Label;
+ import com.vaadin.ui.Layout;
++import com.vaadin.ui.Root;
+ import com.vaadin.ui.Select;
-public class GridLayoutComboBoxZoomOut extends TestBase {
+
+ @SuppressWarnings("serial")
- public void setup() {
- Window mainWindow = new Window("Gridlayoutbug Application");
++public class GridLayoutComboBoxZoomOut extends AbstractTestCase {
+
+ @Override
++ public void init() {
++ Root.LegacyWindow mainWindow = new Root.LegacyWindow(
++ "Gridlayoutbug Application");
+ setMainWindow(mainWindow);
+
+ Label description = new Label(
+ "Open this application in Chrome, zoom out (cmd + \"-\") and "
+ + "open the ComboBox for weird behaviour.");
+ mainWindow.addComponent(description);
+
+ Layout formLayout = new GridLayout(2, 1);
+ // formLayout.setWidth("100%");
+ formLayout.setWidth("1000px");
+
+ Select countryField = new ComboBox();
+ countryField.addItem("Finland");
+ countryField.addItem("Sweden");
+ countryField.addItem("Canada");
+ countryField.addItem("USA");
+ countryField.setCaption("Country");
+ countryField.setWidth("100%");
+ formLayout.addComponent(countryField);
+
+ Select statusField = new ComboBox();
+ statusField.addItem("Available");
+ statusField.addItem("On vacation");
+ statusField.addItem("Busy");
+ statusField.addItem("Left the building");
+ statusField.setCaption("Status");
+ statusField.setWidth("100%");
+ formLayout.addComponent(statusField);
+
+ mainWindow.addComponent(formLayout);
+ }
+
+ @Override
+ protected String getDescription() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }