From: Artur Signell Date: Fri, 27 Jan 2012 12:17:08 +0000 (+0200) Subject: Merge remote-tracking branch 'origin/6.8' X-Git-Tag: 7.0.0.alpha2~532^2 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=8cc1ee0aa018012e6644723860a353d41d6af7f8;p=vaadin-framework.git Merge remote-tracking branch 'origin/6.8' Conflicts: WebContent/VAADIN/themes/base/table/table.css WebContent/release-notes.html build/build.xml src/com/vaadin/terminal/gwt/client/ApplicationConnection.java src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java src/com/vaadin/terminal/gwt/client/ui/VSlider.java src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java src/com/vaadin/terminal/gwt/client/ui/VWindow.java src/com/vaadin/ui/Table.java tests/integration_tests.xml tests/test.xml tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java --- 8cc1ee0aa018012e6644723860a353d41d6af7f8 diff --cc WebContent/VAADIN/themes/base/datefield/datefield.css index 88d6f92c79,8e2e9aeb2b..7af440c735 --- a/WebContent/VAADIN/themes/base/datefield/datefield.css +++ b/WebContent/VAADIN/themes/base/datefield/datefield.css @@@ -60,7 -60,20 +60,10 @@@ .v-datefield-calendarpanel-day-focused { outline: 1px dotted black; } + .v-datefield-calendarpanel-day-offmonth { + color: #666; + } -.v-ie6 .v-datefield-calendarpanel-day, -.v-ie7 .v-datefield-calendarpanel-day { - margin: 1px; -} -.v-ie6 .v-datefield-calendarpanel-day-focused, -.v-ie7 .v-datefield-calendarpanel-day-focused { - border: 1px dotted black; - margin: 0px; -} - .v-datefield-time { white-space: nowrap; } diff --cc WebContent/VAADIN/themes/base/table/table.css index e2b2a16ffe,d789e8b548..877faf364f --- a/WebContent/VAADIN/themes/base/table/table.css +++ b/WebContent/VAADIN/themes/base/table/table.css @@@ -174,6 -190,13 +183,9 @@@ position: relative; /* hide this from IE, it works without it */ cursor: pointer; } + .v-table.v-disabled .v-table-column-selector { + cursor: default; + } -.v-ie6 .v-table-column-selector, -.v-ie7 .v-table-column-selector { - position: static; -} .v-table-focus-slot-left { border-left: 2px solid #999; float: none; diff --cc build/build.xml index e21984cf06,1fdcc0ee25..05d3a931ad --- a/build/build.xml +++ b/build/build.xml @@@ -22,18 -17,35 +22,17 @@@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + - - - + @@@ -62,7 -104,7 +79,7 @@@ - - ++ @@@ -330,15 -395,24 +352,14 @@@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> - - - - - - - - - - - Adding VAADIN/themes and demo files. + Adding VAADIN/themes and META-INF -- - + + @@@ -396,10 -483,7 +430,10 @@@ - + + + ++ classpathref="buildhelpers.dependencies" destdir="${buildhelpers-classes}" debug="true" encoding="UTF-8" /> @@@ -441,9 -527,19 +475,9 @@@ - - + + - - - - - - - - - - - + @@@ -921,15 -983,16 +924,15 @@@ - - + + + - - + - - - ++ diff --cc src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 18f7b19e92,944d9b5974..e659a18477 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@@ -525,6 -536,26 +548,25 @@@ public class ApplicationConnection 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; + } + } + - final Date start = new Date(); // for(;;);[realjson] final String jsonText = response.getText().substring(9, response.getText().length() - 1); @@@ -1651,9 -1854,60 +1693,68 @@@ fw.setEnabled(enabled); } - TooltipInfo tooltipInfo = componentDetail.getTooltipInfo(null); ++ // Style names ++ component.setStyleName(getStyleName(component.getStylePrimaryName(), ++ uidl, component instanceof Field)); ++ ++ TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(paintable, null); + // Update tooltip + if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) { + tooltipInfo + .setTitle(uidl.getStringAttribute(ATTRIBUTE_DESCRIPTION)); + } else { + tooltipInfo.setTitle(null); + } + ++ // Set captions ++ if (manageCaption) { ++ final Container parent = Util.getLayout(component); ++ if (parent != null) { ++ parent.updateCaption(paintable, uidl); ++ } ++ } ++ + // add error classname to components w/ error + if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { + tooltipInfo.setErrorUidl(uidl.getErrors()); + } else { + tooltipInfo.setErrorUidl(null); + } + - // Style names - component.setStyleName(getStyleName(component.getStylePrimaryName(), - uidl, component instanceof Field)); - + // Set captions + if (manageCaption) { + final Container parent = Util.getLayout(component); + if (parent != null) { - parent.updateCaption((Paintable) component, uidl); ++ parent.updateCaption(paintable, uidl); + } + } + /* + * updateComponentSize need to be after caption update so caption can be + * taken into account + */ + - updateComponentSize(componentDetail, uidl); ++ updateComponentSize(paintable, uidl); + + return false; + } + + /** + * Generates the style name for the widget based on the given primary style + * name (typically returned by Widget.getPrimaryStyleName()) and the UIDL. + * An additional "modified" style name can be added if the field parameter + * is set to true. + * + * @param primaryStyleName + * @param uidl + * @param isField + * @return + */ + public static String getStyleName(String primaryStyleName, UIDL uidl, + boolean field) { + boolean enabled = !uidl.getBooleanAttribute("disabled"); + StringBuffer styleBuf = new StringBuffer(); - final String primaryName = component.getStylePrimaryName(); - styleBuf.append(primaryName); + styleBuf.append(primaryStyleName); // first disabling and read-only status if (!enabled) { @@@ -1685,25 -1939,11 +1786,12 @@@ styleBuf.append(MODIFIED_CLASSNAME); } - TooltipInfo tooltipInfo = paintableMap.getTooltipInfo(paintable, null); - // Update tooltip - if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) { - tooltipInfo - .setTitle(uidl.getStringAttribute(ATTRIBUTE_DESCRIPTION)); - } else { - tooltipInfo.setTitle(null); - } - + // add error classname to components w/ error if (uidl.hasAttribute(ATTRIBUTE_ERROR)) { - tooltipInfo.setErrorUidl(uidl.getErrors()); styleBuf.append(" "); - styleBuf.append(primaryName); + styleBuf.append(primaryStyleName); styleBuf.append(ERROR_CLASSNAME_EXT); - } else { - tooltipInfo.setErrorUidl(null); } - // add required style to required components if (uidl.hasAttribute("required")) { styleBuf.append(" "); @@@ -1711,27 -1951,11 +1799,10 @@@ styleBuf.append(REQUIRED_CLASSNAME_EXT); } - // Styles + disabled & readonly - component.setStyleName(styleBuf.toString()); - - // Set captions - if (manageCaption) { - final Container parent = Util.getLayout(component); - if (parent != null) { - parent.updateCaption(paintable, uidl); - } - } - /* - * updateComponentSize need to be after caption update so caption can be - * taken into account - */ - - updateComponentSize(paintable, uidl); - - return false; + return styleBuf.toString(); - } - private void updateComponentSize(ComponentDetail cd, UIDL uidl) { + private void updateComponentSize(VPaintableWidget paintable, UIDL uidl) { String w = uidl.hasAttribute("width") ? uidl .getStringAttribute("width") : ""; diff --cc src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java index 6d068dd11a,174e66b7aa..e6305b3c42 --- a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java @@@ -112,31 -111,26 +112,30 @@@ public class VFormLayout extends Simple for (final Iterator it = uidl.getChildIterator(); it.hasNext(); i++) { prepareCell(i, 1); final UIDL childUidl = (UIDL) it.next(); - final Paintable p = client.getPaintable(childUidl); - Caption caption = componentToCaption.get(p); + final VPaintableWidget childPaintable = client + .getPaintable(childUidl); + Widget childWidget = childPaintable.getWidgetForPaintable(); + Caption caption = widgetToCaption.get(childWidget); if (caption == null) { - caption = new Caption(childPaintable, client, - getStylesFromUIDL(childUidl)); - caption = new Caption(p, client); ++ caption = new Caption(childPaintable, client); caption.addClickHandler(this); - componentToCaption.put(p, caption); + widgetToCaption.put(childWidget, caption); } - ErrorFlag error = componentToError.get(p); + ErrorFlag error = widgetToError.get(childWidget); if (error == null) { error = new ErrorFlag(); - componentToError.put(p, error); + widgetToError.put(childWidget, error); } prepareCell(i, COLUMN_WIDGET); - final Paintable oldComponent = (Paintable) getWidget(i, - COLUMN_WIDGET); - if (oldComponent == null) { - setWidget(i, COLUMN_WIDGET, (Widget) p); - } else if (oldComponent != p) { - client.unregisterPaintable(oldComponent); - setWidget(i, COLUMN_WIDGET, (Widget) p); + + Widget oldWidget = getWidget(i, COLUMN_WIDGET); + if (oldWidget == null) { + setWidget(i, COLUMN_WIDGET, childWidget); + } else if (oldWidget != childWidget) { + final VPaintableWidget oldPaintable = VPaintableMap.get( + client).getPaintable(oldWidget); + client.unregisterPaintable(oldPaintable); + setWidget(i, COLUMN_WIDGET, childWidget); } getCellFormatter().setStyleName(i, COLUMN_WIDGET, CLASSNAME + "-contentcell"); @@@ -202,21 -194,16 +201,20 @@@ for (i = 0; i < getRowCount(); i++) { Widget candidate = getWidget(i, COLUMN_WIDGET); if (oldComponent == candidate) { - Caption oldCap = componentToCaption.get(oldComponent); - final Caption newCap = new Caption( - (Paintable) newComponent, client); + VPaintableMap paintableMap = VPaintableMap.get(client); + VPaintableWidget oldPaintable = paintableMap + .getPaintable(oldComponent); + VPaintableWidget newPaintable = paintableMap + .getPaintable(newComponent); + Caption oldCap = widgetToCaption.get(oldComponent); - final Caption newCap = new Caption(newPaintable, client, - null); ++ final Caption newCap = new Caption(newPaintable, client); newCap.addClickHandler(this); newCap.setStyleName(oldCap.getStyleName()); - componentToCaption.put((Paintable) newComponent, newCap); - ErrorFlag error = componentToError.get(newComponent); + widgetToCaption.put(newComponent, newCap); + ErrorFlag error = widgetToError.get(newComponent); if (error == null) { error = new ErrorFlag(); - componentToError.put((Paintable) newComponent, error); + widgetToError.put(newComponent, error); } setWidget(i, COLUMN_CAPTION, newCap); @@@ -333,8 -318,7 +331,7 @@@ * return null * @param client */ - public Caption(VPaintableWidget component, - ApplicationConnection client, String[] styles) { - public Caption(Paintable component, ApplicationConnection client) { ++ public Caption(VPaintableWidget component, ApplicationConnection client) { super(); this.client = client; owner = component; diff --cc src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java index 7de1658c5d,549248aab3..44fb9ac69c --- a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java @@@ -1,462 -1,482 +1,474 @@@ - /* - @VaadinApache2LicenseForJavaFiles@ - */ - - package com.vaadin.terminal.gwt.client.ui; - - import java.util.Date; - - import com.google.gwt.core.client.GWT; - 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.KeyCodes; - import com.google.gwt.event.logical.shared.CloseEvent; - import com.google.gwt.event.logical.shared.CloseHandler; - 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.PopupPanel; - import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; - import com.vaadin.terminal.gwt.client.ApplicationConnection; - import com.vaadin.terminal.gwt.client.BrowserInfo; - import com.vaadin.terminal.gwt.client.DateTimeService; - import com.vaadin.terminal.gwt.client.VPaintableWidget; - import com.vaadin.terminal.gwt.client.UIDL; - import com.vaadin.terminal.gwt.client.VConsole; - import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; - import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; - import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; - import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; - - /** - * Represents a date selection component with a text field and a popup date - * selector. - * - * Note: To change the keyboard assignments used in the popup dialog you - * should extend com.vaadin.terminal.gwt.client.ui.VCalendarPanel - * and then pass set it by calling the - * setCalendarPanel(VCalendarPanel panel) method. - * - */ - public class VPopupCalendar extends VTextualDate implements VPaintableWidget, - Field, ClickHandler, CloseHandler, SubPartAware { - - private final Button calendarToggle; - - private VCalendarPanel calendar; - - private final VOverlay popup; - private boolean open = false; - private boolean parsable = true; - - public VPopupCalendar() { - super(); - - calendarToggle = new Button(); - calendarToggle.setStyleName(CLASSNAME + "-button"); - calendarToggle.setText(""); - calendarToggle.addClickHandler(this); - // -2 instead of -1 to avoid FocusWidget.onAttach to reset it - calendarToggle.getElement().setTabIndex(-2); - add(calendarToggle); - - calendar = GWT.create(VCalendarPanel.class); - calendar.setFocusOutListener(new FocusOutListener() { - public boolean onFocusOut(DomEvent event) { - event.preventDefault(); - closeCalendarPanel(); - return true; - } - }); - - calendar.setSubmitListener(new SubmitListener() { - public void onSubmit() { - // Update internal value and send valuechange event if immediate - updateValue(calendar.getDate()); - - // Update text field (a must when not immediate). - buildDate(true); - - closeCalendarPanel(); - } - - public void onCancel() { - closeCalendarPanel(); - } - }); - - popup = new VOverlay(true, true, true); - popup.setStyleName(VDateField.CLASSNAME + "-popup"); - popup.setWidget(calendar); - popup.addCloseHandler(this); - - DOM.setElementProperty(calendar.getElement(), "id", - "PID_VAADIN_POPUPCAL"); - - sinkEvents(Event.ONKEYDOWN); - - } - - @SuppressWarnings("deprecation") - private void updateValue(Date newDate) { - Date currentDate = getCurrentDate(); - if (currentDate == null || newDate.getTime() != currentDate.getTime()) { - setCurrentDate((Date) newDate.clone()); - getClient().updateVariable(getId(), "year", - newDate.getYear() + 1900, false); - if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { - getClient().updateVariable(getId(), "month", - newDate.getMonth() + 1, false); - if (getCurrentResolution() > RESOLUTION_MONTH) { - getClient().updateVariable(getId(), "day", - newDate.getDate(), false); - if (getCurrentResolution() > RESOLUTION_DAY) { - getClient().updateVariable(getId(), "hour", - newDate.getHours(), false); - if (getCurrentResolution() > RESOLUTION_HOUR) { - getClient().updateVariable(getId(), "min", - newDate.getMinutes(), false); - if (getCurrentResolution() > RESOLUTION_MIN) { - getClient().updateVariable(getId(), "sec", - newDate.getSeconds(), false); - } - } - } - } - } - if (isImmediate()) { - getClient().sendPendingVariableChanges(); - } - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin - * .terminal.gwt.client.UIDL, - * com.vaadin.terminal.gwt.client.ApplicationConnection) - */ - @Override - @SuppressWarnings("deprecation") - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - boolean lastReadOnlyState = readonly; - parsable = uidl.getBooleanAttribute("parsable"); - - super.updateFromUIDL(uidl, client); - - popup.setStyleName(VDateField.CLASSNAME + "-popup " - + VDateField.CLASSNAME + "-" - + resolutionToString(currentResolution)); - calendar.setDateTimeService(getDateTimeService()); - calendar.setShowISOWeekNumbers(isShowISOWeekNumbers()); - if (calendar.getResolution() != currentResolution) { - calendar.setResolution(currentResolution); - if (calendar.getDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - // force re-render when changing resolution only - calendar.renderCalendar(); - } - } - calendarToggle.setEnabled(enabled); - - if (currentResolution <= RESOLUTION_MONTH) { - calendar.setFocusChangeListener(new FocusChangeListener() { - public void focusChanged(Date date) { - updateValue(date); - buildDate(); - Date date2 = calendar.getDate(); - date2.setYear(date.getYear()); - date2.setMonth(date.getMonth()); - } - }); - } else { - calendar.setFocusChangeListener(null); - } - - if (currentResolution > RESOLUTION_DAY) { - calendar.setTimeChangeListener(new TimeChangeListener() { - public void changed(int hour, int min, int sec, int msec) { - Date d = getDate(); - if (d == null) { - // date currently null, use the value from calendarPanel - // (~ client time at the init of the widget) - d = (Date) calendar.getDate().clone(); - } - d.setHours(hour); - d.setMinutes(min); - d.setSeconds(sec); - DateTimeService.setMilliseconds(d, msec); - - // Always update time changes to the server - updateValue(d); - - // Update text field - buildDate(); - } - }); - } - - if (readonly) { - calendarToggle.addStyleName(CLASSNAME + "-button-readonly"); - } else { - calendarToggle.removeStyleName(CLASSNAME + "-button-readonly"); - } - - if (lastReadOnlyState != readonly) { - updateWidth(); - } - - calendarToggle.setEnabled(true); - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String) - */ - @Override - public void setStyleName(String style) { - // make sure the style is there before size calculation - super.setStyleName(style + " " + CLASSNAME + "-popupcalendar"); - } - - /** - * Opens the calendar panel popup - */ - public void openCalendarPanel() { - - if (!open && !readonly) { - open = true; - - if (getCurrentDate() != null) { - calendar.setDate((Date) getCurrentDate().clone()); - } else { - calendar.setDate(new Date()); - } - - // clear previous values - popup.setWidth(""); - popup.setHeight(""); - popup.setPopupPositionAndShow(new PositionCallback() { - public void setPosition(int offsetWidth, int offsetHeight) { - final int w = offsetWidth; - final int h = offsetHeight; - final int browserWindowWidth = Window.getClientWidth() - + Window.getScrollLeft(); - final int browserWindowHeight = Window.getClientHeight() - + Window.getScrollTop(); - int t = calendarToggle.getAbsoluteTop(); - int l = calendarToggle.getAbsoluteLeft(); - - // Add a little extra space to the right to avoid - // problems with IE7 scrollbars and to make it look - // nicer. - int extraSpace = 30; - - boolean overflowRight = false; - if (l + +w + extraSpace > browserWindowWidth) { - overflowRight = true; - // Part of the popup is outside the browser window - // (to the right) - l = browserWindowWidth - w - extraSpace; - } - - if (t + h + calendarToggle.getOffsetHeight() + 30 > browserWindowHeight) { - // Part of the popup is outside the browser window - // (below) - t = browserWindowHeight - h - - calendarToggle.getOffsetHeight() - 30; - if (!overflowRight) { - // Show to the right of the popup button unless we - // are in the lower right corner of the screen - l += calendarToggle.getOffsetWidth(); - } - } - - // fix size - popup.setWidth(w + "px"); - popup.setHeight(h + "px"); - - popup.setPopupPosition(l, - t + calendarToggle.getOffsetHeight() + 2); - - /* - * We have to wait a while before focusing since the popup - * needs to be opened before we can focus - */ - Timer focusTimer = new Timer() { - @Override - public void run() { - setFocus(true); - } - }; - - focusTimer.schedule(100); - } - }); - } else { - VConsole.error("Cannot reopen popup, it is already open!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event - * .dom.client.ClickEvent) - */ - public void onClick(ClickEvent event) { - if (event.getSource() == calendarToggle && isEnabled()) { - openCalendarPanel(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt - * .event.logical.shared.CloseEvent) - */ - public void onClose(CloseEvent event) { - if (event.getSource() == popup) { - buildDate(); - if (!BrowserInfo.get().isTouchDevice()) { - /* - * Move focus to textbox, unless on touch device (avoids opening - * virtual keyboard). - */ - focus(); - } - - // TODO resolve what the "Sigh." is all about and document it here - // Sigh. - Timer t = new Timer() { - @Override - public void run() { - open = false; - } - }; - t.schedule(100); - } - } - - /** - * Sets focus to Calendar panel. - * - * @param focus - */ - public void setFocus(boolean focus) { - calendar.setFocus(focus); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth() - */ - @Override - protected int getFieldExtraWidth() { - if (fieldExtraWidth < 0) { - fieldExtraWidth = super.getFieldExtraWidth(); - fieldExtraWidth += calendarToggle.getOffsetWidth(); - } - return fieldExtraWidth; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate() - */ - @Override - protected void buildDate() { - // Save previous value - String previousValue = getText(); - super.buildDate(); - - // Restore previous value if the input could not be parsed - if (!parsable) { - setText(previousValue); - } - } - - /** - * Update the text field contents from the date. See {@link #buildDate()}. - * - * @param forceValid - * true to force the text field to be updated, false to only - * update if the parsable flag is true. - */ - protected void buildDate(boolean forceValid) { - if (forceValid) { - parsable = true; - } - buildDate(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google - * .gwt.user.client.Event) - */ - @Override - public void onBrowserEvent(com.google.gwt.user.client.Event event) { - super.onBrowserEvent(event); - if (DOM.eventGetType(event) == Event.ONKEYDOWN - && event.getKeyCode() == getOpenCalenderPanelKey()) { - openCalendarPanel(); - event.preventDefault(); - } - } - - /** - * Get the key code that opens the calendar panel. By default it is the down - * key but you can override this to be whatever you like - * - * @return - */ - protected int getOpenCalenderPanelKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * Closes the open popup panel - */ - public void closeCalendarPanel() { - if (open) { - popup.hide(true); - } - } - - private final String CALENDAR_TOGGLE_ID = "popupButton"; - - @Override - public Element getSubPartElement(String subPart) { - if (subPart.equals(CALENDAR_TOGGLE_ID)) { - return calendarToggle.getElement(); - } - - return super.getSubPartElement(subPart); - } - - @Override - public String getSubPartName(Element subElement) { - if (calendarToggle.getElement().isOrHasChild(subElement)) { - return CALENDAR_TOGGLE_ID; - } - - return super.getSubPartName(subElement); - } - - } + /* + @VaadinApache2LicenseForJavaFiles@ + */ + + package com.vaadin.terminal.gwt.client.ui; + + import java.util.Date; + + import com.google.gwt.core.client.GWT; + 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.KeyCodes; + import com.google.gwt.event.logical.shared.CloseEvent; + import com.google.gwt.event.logical.shared.CloseHandler; + 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.PopupPanel; + import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; + import com.vaadin.terminal.gwt.client.ApplicationConnection; + import com.vaadin.terminal.gwt.client.BrowserInfo; + import com.vaadin.terminal.gwt.client.DateTimeService; -import com.vaadin.terminal.gwt.client.Paintable; ++import com.vaadin.terminal.gwt.client.VPaintableWidget; + import com.vaadin.terminal.gwt.client.UIDL; + import com.vaadin.terminal.gwt.client.VConsole; + import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener; + import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener; + import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener; + import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener; + + /** + * Represents a date selection component with a text field and a popup date + * selector. + * + * Note: To change the keyboard assignments used in the popup dialog you + * should extend com.vaadin.terminal.gwt.client.ui.VCalendarPanel + * and then pass set it by calling the + * setCalendarPanel(VCalendarPanel panel) method. + * + */ -public class VPopupCalendar extends VTextualDate implements Paintable, Field, - ClickHandler, CloseHandler, SubPartAware { ++public class VPopupCalendar extends VTextualDate implements VPaintableWidget, ++ Field, ClickHandler, CloseHandler, SubPartAware { + + private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME + + "-popup"; + + private final Button calendarToggle; + + private VCalendarPanel calendar; + + private final VOverlay popup; + private boolean open = false; + private boolean parsable = true; + + public VPopupCalendar() { + super(); + + calendarToggle = new Button(); + calendarToggle.setStyleName(CLASSNAME + "-button"); + calendarToggle.setText(""); + calendarToggle.addClickHandler(this); + // -2 instead of -1 to avoid FocusWidget.onAttach to reset it + calendarToggle.getElement().setTabIndex(-2); + add(calendarToggle); + + calendar = GWT.create(VCalendarPanel.class); + calendar.setFocusOutListener(new FocusOutListener() { + public boolean onFocusOut(DomEvent event) { + event.preventDefault(); + closeCalendarPanel(); + return true; + } + }); + + calendar.setSubmitListener(new SubmitListener() { + public void onSubmit() { + // Update internal value and send valuechange event if immediate + updateValue(calendar.getDate()); + + // Update text field (a must when not immediate). + buildDate(true); + + closeCalendarPanel(); + } + + public void onCancel() { + closeCalendarPanel(); + } + }); + + popup = new VOverlay(true, true, true); + popup.setStyleName(POPUP_PRIMARY_STYLE_NAME); + popup.setWidget(calendar); + popup.addCloseHandler(this); + + DOM.setElementProperty(calendar.getElement(), "id", + "PID_VAADIN_POPUPCAL"); + + sinkEvents(Event.ONKEYDOWN); + + } + + @SuppressWarnings("deprecation") + private void updateValue(Date newDate) { + Date currentDate = getCurrentDate(); + if (currentDate == null || newDate.getTime() != currentDate.getTime()) { + setCurrentDate((Date) newDate.clone()); + getClient().updateVariable(getId(), "year", + newDate.getYear() + 1900, false); + if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) { + getClient().updateVariable(getId(), "month", + newDate.getMonth() + 1, false); + if (getCurrentResolution() > RESOLUTION_MONTH) { + getClient().updateVariable(getId(), "day", + newDate.getDate(), false); + if (getCurrentResolution() > RESOLUTION_DAY) { + getClient().updateVariable(getId(), "hour", + newDate.getHours(), false); + if (getCurrentResolution() > RESOLUTION_HOUR) { + getClient().updateVariable(getId(), "min", + newDate.getMinutes(), false); + if (getCurrentResolution() > RESOLUTION_MIN) { + getClient().updateVariable(getId(), "sec", + newDate.getSeconds(), false); - if (getCurrentResolution() == RESOLUTION_MSEC) { - getClient().updateVariable( - getId(), - "msec", - DateTimeService - .getMilliseconds(newDate), - false); - } + } + } + } + } + } + if (isImmediate()) { + getClient().sendPendingVariableChanges(); + } + } + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin + * .terminal.gwt.client.UIDL, + * com.vaadin.terminal.gwt.client.ApplicationConnection) + */ + @Override + @SuppressWarnings("deprecation") + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + boolean lastReadOnlyState = readonly; + boolean lastEnabledState = isEnabled(); + + parsable = uidl.getBooleanAttribute("parsable"); + + super.updateFromUIDL(uidl, client); + + String popupStyleNames = ApplicationConnection.getStyleName( + POPUP_PRIMARY_STYLE_NAME, uidl, false); + popupStyleNames += " " + VDateField.CLASSNAME + "-" + + resolutionToString(currentResolution); + popup.setStyleName(popupStyleNames); + + calendar.setDateTimeService(getDateTimeService()); + calendar.setShowISOWeekNumbers(isShowISOWeekNumbers()); + if (calendar.getResolution() != currentResolution) { + calendar.setResolution(currentResolution); + if (calendar.getDate() != null) { + calendar.setDate((Date) getCurrentDate().clone()); + // force re-render when changing resolution only + calendar.renderCalendar(); + } + } + calendarToggle.setEnabled(enabled); + + if (currentResolution <= RESOLUTION_MONTH) { + calendar.setFocusChangeListener(new FocusChangeListener() { + public void focusChanged(Date date) { + updateValue(date); + buildDate(); + Date date2 = calendar.getDate(); + date2.setYear(date.getYear()); + date2.setMonth(date.getMonth()); + } + }); + } else { + calendar.setFocusChangeListener(null); + } + + if (currentResolution > RESOLUTION_DAY) { + calendar.setTimeChangeListener(new TimeChangeListener() { + public void changed(int hour, int min, int sec, int msec) { + Date d = getDate(); + if (d == null) { + // date currently null, use the value from calendarPanel + // (~ client time at the init of the widget) + d = (Date) calendar.getDate().clone(); + } + d.setHours(hour); + d.setMinutes(min); + d.setSeconds(sec); + DateTimeService.setMilliseconds(d, msec); + + // Always update time changes to the server + updateValue(d); + + // Update text field + buildDate(); + } + }); + } + + if (readonly) { + calendarToggle.addStyleName(CLASSNAME + "-button-readonly"); + } else { + calendarToggle.removeStyleName(CLASSNAME + "-button-readonly"); + } + + if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) { + // Enabled or readonly state changed. Differences in theming might + // affect the width (for instance if the popup button is hidden) so + // we have to recalculate the width (IF the width of the field is + // fixed) + updateWidth(); + } + + calendarToggle.setEnabled(true); + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String) + */ + @Override + public void setStyleName(String style) { + // make sure the style is there before size calculation + super.setStyleName(style + " " + CLASSNAME + "-popupcalendar"); + } + + /** + * Opens the calendar panel popup + */ + public void openCalendarPanel() { + + if (!open && !readonly) { + open = true; + + if (getCurrentDate() != null) { + calendar.setDate((Date) getCurrentDate().clone()); + } else { + calendar.setDate(new Date()); + } + + // clear previous values + popup.setWidth(""); + popup.setHeight(""); + popup.setPopupPositionAndShow(new PositionCallback() { + public void setPosition(int offsetWidth, int offsetHeight) { + final int w = offsetWidth; + final int h = offsetHeight; + final int browserWindowWidth = Window.getClientWidth() + + Window.getScrollLeft(); + final int browserWindowHeight = Window.getClientHeight() + + Window.getScrollTop(); + int t = calendarToggle.getAbsoluteTop(); + int l = calendarToggle.getAbsoluteLeft(); + + // Add a little extra space to the right to avoid - // problems with IE6/IE7 scrollbars and to make it look ++ // problems with IE7 scrollbars and to make it look + // nicer. + int extraSpace = 30; + + boolean overflowRight = false; + if (l + +w + extraSpace > browserWindowWidth) { + overflowRight = true; + // Part of the popup is outside the browser window + // (to the right) + l = browserWindowWidth - w - extraSpace; + } + + if (t + h + calendarToggle.getOffsetHeight() + 30 > browserWindowHeight) { + // Part of the popup is outside the browser window + // (below) + t = browserWindowHeight - h + - calendarToggle.getOffsetHeight() - 30; + if (!overflowRight) { + // Show to the right of the popup button unless we + // are in the lower right corner of the screen + l += calendarToggle.getOffsetWidth(); + } + } + + // fix size + popup.setWidth(w + "px"); + popup.setHeight(h + "px"); + + popup.setPopupPosition(l, + t + calendarToggle.getOffsetHeight() + 2); + + /* + * We have to wait a while before focusing since the popup + * needs to be opened before we can focus + */ + Timer focusTimer = new Timer() { + @Override + public void run() { + setFocus(true); + } + }; + + focusTimer.schedule(100); + } + }); + } else { + VConsole.error("Cannot reopen popup, it is already open!"); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event + * .dom.client.ClickEvent) + */ + public void onClick(ClickEvent event) { + if (event.getSource() == calendarToggle && isEnabled()) { + openCalendarPanel(); + } + } + + /* + * (non-Javadoc) + * + * @see + * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt + * .event.logical.shared.CloseEvent) + */ + public void onClose(CloseEvent event) { + if (event.getSource() == popup) { + buildDate(); + if (!BrowserInfo.get().isTouchDevice()) { + /* + * Move focus to textbox, unless on touch device (avoids opening + * virtual keyboard). + */ + focus(); + } + + // TODO resolve what the "Sigh." is all about and document it here + // Sigh. + Timer t = new Timer() { + @Override + public void run() { + open = false; + } + }; + t.schedule(100); + } + } + + /** + * Sets focus to Calendar panel. + * + * @param focus + */ + public void setFocus(boolean focus) { + calendar.setFocus(focus); + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth() + */ + @Override + protected int getFieldExtraWidth() { + if (fieldExtraWidth < 0) { + fieldExtraWidth = super.getFieldExtraWidth(); + fieldExtraWidth += calendarToggle.getOffsetWidth(); + } + return fieldExtraWidth; + } + + /* + * (non-Javadoc) + * + * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate() + */ + @Override + protected void buildDate() { + // Save previous value + String previousValue = getText(); + super.buildDate(); + + // Restore previous value if the input could not be parsed + if (!parsable) { + setText(previousValue); + } + } + + /** + * Update the text field contents from the date. See {@link #buildDate()}. + * + * @param forceValid + * true to force the text field to be updated, false to only + * update if the parsable flag is true. + */ + protected void buildDate(boolean forceValid) { + if (forceValid) { + parsable = true; + } + buildDate(); + } + + /* + * (non-Javadoc) + * + * @see + * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google + * .gwt.user.client.Event) + */ + @Override + public void onBrowserEvent(com.google.gwt.user.client.Event event) { + super.onBrowserEvent(event); + if (DOM.eventGetType(event) == Event.ONKEYDOWN + && event.getKeyCode() == getOpenCalenderPanelKey()) { + openCalendarPanel(); + event.preventDefault(); + } + } + + /** + * Get the key code that opens the calendar panel. By default it is the down + * key but you can override this to be whatever you like + * + * @return + */ + protected int getOpenCalenderPanelKey() { + return KeyCodes.KEY_DOWN; + } + + /** + * Closes the open popup panel + */ + public void closeCalendarPanel() { + if (open) { + popup.hide(true); + } + } + + private final String CALENDAR_TOGGLE_ID = "popupButton"; + + @Override + public Element getSubPartElement(String subPart) { + if (subPart.equals(CALENDAR_TOGGLE_ID)) { + return calendarToggle.getElement(); + } + + return super.getSubPartElement(subPart); + } + + @Override + public String getSubPartName(Element subElement) { + if (calendarToggle.getElement().isOrHasChild(subElement)) { + return CALENDAR_TOGGLE_ID; + } + + return super.getSubPartName(subElement); + } + + } diff --cc src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java index 41b7efcf02,553934bf98..de68ae96a4 --- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java @@@ -2105,26 -2292,17 +2105,16 @@@ public class VScrollTable extends FlowP * of the caption container element by the correct amount */ public void resizeCaptionContainer(int rightSpacing) { - + int captionContainerWidth = width + - colResizeWidget.getOffsetWidth() - rightSpacing; + - if (BrowserInfo.get().isIE6() || td.getClassName().contains("-asc") + if (td.getClassName().contains("-asc") || td.getClassName().contains("-desc")) { - /* - * Room for the sort indicator is made by subtracting the styled - * margin and width of the resizer from the width of the caption - * container. - */ - int captionContainerWidth = width - - sortIndicator.getOffsetWidth() - - colResizeWidget.getOffsetWidth() - rightSpacing; - captionContainer.getStyle().setPropertyPx("width", - captionContainerWidth); - } else { - /* - * Set the caption container element as wide as possible when - * the sorting indicator is not visible. - */ - captionContainer.getStyle().setPropertyPx("width", - width - rightSpacing); + // Leave room for the sort indicator + captionContainerWidth -= sortIndicator.getOffsetWidth(); } + captionContainer.getStyle().setPropertyPx("width", + captionContainerWidth); // Apply/Remove spacing if defined if (rightSpacing > 0) { diff --cc src/com/vaadin/terminal/gwt/client/ui/VSlider.java index 6b55fa0802,9dfab44b93..3632e90956 --- a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java @@@ -1,573 -1,599 +1,569 @@@ - /* - @VaadinApache2LicenseForJavaFiles@ - */ - // - package com.vaadin.terminal.gwt.client.ui; - - import com.google.gwt.core.client.Scheduler; - import com.google.gwt.core.client.Scheduler.ScheduledCommand; - import com.google.gwt.event.dom.client.KeyCodes; - import com.google.gwt.user.client.Command; - import com.google.gwt.user.client.DOM; - import com.google.gwt.user.client.Element; - import com.google.gwt.user.client.Event; - import com.google.gwt.user.client.Window; - import com.google.gwt.user.client.ui.HTML; - import com.google.gwt.user.client.ui.Widget; - import com.vaadin.terminal.gwt.client.ApplicationConnection; - import com.vaadin.terminal.gwt.client.BrowserInfo; - import com.vaadin.terminal.gwt.client.ContainerResizedListener; - import com.vaadin.terminal.gwt.client.VPaintableWidget; - import com.vaadin.terminal.gwt.client.UIDL; - import com.vaadin.terminal.gwt.client.Util; - import com.vaadin.terminal.gwt.client.VConsole; - - public class VSlider extends SimpleFocusablePanel implements VPaintableWidget, - Field, ContainerResizedListener { - - public static final String CLASSNAME = "v-slider"; - - /** - * Minimum size (width or height, depending on orientation) of the slider - * base. - */ - private static final int MIN_SIZE = 50; - - ApplicationConnection client; - - String id; - - private boolean immediate; - private boolean disabled; - private boolean readonly; - - private int acceleration = 1; - private double min; - private double max; - private int resolution; - private Double value; - private boolean vertical; - - private final HTML feedback = new HTML("", false); - private final VOverlay feedbackPopup = new VOverlay(true, false, true) { - @Override - public void show() { - super.show(); - updateFeedbackPosition(); - } - }; - - /* DOM element for slider's base */ - private final Element base; - private final int BASE_BORDER_WIDTH = 1; - - /* DOM element for slider's handle */ - private final Element handle; - - /* DOM element for decrement arrow */ - private final Element smaller; - - /* DOM element for increment arrow */ - private final Element bigger; - - /* Temporary dragging/animation variables */ - private boolean dragging = false; - - private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100, - new ScheduledCommand() { - - public void execute() { - updateValueToServer(); - acceleration = 1; - } - }); - - public VSlider() { - super(); - - base = DOM.createDiv(); - handle = DOM.createDiv(); - smaller = DOM.createDiv(); - bigger = DOM.createDiv(); - - setStyleName(CLASSNAME); - DOM.setElementProperty(base, "className", CLASSNAME + "-base"); - DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); - DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller"); - DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger"); - - DOM.appendChild(getElement(), bigger); - DOM.appendChild(getElement(), smaller); - DOM.appendChild(getElement(), base); - DOM.appendChild(base, handle); - - // Hide initially - DOM.setStyleAttribute(smaller, "display", "none"); - DOM.setStyleAttribute(bigger, "display", "none"); - DOM.setStyleAttribute(handle, "visibility", "hidden"); - - sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS - | Event.FOCUSEVENTS | Event.TOUCHEVENTS); - - feedbackPopup.addStyleName(CLASSNAME + "-feedback"); - feedbackPopup.setWidget(feedback); - } - - public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - - this.client = client; - id = uidl.getId(); - - // Ensure correct implementation - if (client.updateComponent(this, uidl, true)) { - return; - } - - immediate = uidl.getBooleanAttribute("immediate"); - disabled = uidl.getBooleanAttribute("disabled"); - readonly = uidl.getBooleanAttribute("readonly"); - - vertical = uidl.hasAttribute("vertical"); - - String style = ""; - if (uidl.hasAttribute("style")) { - style = uidl.getStringAttribute("style"); - } - - if (vertical) { - addStyleName(CLASSNAME + "-vertical"); - } else { - removeStyleName(CLASSNAME + "-vertical"); - } - - min = uidl.getDoubleAttribute("min"); - max = uidl.getDoubleAttribute("max"); - resolution = uidl.getIntAttribute("resolution"); - value = new Double(uidl.getDoubleVariable("value")); - - setFeedbackValue(value); - - buildBase(); - - if (!vertical) { - // Draw handle with a delay to allow base to gain maximum width - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - buildHandle(); - setValue(value, false); - } - }); - } else { - buildHandle(); - setValue(value, false); - } - } - - private void setFeedbackValue(double value) { - String currentValue = "" + value; - if (resolution == 0) { - currentValue = "" + new Double(value).intValue(); - } - feedback.setText(currentValue); - } - - private void updateFeedbackPosition() { - if (vertical) { - feedbackPopup.setPopupPosition( - DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(), - DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2 - - feedbackPopup.getOffsetHeight() / 2); - } else { - feedbackPopup.setPopupPosition( - DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2 - - feedbackPopup.getOffsetWidth() / 2, - DOM.getAbsoluteTop(handle) - - feedbackPopup.getOffsetHeight()); - } - } - - private void buildBase() { - final String styleAttribute = vertical ? "height" : "width"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - - final Element p = DOM.getParent(getElement()); - if (DOM.getElementPropertyInt(p, domProperty) > 50) { - if (vertical) { - setHeight(); - } else { - DOM.setStyleAttribute(base, styleAttribute, ""); - } - } else { - // Set minimum size and adjust after all components have - // (supposedly) been drawn completely. - DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px"); - Scheduler.get().scheduleDeferred(new Command() { - public void execute() { - final Element p = DOM.getParent(getElement()); - if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) { - if (vertical) { - setHeight(); - } else { - DOM.setStyleAttribute(base, styleAttribute, ""); - } - // Ensure correct position - setValue(value, false); - } - } - }); - } - - // TODO attach listeners for focusing and arrow keys - } - - private void buildHandle() { - final String handleAttribute = vertical ? "marginTop" : "marginLeft"; - - DOM.setStyleAttribute(handle, handleAttribute, "0"); - - // Restore visibility - DOM.setStyleAttribute(handle, "visibility", "visible"); - - } - - private void setValue(Double value, boolean updateToServer) { - if (value == null) { - return; - } - - if (value < min) { - value = min; - } else if (value > max) { - value = max; - } - - // Update handle position - final String styleAttribute = vertical ? "marginTop" : "marginLeft"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; - final int handleSize = Integer.parseInt(DOM.getElementProperty(handle, - domProperty)); - final int baseSize = Integer.parseInt(DOM.getElementProperty(base, - domProperty)) - (2 * BASE_BORDER_WIDTH); - - final int range = baseSize - handleSize; - double v = value.doubleValue(); - - // Round value to resolution - if (resolution > 0) { - v = Math.round(v * Math.pow(10, resolution)); - v = v / Math.pow(10, resolution); - } else { - v = Math.round(v); - } - final double valueRange = max - min; - double p = 0; - if (valueRange > 0) { - p = range * ((v - min) / valueRange); - } - if (p < 0) { - p = 0; - } - if (vertical) { - p = range - p; - } - final double pos = p; - - DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px"); - - // Update value - this.value = new Double(v); - setFeedbackValue(v); - - if (updateToServer) { - updateValueToServer(); - } - } - - @Override - public void onBrowserEvent(Event event) { - if (disabled || readonly) { - return; - } - final Element targ = DOM.eventGetTarget(event); - - if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) { - processMouseWheelEvent(event); - } else if (dragging || targ == handle) { - processHandleEvent(event); - } else if (targ == smaller) { - decreaseValue(true); - } else if (targ == bigger) { - increaseValue(true); - } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) { - processBaseEvent(event); - } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS) - || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) { - - if (handleNavigation(event.getKeyCode(), event.getCtrlKey(), - event.getShiftKey())) { - - feedbackPopup.show(); - - delayedValueUpdater.trigger(); - - DOM.eventPreventDefault(event); - DOM.eventCancelBubble(event, true); - } - } else if (targ.equals(getElement()) - && DOM.eventGetType(event) == Event.ONFOCUS) { - feedbackPopup.show(); - } else if (targ.equals(getElement()) - && DOM.eventGetType(event) == Event.ONBLUR) { - feedbackPopup.hide(); - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { - feedbackPopup.show(); - } - if (Util.isTouchEvent(event)) { - event.preventDefault(); // avoid simulated events - event.stopPropagation(); - } - } - - private void processMouseWheelEvent(final Event event) { - final int dir = DOM.eventGetMouseWheelVelocityY(event); - - if (dir < 0) { - increaseValue(false); - } else { - decreaseValue(false); - } - - delayedValueUpdater.trigger(); - - DOM.eventPreventDefault(event); - DOM.eventCancelBubble(event, true); - } - - private void processHandleEvent(Event event) { - switch (DOM.eventGetType(event)) { - case Event.ONMOUSEDOWN: - case Event.ONTOUCHSTART: - if (!disabled && !readonly) { - focus(); - feedbackPopup.show(); - dragging = true; - DOM.setElementProperty(handle, "className", CLASSNAME - + "-handle " + CLASSNAME + "-handle-active"); - DOM.setCapture(getElement()); - DOM.eventPreventDefault(event); // prevent selecting text - DOM.eventCancelBubble(event, true); - event.stopPropagation(); - VConsole.log("Slider move start"); - } - break; - case Event.ONMOUSEMOVE: - case Event.ONTOUCHMOVE: - if (dragging) { - VConsole.log("Slider move"); - setValueByEvent(event, false); - updateFeedbackPosition(); - event.stopPropagation(); - } - break; - case Event.ONTOUCHEND: - feedbackPopup.hide(); - case Event.ONMOUSEUP: - // feedbackPopup.hide(); - VConsole.log("Slider move end"); - dragging = false; - DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); - DOM.releaseCapture(getElement()); - setValueByEvent(event, true); - event.stopPropagation(); - break; - default: - break; - } - } - - private void processBaseEvent(Event event) { - if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { - if (!disabled && !readonly && !dragging) { - setValueByEvent(event, true); - DOM.eventCancelBubble(event, true); - } - } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) { - dragging = false; - DOM.releaseCapture(getElement()); - setValueByEvent(event, true); - } - } - - private void decreaseValue(boolean updateToServer) { - setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)), - updateToServer); - } - - private void increaseValue(boolean updateToServer) { - setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)), - updateToServer); - } - - private void setValueByEvent(Event event, boolean updateToServer) { - double v = min; // Fallback to min - - final int coord = getEventPosition(event); - - final int handleSize, baseSize, baseOffset; - if (vertical) { - handleSize = handle.getOffsetHeight(); - baseSize = base.getOffsetHeight(); - baseOffset = base.getAbsoluteTop() - Window.getScrollTop() - - handleSize / 2; - } else { - handleSize = handle.getOffsetWidth(); - baseSize = base.getOffsetWidth(); - baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft() - + handleSize / 2; - } - - if (vertical) { - v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize)) - * (max - min) + min; - } else { - v = ((coord - baseOffset) / (double) (baseSize - handleSize)) - * (max - min) + min; - } - - if (v < min) { - v = min; - } else if (v > max) { - v = max; - } - - setValue(v, updateToServer); - } - - /** - * TODO consider extracting touches support to an impl class specific for - * webkit (only browser that really supports touches). - * - * @param event - * @return - */ - protected int getEventPosition(Event event) { - if (vertical) { - return Util.getTouchOrMouseClientY(event); - } else { - return Util.getTouchOrMouseClientX(event); - } - } - - public void iLayout() { - if (vertical) { - setHeight(); - } - // Update handle position - setValue(value, false); - } - - private void setHeight() { - // Calculate decoration size - DOM.setStyleAttribute(base, "height", "0"); - DOM.setStyleAttribute(base, "overflow", "hidden"); - int h = DOM.getElementPropertyInt(getElement(), "offsetHeight"); - if (h < MIN_SIZE) { - h = MIN_SIZE; - } - DOM.setStyleAttribute(base, "height", h + "px"); - DOM.setStyleAttribute(base, "overflow", ""); - } - - private void updateValueToServer() { - client.updateVariable(id, "value", value.doubleValue(), immediate); - } - - /** - * Handles the keyboard events handled by the Slider - * - * @param event - * The keyboard event received - * @return true iff the navigation event was handled - */ - public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { - - // No support for ctrl moving - if (ctrl) { - return false; - } - - if ((keycode == getNavigationUpKey() && vertical) - || (keycode == getNavigationRightKey() && !vertical)) { - if (shift) { - for (int a = 0; a < acceleration; a++) { - increaseValue(false); - } - acceleration++; - } else { - increaseValue(false); - } - return true; - } else if (keycode == getNavigationDownKey() && vertical - || (keycode == getNavigationLeftKey() && !vertical)) { - if (shift) { - for (int a = 0; a < acceleration; a++) { - decreaseValue(false); - } - acceleration++; - } else { - decreaseValue(false); - } - return true; - } - - return false; - } - - /** - * Get the key that increases the vertical slider. By default it is the up - * arrow key but by overriding this you can change the key to whatever you - * want. - * - * @return The keycode of the key - */ - protected int getNavigationUpKey() { - return KeyCodes.KEY_UP; - } - - /** - * Get the key that decreases the vertical slider. By default it is the down - * arrow key but by overriding this you can change the key to whatever you - * want. - * - * @return The keycode of the key - */ - protected int getNavigationDownKey() { - return KeyCodes.KEY_DOWN; - } - - /** - * Get the key that decreases the horizontal slider. By default it is the - * left arrow key but by overriding this you can change the key to whatever - * you want. - * - * @return The keycode of the key - */ - protected int getNavigationLeftKey() { - return KeyCodes.KEY_LEFT; - } - - /** - * Get the key that increases the horizontal slider. By default it is the - * right arrow key but by overriding this you can change the key to whatever - * you want. - * - * @return The keycode of the key - */ - protected int getNavigationRightKey() { - return KeyCodes.KEY_RIGHT; - } - - public Widget getWidgetForPaintable() { - return this; - } - } + /* + @VaadinApache2LicenseForJavaFiles@ + */ + // + package com.vaadin.terminal.gwt.client.ui; + + import com.google.gwt.core.client.Scheduler; + import com.google.gwt.core.client.Scheduler.ScheduledCommand; + import com.google.gwt.event.dom.client.KeyCodes; + import com.google.gwt.user.client.Command; + import com.google.gwt.user.client.DOM; + import com.google.gwt.user.client.Element; + import com.google.gwt.user.client.Event; + import com.google.gwt.user.client.Window; + import com.google.gwt.user.client.ui.HTML; ++import com.google.gwt.user.client.ui.Widget; + import com.vaadin.terminal.gwt.client.ApplicationConnection; + import com.vaadin.terminal.gwt.client.BrowserInfo; + import com.vaadin.terminal.gwt.client.ContainerResizedListener; -import com.vaadin.terminal.gwt.client.Paintable; ++import com.vaadin.terminal.gwt.client.VPaintableWidget; + import com.vaadin.terminal.gwt.client.UIDL; + import com.vaadin.terminal.gwt.client.Util; + import com.vaadin.terminal.gwt.client.VConsole; + -public class VSlider extends SimpleFocusablePanel implements Paintable, Field, - ContainerResizedListener { ++public class VSlider extends SimpleFocusablePanel implements VPaintableWidget, ++ Field, ContainerResizedListener { + + public static final String CLASSNAME = "v-slider"; + + /** + * Minimum size (width or height, depending on orientation) of the slider + * base. + */ + private static final int MIN_SIZE = 50; + + ApplicationConnection client; + + String id; + + private boolean immediate; + private boolean disabled; + private boolean readonly; - private boolean scrollbarStyle; + + private int acceleration = 1; - private int handleSize; + private double min; + private double max; + private int resolution; + private Double value; + private boolean vertical; - private boolean arrows; + + private final HTML feedback = new HTML("", false); + private final VOverlay feedbackPopup = new VOverlay(true, false, true) { + @Override + public void show() { + super.show(); + updateFeedbackPosition(); + } + }; + + /* DOM element for slider's base */ + private final Element base; + private final int BASE_BORDER_WIDTH = 1; + + /* DOM element for slider's handle */ + private final Element handle; + + /* DOM element for decrement arrow */ + private final Element smaller; + + /* DOM element for increment arrow */ + private final Element bigger; + + /* Temporary dragging/animation variables */ + private boolean dragging = false; + + private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100, + new ScheduledCommand() { + + public void execute() { + updateValueToServer(); + acceleration = 1; + } + }); + + public VSlider() { + super(); + + base = DOM.createDiv(); + handle = DOM.createDiv(); + smaller = DOM.createDiv(); + bigger = DOM.createDiv(); + + setStyleName(CLASSNAME); + DOM.setElementProperty(base, "className", CLASSNAME + "-base"); + DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); + DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller"); + DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger"); + + DOM.appendChild(getElement(), bigger); + DOM.appendChild(getElement(), smaller); + DOM.appendChild(getElement(), base); + DOM.appendChild(base, handle); + + // Hide initially + DOM.setStyleAttribute(smaller, "display", "none"); + DOM.setStyleAttribute(bigger, "display", "none"); + DOM.setStyleAttribute(handle, "visibility", "hidden"); + + sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS + | Event.FOCUSEVENTS | Event.TOUCHEVENTS); + + feedbackPopup.addStyleName(CLASSNAME + "-feedback"); + feedbackPopup.setWidget(feedback); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + this.client = client; + id = uidl.getId(); + + // Ensure correct implementation + if (client.updateComponent(this, uidl, true)) { + return; + } + + immediate = uidl.getBooleanAttribute("immediate"); + disabled = uidl.getBooleanAttribute("disabled"); + readonly = uidl.getBooleanAttribute("readonly"); + + vertical = uidl.hasAttribute("vertical"); - arrows = uidl.hasAttribute("arrows"); + + String style = ""; + if (uidl.hasAttribute("style")) { + style = uidl.getStringAttribute("style"); + } + - scrollbarStyle = style.indexOf("scrollbar") > -1; - - if (arrows) { - DOM.setStyleAttribute(smaller, "display", "block"); - DOM.setStyleAttribute(bigger, "display", "block"); - } - + if (vertical) { + addStyleName(CLASSNAME + "-vertical"); + } else { + removeStyleName(CLASSNAME + "-vertical"); + } + + min = uidl.getDoubleAttribute("min"); + max = uidl.getDoubleAttribute("max"); + resolution = uidl.getIntAttribute("resolution"); + value = new Double(uidl.getDoubleVariable("value")); + + setFeedbackValue(value); + - handleSize = uidl.getIntAttribute("hsize"); - + buildBase(); + + if (!vertical) { + // Draw handle with a delay to allow base to gain maximum width + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + buildHandle(); + setValue(value, false); + } + }); + } else { + buildHandle(); + setValue(value, false); + } + } + + private void setFeedbackValue(double value) { + String currentValue = "" + value; + if (resolution == 0) { + currentValue = "" + new Double(value).intValue(); + } + feedback.setText(currentValue); + } + + private void updateFeedbackPosition() { + if (vertical) { + feedbackPopup.setPopupPosition( + DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(), + DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2 + - feedbackPopup.getOffsetHeight() / 2); + } else { + feedbackPopup.setPopupPosition( + DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2 + - feedbackPopup.getOffsetWidth() / 2, + DOM.getAbsoluteTop(handle) + - feedbackPopup.getOffsetHeight()); + } + } + + private void buildBase() { + final String styleAttribute = vertical ? "height" : "width"; + final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; + + final Element p = DOM.getParent(getElement()); + if (DOM.getElementPropertyInt(p, domProperty) > 50) { + if (vertical) { + setHeight(); + } else { + DOM.setStyleAttribute(base, styleAttribute, ""); + } + } else { + // Set minimum size and adjust after all components have + // (supposedly) been drawn completely. + DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px"); + Scheduler.get().scheduleDeferred(new Command() { + public void execute() { + final Element p = DOM.getParent(getElement()); + if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) { + if (vertical) { + setHeight(); + } else { + DOM.setStyleAttribute(base, styleAttribute, ""); + } + // Ensure correct position + setValue(value, false); + } + } + }); + } + + // TODO attach listeners for focusing and arrow keys + } + + private void buildHandle() { - final String styleAttribute = vertical ? "height" : "width"; + final String handleAttribute = vertical ? "marginTop" : "marginLeft"; - final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; + + DOM.setStyleAttribute(handle, handleAttribute, "0"); + - if (scrollbarStyle) { - // Only stretch the handle if scrollbar style is set. - int s = (int) (Double.parseDouble(DOM.getElementProperty(base, - domProperty)) / 100 * handleSize); - if (handleSize == -1) { - final int baseS = Integer.parseInt(DOM.getElementProperty(base, - domProperty)); - final double range = (max - min) * (resolution + 1) * 3; - s = (int) (baseS - range); - } - if (s < 3) { - s = 3; - } - DOM.setStyleAttribute(handle, styleAttribute, s + "px"); - } else { - DOM.setStyleAttribute(handle, styleAttribute, ""); - } - + // Restore visibility + DOM.setStyleAttribute(handle, "visibility", "visible"); + + } + + private void setValue(Double value, boolean updateToServer) { + if (value == null) { + return; + } + + if (value < min) { + value = min; + } else if (value > max) { + value = max; + } + + // Update handle position + final String styleAttribute = vertical ? "marginTop" : "marginLeft"; + final String domProperty = vertical ? "offsetHeight" : "offsetWidth"; + final int handleSize = Integer.parseInt(DOM.getElementProperty(handle, + domProperty)); + final int baseSize = Integer.parseInt(DOM.getElementProperty(base, + domProperty)) - (2 * BASE_BORDER_WIDTH); + + final int range = baseSize - handleSize; + double v = value.doubleValue(); + + // Round value to resolution + if (resolution > 0) { + v = Math.round(v * Math.pow(10, resolution)); + v = v / Math.pow(10, resolution); + } else { + v = Math.round(v); + } + final double valueRange = max - min; + double p = 0; + if (valueRange > 0) { + p = range * ((v - min) / valueRange); + } + if (p < 0) { + p = 0; + } + if (vertical) { - // IE6 rounding behaves a little unstable, reduce one pixel so the - // containing element (base) won't expand without limits - p = range - p - (BrowserInfo.get().isIE6() ? 1 : 0); ++ p = range - p; + } + final double pos = p; + + DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px"); + + // Update value + this.value = new Double(v); + setFeedbackValue(v); + + if (updateToServer) { + updateValueToServer(); + } + } + + @Override + public void onBrowserEvent(Event event) { + if (disabled || readonly) { + return; + } + final Element targ = DOM.eventGetTarget(event); + + if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) { + processMouseWheelEvent(event); + } else if (dragging || targ == handle) { + processHandleEvent(event); + } else if (targ == smaller) { + decreaseValue(true); + } else if (targ == bigger) { + increaseValue(true); + } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) { + processBaseEvent(event); + } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS) + || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) { + + if (handleNavigation(event.getKeyCode(), event.getCtrlKey(), + event.getShiftKey())) { + + feedbackPopup.show(); + + delayedValueUpdater.trigger(); + + DOM.eventPreventDefault(event); + DOM.eventCancelBubble(event, true); + } + } else if (targ.equals(getElement()) + && DOM.eventGetType(event) == Event.ONFOCUS) { + feedbackPopup.show(); + } else if (targ.equals(getElement()) + && DOM.eventGetType(event) == Event.ONBLUR) { + feedbackPopup.hide(); + } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { + feedbackPopup.show(); + } - if(Util.isTouchEvent(event)) { ++ if (Util.isTouchEvent(event)) { + event.preventDefault(); // avoid simulated events + event.stopPropagation(); + } + } + + private void processMouseWheelEvent(final Event event) { + final int dir = DOM.eventGetMouseWheelVelocityY(event); + + if (dir < 0) { + increaseValue(false); + } else { + decreaseValue(false); + } + + delayedValueUpdater.trigger(); + + DOM.eventPreventDefault(event); + DOM.eventCancelBubble(event, true); + } + + private void processHandleEvent(Event event) { + switch (DOM.eventGetType(event)) { + case Event.ONMOUSEDOWN: + case Event.ONTOUCHSTART: + if (!disabled && !readonly) { + focus(); + feedbackPopup.show(); + dragging = true; + DOM.setElementProperty(handle, "className", CLASSNAME + + "-handle " + CLASSNAME + "-handle-active"); + DOM.setCapture(getElement()); + DOM.eventPreventDefault(event); // prevent selecting text + DOM.eventCancelBubble(event, true); + event.stopPropagation(); + VConsole.log("Slider move start"); + } + break; + case Event.ONMOUSEMOVE: + case Event.ONTOUCHMOVE: + if (dragging) { + VConsole.log("Slider move"); + setValueByEvent(event, false); + updateFeedbackPosition(); + event.stopPropagation(); + } + break; + case Event.ONTOUCHEND: + feedbackPopup.hide(); + case Event.ONMOUSEUP: + // feedbackPopup.hide(); + VConsole.log("Slider move end"); + dragging = false; + DOM.setElementProperty(handle, "className", CLASSNAME + "-handle"); + DOM.releaseCapture(getElement()); + setValueByEvent(event, true); + event.stopPropagation(); + break; + default: + break; + } + } + + private void processBaseEvent(Event event) { + if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) { + if (!disabled && !readonly && !dragging) { + setValueByEvent(event, true); + DOM.eventCancelBubble(event, true); + } + } + } + + private void decreaseValue(boolean updateToServer) { + setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)), + updateToServer); + } + + private void increaseValue(boolean updateToServer) { + setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)), + updateToServer); + } + + private void setValueByEvent(Event event, boolean updateToServer) { + double v = min; // Fallback to min + + final int coord = getEventPosition(event); + + final int handleSize, baseSize, baseOffset; + if (vertical) { + handleSize = handle.getOffsetHeight(); + baseSize = base.getOffsetHeight(); + baseOffset = base.getAbsoluteTop() - Window.getScrollTop() + - handleSize / 2; + } else { + handleSize = handle.getOffsetWidth(); + baseSize = base.getOffsetWidth(); + baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft() + + handleSize / 2; + } + + if (vertical) { + v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize)) + * (max - min) + min; + } else { + v = ((coord - baseOffset) / (double) (baseSize - handleSize)) + * (max - min) + min; + } + + if (v < min) { + v = min; + } else if (v > max) { + v = max; + } + + setValue(v, updateToServer); + } + + /** + * TODO consider extracting touches support to an impl class specific for + * webkit (only browser that really supports touches). + * + * @param event + * @return + */ + protected int getEventPosition(Event event) { + if (vertical) { + return Util.getTouchOrMouseClientY(event); + } else { + return Util.getTouchOrMouseClientX(event); + } + } + + public void iLayout() { + if (vertical) { + setHeight(); + } + // Update handle position + setValue(value, false); + } + + private void setHeight() { + // Calculate decoration size + DOM.setStyleAttribute(base, "height", "0"); + DOM.setStyleAttribute(base, "overflow", "hidden"); + int h = DOM.getElementPropertyInt(getElement(), "offsetHeight"); + if (h < MIN_SIZE) { + h = MIN_SIZE; + } + DOM.setStyleAttribute(base, "height", h + "px"); + DOM.setStyleAttribute(base, "overflow", ""); + } + + private void updateValueToServer() { + client.updateVariable(id, "value", value.doubleValue(), immediate); + } + + /** + * Handles the keyboard events handled by the Slider + * + * @param event + * The keyboard event received + * @return true iff the navigation event was handled + */ + public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) { + + // No support for ctrl moving + if (ctrl) { + return false; + } + + if ((keycode == getNavigationUpKey() && vertical) + || (keycode == getNavigationRightKey() && !vertical)) { + if (shift) { + for (int a = 0; a < acceleration; a++) { + increaseValue(false); + } + acceleration++; + } else { + increaseValue(false); + } + return true; + } else if (keycode == getNavigationDownKey() && vertical + || (keycode == getNavigationLeftKey() && !vertical)) { + if (shift) { + for (int a = 0; a < acceleration; a++) { + decreaseValue(false); + } + acceleration++; + } else { + decreaseValue(false); + } + return true; + } + + return false; + } + + /** + * Get the key that increases the vertical slider. By default it is the up + * arrow key but by overriding this you can change the key to whatever you + * want. + * + * @return The keycode of the key + */ + protected int getNavigationUpKey() { + return KeyCodes.KEY_UP; + } + + /** + * Get the key that decreases the vertical slider. By default it is the down + * arrow key but by overriding this you can change the key to whatever you + * want. + * + * @return The keycode of the key + */ + protected int getNavigationDownKey() { + return KeyCodes.KEY_DOWN; + } + + /** + * Get the key that decreases the horizontal slider. By default it is the + * left arrow key but by overriding this you can change the key to whatever + * you want. + * + * @return The keycode of the key + */ + protected int getNavigationLeftKey() { + return KeyCodes.KEY_LEFT; + } + + /** + * Get the key that increases the horizontal slider. By default it is the + * right arrow key but by overriding this you can change the key to whatever + * you want. + * + * @return The keycode of the key + */ + protected int getNavigationRightKey() { + return KeyCodes.KEY_RIGHT; + } ++ ++ public Widget getWidgetForPaintable() { ++ return this; ++ } + } diff --cc src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java index ed4953d463,56cdf05ddb..a522c79736 --- a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java @@@ -20,12 -22,12 +20,12 @@@ import com.vaadin.terminal.gwt.client.E import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.LocaleNotLoadedException; import com.vaadin.terminal.gwt.client.LocaleService; - import com.vaadin.terminal.gwt.client.VPaintableWidget; -import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.VConsole; ++import com.vaadin.terminal.gwt.client.VPaintableWidget; - public class VTextualDate extends VDateField implements VPaintableWidget, Field, -public class VTextualDate extends VDateField implements Paintable, Field, -- ChangeHandler, ContainerResizedListener, Focusable, SubPartAware { ++public class VTextualDate extends VDateField implements VPaintableWidget, ++ Field, ChangeHandler, ContainerResizedListener, Focusable, SubPartAware { private static final String PARSE_ERROR_CLASSNAME = CLASSNAME + "-parseerror"; @@@ -331,7 -340,11 +331,8 @@@ @Override public void setWidth(String newWidth) { - if (!"".equals(newWidth) && (width == null || !newWidth.equals(width))) { - if (!"".equals(newWidth) && (isUndefinedWidth() || !newWidth.equals(width))) { - if (BrowserInfo.get().isIE6()) { - // in IE6 cols ~ min-width - DOM.setElementProperty(text.getElement(), "size", "1"); - } ++ if (!"".equals(newWidth) ++ && (isUndefinedWidth() || !newWidth.equals(width))) { needLayout = true; width = newWidth; super.setWidth(width); @@@ -340,16 -353,22 +341,18 @@@ needLayout = false; } } else { - if ("".equals(newWidth) && width != null && !"".equals(width)) { + if ("".equals(newWidth) && !isUndefinedWidth()) { - // Changing from defined to undefined - if (BrowserInfo.get().isIE6()) { - // revert IE6 hack - DOM.setElementProperty(text.getElement(), "size", ""); - } super.setWidth(""); - needLayout = true; - iLayout(); - needLayout = false; + iLayout(true); width = null; } } } + + protected boolean isUndefinedWidth() { - return width == null || "".equals(width); ++ return width == null || "".equals(width); + } + /** * Returns pixels in x-axis reserved for other than textfield content. * diff --cc src/com/vaadin/terminal/gwt/client/ui/VWindow.java index c1ef2bbac4,7b9ece24c9..95ab0dc773 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java @@@ -703,28 -777,70 +709,62 @@@ public class VWindow extends VOverlay i } /* - * Shows (or hides) an empty div on top of all other content; used when - * resizing or moving, so that iframes (etc) do not steal event. + * Shows an empty div on top of all other content; used when moving, so that + * iframes (etc) do not steal event. */ - private void showDraggingCurtain(boolean show) { - if (show && draggingCurtain == null) { + private void showDraggingCurtain() { - setFF2CaretFixEnabled(false); // makes FF2 slow - + DOM.appendChild(RootPanel.getBodyElement(), getDraggingCurtain()); + } - draggingCurtain = DOM.createDiv(); - DOM.setStyleAttribute(draggingCurtain, "position", "absolute"); - DOM.setStyleAttribute(draggingCurtain, "top", "0px"); - DOM.setStyleAttribute(draggingCurtain, "left", "0px"); - DOM.setStyleAttribute(draggingCurtain, "width", "100%"); - DOM.setStyleAttribute(draggingCurtain, "height", "100%"); - DOM.setStyleAttribute(draggingCurtain, "zIndex", "" - + VOverlay.Z_INDEX); + private void hideDraggingCurtain() { + if (draggingCurtain != null) { - setFF2CaretFixEnabled(true); // makes FF2 slow - + DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain); + } + } - DOM.appendChild(RootPanel.getBodyElement(), draggingCurtain); - } else if (!show && draggingCurtain != null) { + /* + * Shows an empty div on top of all other content; used when resizing, so + * that iframes (etc) do not steal event. + */ + private void showResizingCurtain() { - setFF2CaretFixEnabled(false); // makes FF2 slow - + DOM.appendChild(RootPanel.getBodyElement(), getResizingCurtain()); + } - DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain); - draggingCurtain = null; + private void hideResizingCurtain() { + if (resizingCurtain != null) { - setFF2CaretFixEnabled(true); // makes FF2 slow - + DOM.removeChild(RootPanel.getBodyElement(), resizingCurtain); } + } + + private Element getDraggingCurtain() { + if (draggingCurtain == null) { + draggingCurtain = createCurtain(); + draggingCurtain.setClassName(CLASSNAME + "-draggingCurtain"); + } + + return draggingCurtain; + } + + private Element getResizingCurtain() { + if (resizingCurtain == null) { + resizingCurtain = createCurtain(); + resizingCurtain.setClassName(CLASSNAME + "-resizingCurtain"); + } + + return resizingCurtain; + } + + private Element createCurtain() { + Element curtain = DOM.createDiv(); + + DOM.setStyleAttribute(curtain, "position", "absolute"); + DOM.setStyleAttribute(curtain, "top", "0px"); + DOM.setStyleAttribute(curtain, "left", "0px"); + DOM.setStyleAttribute(curtain, "width", "100%"); + DOM.setStyleAttribute(curtain, "height", "100%"); + DOM.setStyleAttribute(curtain, "zIndex", "" + VOverlay.Z_INDEX); + return curtain; } private void setResizable(boolean resizability) { diff --cc src/com/vaadin/ui/Table.java index ec620ddcd5,199a6805f6..6a946560cf --- a/src/com/vaadin/ui/Table.java +++ b/src/com/vaadin/ui/Table.java @@@ -5132,60 -5152,13 +5135,69 @@@ public class Table extends AbstractSele return rowGenerator; } + /** + * Sets a converter for a property id. + *

+ * The converter is used to format the the data for the given property id + * before displaying it in the table. + *

+ * + * @param propertyId + * The propertyId to format using the converter + * @param converter + * The converter to use for the property id + */ + public void setConverter(Object propertyId, Converter converter) { + if (!getContainerPropertyIds().contains(propertyId)) { + throw new IllegalArgumentException("PropertyId " + propertyId + + " must be in the container"); + } + // FIXME: This check should be here but primitive types like Boolean + // formatter for boolean property must be handled + + // if (!converter.getSourceType().isAssignableFrom(getType(propertyId))) + // { + // throw new IllegalArgumentException("Property type (" + // + getType(propertyId) + // + ") must match converter source type (" + // + converter.getSourceType() + ")"); + // } + propertyValueConverters.put(propertyId, + (Converter) converter); + refreshRowCache(); + } + + /** + * Checks if there is a converter set explicitly for the given property id. + * + * @param propertyId + * The propertyId to check + * @return true if a converter has been set for the property id, false + * otherwise + */ + protected boolean hasConverter(Object propertyId) { + return propertyValueConverters.containsKey(propertyId); + } + + /** + * Returns the converter used to format the given propertyId. + * + * @param propertyId + * The propertyId to check + * @return The converter used to format the propertyId or null if no + * converter has been set + */ + public Converter getConverter(Object propertyId) { + return propertyValueConverters.get(propertyId); + } + + @Override + public void setVisible(boolean visible) { + if (!isVisible() && visible) { + // We need to ensure that the rows are sent to the client when the + // Table is made visible if it has been rendered as invisible. + setRowCacheInvalidated(true); + } + super.setVisible(visible); + } } diff --cc tests/integration_tests.xml index 60e4882044,fa8defd14e..1b37347ddd --- a/tests/integration_tests.xml +++ b/tests/integration_tests.xml @@@ -1,16 -1,12 +1,16 @@@ - + + + + - - - - + + + + @@@ -97,24 -100,30 +97,22 @@@
- - - - - - - - - - + - - +
+ - + - - +
+ - @@@ -131,11 -139,23 +128,16 @@@
- + + + + + + + - - - - - - - - + @@@ -251,17 -286,17 +268,16 @@@
- + - + - + - - + - - + @@@ -282,8 -317,8 +298,7 @@@ - - + - @@@ -301,6 -338,8 +317,7 @@@ + - @@@ -312,31 -351,31 +329,30 @@@ - - - + - + - - + + - - Delaying startup of ${target-server} with ${sleepTime} seconds + + Delaying startup of ${target-server} with ${sleepTime} seconds - - - + + + - + - + @@@ -367,20 -406,20 +383,20 @@@ - + - + - + - - - + + + - + @@@ -389,46 -428,46 +405,46 @@@ - + - + - + - + ##teamcity[testStarted name='${target-server}' flowId='${target-server}'] - + - + - + ##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}'] - + ##teamcity[testFinished name='${target-server}' flowId='${target-server}']" - + - + - - - + + + - + - + ##teamcity[testStarted name='${target-server}' flowId='${target-server}'] - + @@@ -439,10 -478,10 +455,10 @@@ ##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}']" - + ##teamcity[testFinished name='${target-server}' flowId='${target-server}']" - + diff --cc tests/server-side/com/vaadin/tests/VaadinClasses.java index 0000000000,e02c4f0b6e..707fc020b6 mode 000000,100644..100644 --- a/tests/server-side/com/vaadin/tests/VaadinClasses.java +++ b/tests/server-side/com/vaadin/tests/VaadinClasses.java @@@ -1,0 -1,236 +1,248 @@@ + package com.vaadin.tests; + + import java.io.File; + import java.io.IOException; + import java.lang.reflect.Method; + import java.lang.reflect.Modifier; + import java.net.JarURLConnection; + import java.net.URISyntaxException; + import java.net.URL; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Collections; + import java.util.Comparator; + import java.util.Enumeration; + import java.util.List; + import java.util.jar.JarEntry; + + import org.junit.Test; + + import com.vaadin.Application; + import com.vaadin.ui.Component; + import com.vaadin.ui.ComponentContainer; + import com.vaadin.ui.CustomComponent; + import com.vaadin.ui.DragAndDropWrapper; ++import com.vaadin.ui.Field; + import com.vaadin.ui.HorizontalSplitPanel; + import com.vaadin.ui.LoginForm; + import com.vaadin.ui.PopupView; ++import com.vaadin.ui.Root; + import com.vaadin.ui.SplitPanel; + import com.vaadin.ui.VerticalSplitPanel; + import com.vaadin.ui.Window; + + @SuppressWarnings("deprecation") + public class VaadinClasses { + + public static void main(String[] args) { + System.out.println("ComponentContainers"); + System.out.println("==================="); + for (Class c : getComponentContainers()) { + System.out.println(c.getName()); + } + System.out.println(); + System.out.println("Components"); + System.out.println("=========="); + for (Class c : getComponents()) { + System.out.println(c.getName()); + } + System.out.println(); + System.out.println("Server side classes"); + System.out.println("==================="); + for (Class c : getAllServerSideClasses()) { + System.out.println(c.getName()); + } + } + + public static List> getComponents() { + try { + return findClasses(Component.class, "com.vaadin.ui"); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + ++ public static List> getFields() { ++ try { ++ return findClasses(Field.class, "com.vaadin.ui"); ++ } catch (IOException e) { ++ e.printStackTrace(); ++ return null; ++ } ++ } ++ + public static List> getAllServerSideClasses() { + try { + return findClassesNoTests(Object.class, "com.vaadin", new String[] { + "com.vaadin.tests", "com.vaadin.terminal.gwt.client" }); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public static List> getComponentContainers() { + try { + return findClasses(ComponentContainer.class, "com.vaadin.ui"); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public static List> getComponentContainersSupportingAddRemoveComponent() { + List> classes = getComponentContainers(); + classes.remove(PopupView.class); + classes.remove(CustomComponent.class); + classes.remove(DragAndDropWrapper.class); + classes.remove(CustomComponent.class); + classes.remove(LoginForm.class); ++ classes.remove(Root.class); + + return classes; + } + + public static List> getComponentContainersSupportingUnlimitedNumberOfComponents() { + List> classes = getComponentContainersSupportingAddRemoveComponent(); + classes.remove(SplitPanel.class); + classes.remove(VerticalSplitPanel.class); + classes.remove(HorizontalSplitPanel.class); + classes.remove(Window.class); + + return classes; + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + public static List> getBasicComponentTests() { + try { + // Given as name to avoid dependencies on testbench source folder + return (List) findClasses( + Class.forName("com.vaadin.tests.components.AbstractComponentTest"), + "com.vaadin.tests.components"); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + } + + private static List> findClasses(Class baseClass, + String basePackage) throws IOException { + return findClasses(baseClass, basePackage, new String[] {}); + } + + private static List> findClasses(Class baseClass, + String basePackage, String[] ignoredPackages) throws IOException { + List> classes = new ArrayList>(); + String basePackageDirName = "/" + basePackage.replace('.', '/'); + URL location = Application.class.getResource(basePackageDirName); + if (location.getProtocol().equals("file")) { + try { + File f = new File(location.toURI()); + if (!f.exists()) { + throw new IOException("Directory " + f.toString() + + " does not exist"); + } + findPackages(f, basePackage, baseClass, classes, + ignoredPackages); + } catch (URISyntaxException e) { + throw new IOException(e.getMessage()); + } + } else if (location.getProtocol().equals("jar")) { + JarURLConnection juc = (JarURLConnection) location.openConnection(); + findPackages(juc, basePackage, baseClass, classes); + } + + Collections.sort(classes, new Comparator>() { + + public int compare(Class o1, Class o2) { + return o1.getName().compareTo(o2.getName()); + } + + }); + return classes; + } + + private static List> findClassesNoTests( + Class baseClass, String basePackage, String[] ignoredPackages) + throws IOException { + List> classes = findClasses(baseClass, basePackage, + ignoredPackages); + List> classesNoTests = new ArrayList>(); + for (Class clazz : classes) { + if (!clazz.getName().contains("Test")) { + boolean testPresent = false; + for (Method method : clazz.getMethods()) { + if (method.isAnnotationPresent(Test.class)) { + testPresent = true; + break; + } + } + if (!testPresent) { + classesNoTests.add(clazz); + } + } + } + return classesNoTests; + } + + private static void findPackages(JarURLConnection juc, + String javaPackage, Class baseClass, + Collection> result) throws IOException { + String prefix = "com/vaadin/ui"; + Enumeration ent = juc.getJarFile().entries(); + while (ent.hasMoreElements()) { + JarEntry e = ent.nextElement(); + if (e.getName().endsWith(".class") + && e.getName().startsWith(prefix)) { + String fullyQualifiedClassName = e.getName().replace('/', '.') + .replace(".class", ""); + addClassIfMatches(result, fullyQualifiedClassName, baseClass); + } + } + } + + private static void findPackages(File parent, String javaPackage, + Class baseClass, Collection> result, + String[] ignoredPackages) { + for (String ignoredPackage : ignoredPackages) { + if (javaPackage.equals(ignoredPackage)) { + return; + } + } + + for (File file : parent.listFiles()) { + if (file.isDirectory()) { + findPackages(file, javaPackage + "." + file.getName(), + baseClass, result, ignoredPackages); + } else if (file.getName().endsWith(".class")) { + String fullyQualifiedClassName = javaPackage + "." + + file.getName().replace(".class", ""); + addClassIfMatches(result, fullyQualifiedClassName, baseClass); + } + } + + } + + @SuppressWarnings("unchecked") + private static void addClassIfMatches( + Collection> result, + String fullyQualifiedClassName, Class baseClass) { + try { + // Try to load the class + + Class c = Class.forName(fullyQualifiedClassName); + if (baseClass.isAssignableFrom(c) + && !Modifier.isAbstract(c.getModifiers())) { + result.add((Class) c); + } + } catch (Exception e) { + // Could ignore that class cannot be loaded + e.printStackTrace(); + } catch (LinkageError e) { + // Ignore. Client side classes will at least throw LinkageErrors + } + + } + } diff --cc tests/test.xml index d4a8f5918c,39d45d2a74..9d060c9a29 --- a/tests/test.xml +++ b/tests/test.xml @@@ -93,8 -127,9 +93,8 @@@ - - - + - ++ diff --cc tests/testbench/com/vaadin/tests/Components.java index 414c97c951,d7bc18e2f6..6bc6860607 --- a/tests/testbench/com/vaadin/tests/Components.java +++ b/tests/testbench/com/vaadin/tests/Components.java @@@ -29,14 -27,15 +29,14 @@@ import com.vaadin.ui.Root.LegacyWindow import com.vaadin.ui.Tree; import com.vaadin.ui.Tree.ItemStyleGenerator; import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; -public class Components extends Application { +public class Components extends Application.LegacyApplication { private static final Object CAPTION = "c"; - private Map>, String> tests = new HashMap>, String>(); + private Map, String> tests = new HashMap, String>(); private Tree naviTree; private HorizontalSplitPanel sp; - private Window mainWindow; + private LegacyWindow mainWindow; private final Embedded applicationEmbedder = new Embedded(); private String baseUrl; private List> componentsWithoutTests = new ArrayList>(); diff --cc tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java index 85cc6ca5e1,ff3c304600..447b5b4be6 --- a/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java +++ b/tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java @@@ -16,8 -19,8 +20,8 @@@ import com.vaadin.ui.HorizontalLayout import com.vaadin.ui.NativeSelect; import com.vaadin.ui.VerticalLayout; -public class OrderedLayoutCases extends TestBase { +public class OrderedLayoutCases extends AbstractTestRoot { - private static final String[] dimensionValues = { "-1px", "5px", "300px", + private static final String[] dimensionValues = { "-1px", "5px", "350px", "800px", "100%", "50%" }; private static class SampleChild extends VerticalLayout { @@@ -102,11 -105,17 +106,17 @@@ } private AbstractOrderedLayout currentLayout; + private HorizontalLayout sizeBar; @Override - protected void setup() { + protected void setup(WrappedRequest request) { - TestUtils.injectCSS(getRoot(), - ".showBorders {border: 1px solid black};"); + TestUtils + .injectCSS( - getMainWindow(), ++ getRoot(), + ".sampleChild, .theLayout {border: 1px solid black;}" + + ".theLayout > div > div:first-child {background: aqua;}" + + ".theLayout > div > div:first-child + div {background: yellow;}" + + ".theLayout > div > div:first-child + div + div {background: lightgrey;}"); currentLayout = new HorizontalLayout(); for (int i = 0; i < 3; i++) { @@@ -190,9 -347,8 +348,8 @@@ } @Override - protected Integer getTicketNumber() { - // TODO Auto-generated method stub - return null; - protected String getDescription() { ++ protected String getTestDescription() { + return "Tester application for exploring how Horizontal/VerticalLayout reacts to various settings "; } } diff --cc tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java index 0000000000,fe99cfaf2a..3b0234d805 mode 000000,100644..100644 --- a/tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java +++ b/tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java @@@ -1,0 -1,91 +1,88 @@@ + package com.vaadin.tests.components.table; + + import com.vaadin.tests.components.TestBase; + import com.vaadin.ui.Button; + import com.vaadin.ui.Button.ClickEvent; + import com.vaadin.ui.HorizontalLayout; + import com.vaadin.ui.Layout; + import com.vaadin.ui.Table; + import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; + + public class ScrollDetachSynchronization extends TestBase { + + @Override + public void setup() { - Window mainWindow = new Window("Synctest Application"); - mainWindow.setContent(buildLayout()); - setMainWindow(mainWindow); ++ getMainWindow().setContent(buildLayout()); + } + + @Override + protected String getDescription() { + return "Scrolling, then detaching, a table causes out of sync on IE"; + } + + @Override + protected Integer getTicketNumber() { + return 6970; + } + + private Layout buildLayout() { + final VerticalLayout mainLayout = new VerticalLayout(); + mainLayout.setSizeFull(); + + HorizontalLayout buttonBar = new HorizontalLayout(); + buttonBar.setSizeUndefined(); + Button first = new Button("First layout"); + Button second = new Button("Second layout"); + first.setDebugId("FirstButton"); + second.setDebugId("SecondButton"); + buttonBar.addComponent(first); + buttonBar.addComponent(second); + mainLayout.addComponent(buttonBar); + + final HorizontalLayout firstLayout = buildTestLayout(true); + final HorizontalLayout secondLayout = buildTestLayout(false); + + mainLayout.addComponent(firstLayout); + mainLayout.setExpandRatio(firstLayout, 1); + + first.addListener(new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + if (mainLayout.getComponent(1).equals(secondLayout)) { + mainLayout.replaceComponent(secondLayout, firstLayout); + mainLayout.setExpandRatio(firstLayout, 1); + } + } + }); + second.addListener(new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + if (mainLayout.getComponent(1).equals(firstLayout)) { + mainLayout.replaceComponent(firstLayout, secondLayout); + mainLayout.setExpandRatio(secondLayout, 1); + } + } + }); + return mainLayout; + } + + private HorizontalLayout buildTestLayout(boolean first) { + String which = first ? "First" : "Second"; + + HorizontalLayout hl = new HorizontalLayout(); + hl.setSizeFull(); + hl.setDebugId(which + "Layout"); + + Table t = new Table(); + t.addContainerProperty("name", String.class, null); + for (int i = 0; i < 10; i++) { + String id = which + " " + i; + t.addItem(new String[] { id }, id); + } + t.setDebugId(which + "Table"); + t.setItemCaptionPropertyId("name"); + t.setSizeFull(); + + hl.addComponent(t); + + return hl; + } + } diff --cc tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java index 8540e39c8c,f7d85f1a3c..bce96ebced --- a/tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java +++ b/tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java @@@ -10,12 -10,16 +10,16 @@@ public class TableHeaderZoom extends Te @Override protected void setup() { Table table = new Table(); - table.setHeight("100px"); - table.setWidth("200px"); - table.setEnabled(false); + table.setHeight("400px"); + table.setWidth("400px"); table.addContainerProperty("Column 1", String.class, ""); + table.addContainerProperty("Column 2", String.class, ""); + + for (int i = 0; i < 100; ++i) { + table.addItem(new Object[] { "" + i, "foo" }, i); + } - Window main = getMainWindow(); + LegacyWindow main = getMainWindow(); main.setContent(new CssLayout()); main.addComponent(table); } diff --cc tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java index 0000000000,6aac7caddd..c04c9d6c13 mode 000000,100644..100644 --- a/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java +++ b/tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java @@@ -1,0 -1,57 +1,59 @@@ + package com.vaadin.tests.components.textfield; + ++import com.vaadin.data.Property.ValueChangeEvent; ++import com.vaadin.data.Property.ValueChangeListener; + import com.vaadin.event.ShortcutAction.KeyCode; + import com.vaadin.tests.components.TestBase; + 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.CheckBox; + import com.vaadin.ui.TextField; + + public class TextFieldInputPromptAndClickShortcut extends TestBase { + + @Override + protected void setup() { + final Log log = new Log(5); + + final TextField textField = new TextField(); + Button button = new Button("Show Text", new ClickListener() { + public void buttonClick(ClickEvent event) { + log.log("Field value: " + textField.getValue()); + } + }); + button.setClickShortcut(KeyCode.ESCAPE); + - final CheckBox inputPromptSelection = new CheckBox("Input prompt", - new ClickListener() { - public void buttonClick(ClickEvent event) { - if (event.getButton().getValue() == Boolean.TRUE) { - textField.setInputPrompt("Input prompt"); - } else { - textField.setInputPrompt(null); - } - log.log("Set input prompt: " - + textField.getInputPrompt()); - } - }); ++ final CheckBox inputPromptSelection = new CheckBox("Input prompt"); ++ inputPromptSelection.setImmediate(true); ++ inputPromptSelection.addListener(new ValueChangeListener() { ++ public void valueChange(ValueChangeEvent event) { ++ if (event.getProperty().getValue() == Boolean.TRUE) { ++ textField.setInputPrompt("Input prompt"); ++ } else { ++ textField.setInputPrompt(null); ++ } ++ log.log("Set input prompt: " + textField.getInputPrompt()); ++ } ++ }); + inputPromptSelection.setImmediate(true); + + addComponent(textField); + addComponent(button); + addComponent(inputPromptSelection); + addComponent(log); + } + + @Override + protected String getDescription() { + return "With the input propmpt enabled, enter something into the field, press enter, remove the entered text and press the button. The previous text is still reported as the value. Without the input prompt, the new value is instead reported as blank."; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + + }