]> source.dussan.org Git - vaadin-framework.git/commitdiff
Merge remote-tracking branch 'origin/6.8'
authorArtur Signell <artur@vaadin.com>
Fri, 27 Jan 2012 12:17:08 +0000 (14:17 +0200)
committerArtur Signell <artur@vaadin.com>
Fri, 27 Jan 2012 12:17:08 +0000 (14:17 +0200)
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

29 files changed:
1  2 
WebContent/VAADIN/themes/base/datefield/datefield.css
WebContent/VAADIN/themes/base/table/table.css
WebContent/VAADIN/themes/base/tabsheet/tabsheet.css
WebContent/VAADIN/themes/base/window/window.css
WebContent/VAADIN/themes/chameleon/components/tabsheet/tabsheet.css
build/build.properties
build/build.xml
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/Util.java
src/com/vaadin/terminal/gwt/client/VDebugConsole.java
src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.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/VTabsheet.java
src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
src/com/vaadin/terminal/gwt/client/ui/VView.java
src/com/vaadin/terminal/gwt/client/ui/VWindow.java
src/com/vaadin/ui/Component.java
src/com/vaadin/ui/Table.java
tests/integration_tests.xml
tests/server-side/com/vaadin/tests/VaadinClasses.java
tests/test.xml
tests/testbench/com/vaadin/tests/Components.java
tests/testbench/com/vaadin/tests/components/orderedlayout/OrderedLayoutCases.java
tests/testbench/com/vaadin/tests/components/table/ScrollDetachSynchronization.java
tests/testbench/com/vaadin/tests/components/table/TableHeaderZoom.java
tests/testbench/com/vaadin/tests/components/textfield/TextFieldInputPromptAndClickShortcut.java

index 88d6f92c79b654f8d4ba27420b6dfa57f5f15b02,8e2e9aeb2b2c1cefe8b3e01292dfb400de3f59a8..7af440c735bdd436e7d5a1c95e15f6601a1b4acb
  .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;
  }
index e2b2a16ffe98d45d8b6dced7df752c6847a12250,d789e8b54886f9f9dc762d5cdcba0d708fb48710..877faf364f252dbaad249979a99c39fcd7dad787
        position: relative; /* hide this from IE, it works without it */
        cursor: pointer;
  }
 -.v-ie6 .v-table-column-selector,
 -.v-ie7 .v-table-column-selector {
 -      position: static;
 -}
+ .v-table.v-disabled .v-table-column-selector {
+       cursor: default;
+ }
  .v-table-focus-slot-left {
        border-left: 2px solid #999;
        float: none;
Simple merge
diff --cc build/build.xml
index e21984cf061087489a1b3f9792e68b5b276e8c43,1fdcc0ee25f932281b4e50c163e2fead0e27502f..05d3a931adf4bfa03d2221babc7f907f5db473c6
  
      <target name="package-liferay-zip" depends="clean-result, init, build, internal-package-liferay">
      </target>
 -
 -    <!-- Locations of Ant task JARs - build properties not yet read at this point -->
 -    <property name="ant.task.jar.antcontrib" value="build/lib/ant-contrib-1.0b3.jar" />
 -    <property name="ant.task.jar.maven" value="build/lib/maven-ant-tasks-2.0.10.jar" />
 -      
 -      <path id="emma.lib" >
 -              <pathelement location="build/lib/emma_ant.jar" />
 -              <pathelement location="build/lib/emma-2.0.5312-patched.jar" />
 -      </path>
        
 -      <taskdef resource="emma_ant.properties" classpathref="emma.lib" />      
 -
 -    <!-- ant contrib required for flow control (for loop, if, property override)   -->
 -    <!-- Note that we have to use a namespace to avoid clash when running sub-ant. -->
 -    <taskdef uri="antlib:net.sf.antcontrib" resource="net/sf/antcontrib/antlib.xml">
 -        <classpath>
 -            <pathelement location="${ant.task.jar.antcontrib}" />
 -        </classpath>
 -    </taskdef>
 -
 -    <!-- ant contrib for Maven integration -->
 -    <path id="maven-ant-tasks.classpath" path="${ant.task.jar.maven}" />
 -    <typedef resource="org/apache/maven/artifact/ant/antlib.xml"
 -             uri="antlib:org.apache.maven.artifact.ant"
 -             classpathref="maven-ant-tasks.classpath" />
 +    <target name="init-deps" depends="common.init-deps" >
 +        <property name="ivy.resolved" value="1" />
 +        <ivy:resolve file="build/ivy/ivy.xml" resolveid="common" conf="ss.compile, cs.compile, ss.test.runtime"/>
 +        <ivy:cachepath pathid="compile.classpath" conf="ss.compile"/>
 +        <ivy:cachepath pathid="client-side.compile.classpath" conf="cs.compile"/>
 +        <ivy:cachepath pathid="test.runtime.classpath" conf="ss.test.runtime"/>
 +    </target>
  
 -      
      <!-- Clean results - - - - - - - - - - - - - - - - - - - - - - - - - -->
-     <target name="clean-result" depends="">
-         <property file="build/build.properties" />
+     <target name="clean-result" depends="build.properties">
  
          <!-- Clean build result directory. -->
          <delete dir="${result-path}" includes="**/*" followsymlinks="false" defaultexcludes="false" includeemptydirs="true" failonerror="false"/>
      <!-- Initialization - - - - - - - - - - - - - - - - - - - - - - - - - - -->
      <!-- ================================================================== -->
  
-      <target name="init" depends="init-deps">
 -    <target name="init" depends="check-java-version, build.properties">
++     <target name="init" depends="init-deps, build.properties">
          <!-- Current timestamp in different formats. -->
          <tstamp>
              <format property="build.date" pattern="yyyy-MM-dd"/>
     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
      <target name="webcontent" depends="preprocess-src,defaulttheme">
  
 -        <!-- copy 3rd part libraries used by tests -->
 -        <copy todir="${output-dir}/WebContent/tests/lib">
 -            <fileset dir="lib/core">
 -                <include name="jetty/**/*" />
 -            </fileset>
 -              <fileset dir="build/lib">
 -                      <include name="emma-2.0.5312-patched.jar" />
 -              </fileset>
 -        </copy>
 -
          <!-- Add WebContent -->
-         <echo>Adding VAADIN/themes and demo files.</echo>
+         <echo>Adding VAADIN/themes and META-INF</echo>
          <copy todir="${output-dir}/WebContent">
              <fileset dir="WebContent">
                  <exclude name="**/.svn" />
--                <!-- TODO check what is necessary -->
-                 <include name="demo/**/*" />
+                 <include name="WEB-INF/lib/hsqldb.jar" />
                  <include name="VAADIN/themes/**/*" />
 +              <include name="VAADIN/vaadinBootstrap.js" />
                  <include name="META-INF/**/*" />
              </fileset>
          </copy>
      </target>
  
      <target name="compile-helpers" depends="init">
 -        <javac source="1.5" target="1.5" srcdir="build/buildhelpers" classpath="build/smartsprites/lib/smartsprites-0.2.3-itmill.jar" includeantruntime="false"/>
 +      <mkdir dir="${buildhelpers-classes}" />
 +        <ivy:cachepath pathid="buildhelpers.dependencies" resolveId="buildhelpers" conf="compile" file="build/ivy/buildhelpers-ivy.xml"/>        
 +        <javac source="1.5" target="1.5" includeantruntime="false" srcdir="${buildhelpers-src}" 
-               classpathref="buildhelpers.dependencies" destdir="${buildhelpers-classes}" debug="true" encoding="UTF-8" />
++                      classpathref="buildhelpers.dependencies" destdir="${buildhelpers-classes}" debug="true" encoding="UTF-8" />
      </target>
      
      <target name="defaulttheme" depends="init, compile-helpers">
      </target>
  
      <!-- The widgetset generator is currently compiled along with rest of server-side Java. -->    
-     <target name="compile-widgetset-generator" depends="init, preprocess-src, compile-java"/>
-     
+     <target name="compile-widgetset-generator" depends="compile-core"/>
 -
 -    <path id="widgetset-compile-classpath">
 -        <pathelement location="${lib-gwt-user}" />
 -        <pathelement location="${lib-gwt-dev}" />
 -        <pathelement location="${lib-gwt-validation}" />
 -        <pathelement location="${lib-gwt-validation-src}" />
 -        <pathelement location="${result-classes-core}" />
 -        <pathelement location="${result-src-core}" />
 -    </path>
 -    
 -    <target name="compile-widgetset" description="Compiles the widgetset given as the first parameter">
 +    <target name="compile-widgetset" depends="init-deps" description="Compiles the widgetset given as the first parameter">
          <fail unless="widgetset" message="No widgetset parameter set"/>
          <property name="widgetset-style" value="OBF" />
        <property name="widgetset-localWorkers" value="4" />
                </emma>                 
          <junit printsummary="yes"> 
              <classpath> 
-                 <pathelement path="${result-path}/junit_emma_classes" />
-                 <pathelement path="${result-path}/classes" />                 
+                 <pathelement path="${result-classes-core-for-emma-junit}" />
+                 <pathelement path="${result-classes-core}" />
+                 <pathelement path="${result-classes-junit}" />
 -              <path refid="emma.lib" />
 -                <path refid="compile.classpath"/>
 +              <path refid="test.runtime.classpath"></path>
-                 <path refid="compile.classpath"></path>
              </classpath>
                <jvmarg value="-Demma.coverage.out.file=../${result-path}/unittests.ec" />
  
              <batchtest fork="yes">
-                 <fileset dir="tests/server-side" includes="**/*.java" excludes="**/Abstract*.java,com/vaadin/tests/data/bean/*.java,com/vaadin/tests/util/*.java" />
 -                <fileset dir="tests/server-side" includes="**/*.java" excludes="**/Abstract*.java,**/VaadinClasses.java" />
++                <fileset dir="tests/server-side" includes="**/*.java" excludes="**/Abstract*.java,com/vaadin/tests/data/bean/*.java,com/vaadin/tests/util/*.java,**/VaadinClasses.java" />
                  <fileset dir="tests/client-side" includes="**/*.java" excludes="**/Abstract*.java" />
              </batchtest>
          </junit>
index 18f7b19e925b430b3967c6603705a36fe6c314d2,944d9b5974b5e2912b42ea7dcc7db79d70d6bb09..e659a18477cd82aef841e55e72ba931a042d67c8
@@@ -525,6 -536,26 +548,25 @@@ public class ApplicationConnection 
                          return;
                      }
  
 -                    final Date start = new Date();
+                     String contentType = response.getHeader("Content-Type");
+                     if (contentType == null
+                             || !contentType.startsWith("application/json")) {
+                         /*
+                          * A servlet filter or equivalent may have intercepted
+                          * the request and served non-UIDL content (for
+                          * instance, a login page if the session has expired.)
+                          * If the response contains a magic substring, do a
+                          * synchronous refresh. See #8241.
+                          */
+                         MatchResult refreshToken = RegExp.compile(
+                                 UIDL_REFRESH_TOKEN + "(:\\s*(.*?))?(\\s|$)")
+                                 .exec(response.getText());
+                         if (refreshToken != null) {
+                             redirect(refreshToken.getGroup(2));
+                             return;
+                         }
+                     }
                      // for(;;);[realjson]
                      final String jsonText = response.getText().substring(9,
                              response.getText().length() - 1);
              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) {
              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(" ");
              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") : "";
  
index 6d068dd11a1d846e79471aae4aac7b37138aa217,174e66b7aaba0abf988e541989eebd967f818a85..e6305b3c42f830c7d663ca906cb09e71cdcd0fa9
@@@ -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");
              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);
           *            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;
index 7de1658c5da36d5f81ac509f0a02530c87a4525c,549248aab38a4178443dff40b26a1ceb9e49b018..44fb9ac69caabba574cd4cdd32d170ba7ae801b1
- /*
- @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.
-  * 
-  * <b>Note:</b> To change the keyboard assignments used in the popup dialog you
-  * should extend <code>com.vaadin.terminal.gwt.client.ui.VCalendarPanel</code>
-  * and then pass set it by calling the
-  * <code>setCalendarPanel(VCalendarPanel panel)</code> method.
-  * 
-  */
- public class VPopupCalendar extends VTextualDate implements VPaintableWidget,
-         Field, ClickHandler, CloseHandler<PopupPanel>, 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<PopupPanel> 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);
-     }
- }
+ /*\r
+ @VaadinApache2LicenseForJavaFiles@\r
+  */\r
\r
+ package com.vaadin.terminal.gwt.client.ui;\r
\r
+ import java.util.Date;\r
\r
+ import com.google.gwt.core.client.GWT;\r
+ import com.google.gwt.event.dom.client.ClickEvent;\r
+ import com.google.gwt.event.dom.client.ClickHandler;\r
+ import com.google.gwt.event.dom.client.DomEvent;\r
+ import com.google.gwt.event.dom.client.KeyCodes;\r
+ import com.google.gwt.event.logical.shared.CloseEvent;\r
+ import com.google.gwt.event.logical.shared.CloseHandler;\r
+ import com.google.gwt.user.client.DOM;\r
+ import com.google.gwt.user.client.Element;\r
+ import com.google.gwt.user.client.Event;\r
+ import com.google.gwt.user.client.Timer;\r
+ import com.google.gwt.user.client.Window;\r
+ import com.google.gwt.user.client.ui.Button;\r
+ import com.google.gwt.user.client.ui.PopupPanel;\r
+ import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;\r
+ import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+ import com.vaadin.terminal.gwt.client.BrowserInfo;\r
+ import com.vaadin.terminal.gwt.client.DateTimeService;\r
 -import com.vaadin.terminal.gwt.client.Paintable;\r
++import com.vaadin.terminal.gwt.client.VPaintableWidget;\r
+ import com.vaadin.terminal.gwt.client.UIDL;\r
+ import com.vaadin.terminal.gwt.client.VConsole;\r
+ import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusChangeListener;\r
+ import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.FocusOutListener;\r
+ import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.SubmitListener;\r
+ import com.vaadin.terminal.gwt.client.ui.VCalendarPanel.TimeChangeListener;\r
\r
+ /**\r
+  * Represents a date selection component with a text field and a popup date\r
+  * selector.\r
+  * \r
+  * <b>Note:</b> To change the keyboard assignments used in the popup dialog you\r
+  * should extend <code>com.vaadin.terminal.gwt.client.ui.VCalendarPanel</code>\r
+  * and then pass set it by calling the\r
+  * <code>setCalendarPanel(VCalendarPanel panel)</code> method.\r
+  * \r
+  */\r
 -public class VPopupCalendar extends VTextualDate implements Paintable, Field,\r
 -        ClickHandler, CloseHandler<PopupPanel>, SubPartAware {\r
++public class VPopupCalendar extends VTextualDate implements VPaintableWidget,\r
++        Field, ClickHandler, CloseHandler<PopupPanel>, SubPartAware {\r
\r
+     private static final String POPUP_PRIMARY_STYLE_NAME = VDateField.CLASSNAME\r
+             + "-popup";\r
\r
+     private final Button calendarToggle;\r
\r
+     private VCalendarPanel calendar;\r
\r
+     private final VOverlay popup;\r
+     private boolean open = false;\r
+     private boolean parsable = true;\r
\r
+     public VPopupCalendar() {\r
+         super();\r
\r
+         calendarToggle = new Button();\r
+         calendarToggle.setStyleName(CLASSNAME + "-button");\r
+         calendarToggle.setText("");\r
+         calendarToggle.addClickHandler(this);\r
+         // -2 instead of -1 to avoid FocusWidget.onAttach to reset it\r
+         calendarToggle.getElement().setTabIndex(-2);\r
+         add(calendarToggle);\r
\r
+         calendar = GWT.create(VCalendarPanel.class);\r
+         calendar.setFocusOutListener(new FocusOutListener() {\r
+             public boolean onFocusOut(DomEvent<?> event) {\r
+                 event.preventDefault();\r
+                 closeCalendarPanel();\r
+                 return true;\r
+             }\r
+         });\r
\r
+         calendar.setSubmitListener(new SubmitListener() {\r
+             public void onSubmit() {\r
+                 // Update internal value and send valuechange event if immediate\r
+                 updateValue(calendar.getDate());\r
\r
+                 // Update text field (a must when not immediate).\r
+                 buildDate(true);\r
\r
+                 closeCalendarPanel();\r
+             }\r
\r
+             public void onCancel() {\r
+                 closeCalendarPanel();\r
+             }\r
+         });\r
\r
+         popup = new VOverlay(true, true, true);\r
+         popup.setStyleName(POPUP_PRIMARY_STYLE_NAME);\r
+         popup.setWidget(calendar);\r
+         popup.addCloseHandler(this);\r
\r
+         DOM.setElementProperty(calendar.getElement(), "id",\r
+                 "PID_VAADIN_POPUPCAL");\r
\r
+         sinkEvents(Event.ONKEYDOWN);\r
\r
+     }\r
\r
+     @SuppressWarnings("deprecation")\r
+     private void updateValue(Date newDate) {\r
+         Date currentDate = getCurrentDate();\r
+         if (currentDate == null || newDate.getTime() != currentDate.getTime()) {\r
+             setCurrentDate((Date) newDate.clone());\r
+             getClient().updateVariable(getId(), "year",\r
+                     newDate.getYear() + 1900, false);\r
+             if (getCurrentResolution() > VDateField.RESOLUTION_YEAR) {\r
+                 getClient().updateVariable(getId(), "month",\r
+                         newDate.getMonth() + 1, false);\r
+                 if (getCurrentResolution() > RESOLUTION_MONTH) {\r
+                     getClient().updateVariable(getId(), "day",\r
+                             newDate.getDate(), false);\r
+                     if (getCurrentResolution() > RESOLUTION_DAY) {\r
+                         getClient().updateVariable(getId(), "hour",\r
+                                 newDate.getHours(), false);\r
+                         if (getCurrentResolution() > RESOLUTION_HOUR) {\r
+                             getClient().updateVariable(getId(), "min",\r
+                                     newDate.getMinutes(), false);\r
+                             if (getCurrentResolution() > RESOLUTION_MIN) {\r
+                                 getClient().updateVariable(getId(), "sec",\r
+                                         newDate.getSeconds(), false);\r
 -                                if (getCurrentResolution() == RESOLUTION_MSEC) {\r
 -                                    getClient().updateVariable(\r
 -                                            getId(),\r
 -                                            "msec",\r
 -                                            DateTimeService\r
 -                                                    .getMilliseconds(newDate),\r
 -                                            false);\r
 -                                }\r
+                             }\r
+                         }\r
+                     }\r
+                 }\r
+             }\r
+             if (isImmediate()) {\r
+                 getClient().sendPendingVariableChanges();\r
+             }\r
+         }\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see\r
+      * com.vaadin.terminal.gwt.client.ui.VTextualDate#updateFromUIDL(com.vaadin\r
+      * .terminal.gwt.client.UIDL,\r
+      * com.vaadin.terminal.gwt.client.ApplicationConnection)\r
+      */\r
+     @Override\r
+     @SuppressWarnings("deprecation")\r
+     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+         boolean lastReadOnlyState = readonly;\r
+         boolean lastEnabledState = isEnabled();\r
\r
+         parsable = uidl.getBooleanAttribute("parsable");\r
\r
+         super.updateFromUIDL(uidl, client);\r
\r
+         String popupStyleNames = ApplicationConnection.getStyleName(\r
+                 POPUP_PRIMARY_STYLE_NAME, uidl, false);\r
+         popupStyleNames += " " + VDateField.CLASSNAME + "-"\r
+                 + resolutionToString(currentResolution);\r
+         popup.setStyleName(popupStyleNames);\r
\r
+         calendar.setDateTimeService(getDateTimeService());\r
+         calendar.setShowISOWeekNumbers(isShowISOWeekNumbers());\r
+         if (calendar.getResolution() != currentResolution) {\r
+             calendar.setResolution(currentResolution);\r
+             if (calendar.getDate() != null) {\r
+                 calendar.setDate((Date) getCurrentDate().clone());\r
+                 // force re-render when changing resolution only\r
+                 calendar.renderCalendar();\r
+             }\r
+         }\r
+         calendarToggle.setEnabled(enabled);\r
\r
+         if (currentResolution <= RESOLUTION_MONTH) {\r
+             calendar.setFocusChangeListener(new FocusChangeListener() {\r
+                 public void focusChanged(Date date) {\r
+                     updateValue(date);\r
+                     buildDate();\r
+                     Date date2 = calendar.getDate();\r
+                     date2.setYear(date.getYear());\r
+                     date2.setMonth(date.getMonth());\r
+                 }\r
+             });\r
+         } else {\r
+             calendar.setFocusChangeListener(null);\r
+         }\r
\r
+         if (currentResolution > RESOLUTION_DAY) {\r
+             calendar.setTimeChangeListener(new TimeChangeListener() {\r
+                 public void changed(int hour, int min, int sec, int msec) {\r
+                     Date d = getDate();\r
+                     if (d == null) {\r
+                         // date currently null, use the value from calendarPanel\r
+                         // (~ client time at the init of the widget)\r
+                         d = (Date) calendar.getDate().clone();\r
+                     }\r
+                     d.setHours(hour);\r
+                     d.setMinutes(min);\r
+                     d.setSeconds(sec);\r
+                     DateTimeService.setMilliseconds(d, msec);\r
\r
+                     // Always update time changes to the server\r
+                     updateValue(d);\r
\r
+                     // Update text field\r
+                     buildDate();\r
+                 }\r
+             });\r
+         }\r
\r
+         if (readonly) {\r
+             calendarToggle.addStyleName(CLASSNAME + "-button-readonly");\r
+         } else {\r
+             calendarToggle.removeStyleName(CLASSNAME + "-button-readonly");\r
+         }\r
\r
+         if (lastReadOnlyState != readonly || lastEnabledState != isEnabled()) {\r
+             // Enabled or readonly state changed. Differences in theming might\r
+             // affect the width (for instance if the popup button is hidden) so\r
+             // we have to recalculate the width (IF the width of the field is\r
+             // fixed)\r
+             updateWidth();\r
+         }\r
\r
+         calendarToggle.setEnabled(true);\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see\r
+      * com.google.gwt.user.client.ui.UIObject#setStyleName(java.lang.String)\r
+      */\r
+     @Override\r
+     public void setStyleName(String style) {\r
+         // make sure the style is there before size calculation\r
+         super.setStyleName(style + " " + CLASSNAME + "-popupcalendar");\r
+     }\r
\r
+     /**\r
+      * Opens the calendar panel popup\r
+      */\r
+     public void openCalendarPanel() {\r
\r
+         if (!open && !readonly) {\r
+             open = true;\r
\r
+             if (getCurrentDate() != null) {\r
+                 calendar.setDate((Date) getCurrentDate().clone());\r
+             } else {\r
+                 calendar.setDate(new Date());\r
+             }\r
\r
+             // clear previous values\r
+             popup.setWidth("");\r
+             popup.setHeight("");\r
+             popup.setPopupPositionAndShow(new PositionCallback() {\r
+                 public void setPosition(int offsetWidth, int offsetHeight) {\r
+                     final int w = offsetWidth;\r
+                     final int h = offsetHeight;\r
+                     final int browserWindowWidth = Window.getClientWidth()\r
+                             + Window.getScrollLeft();\r
+                     final int browserWindowHeight = Window.getClientHeight()\r
+                             + Window.getScrollTop();\r
+                     int t = calendarToggle.getAbsoluteTop();\r
+                     int l = calendarToggle.getAbsoluteLeft();\r
\r
+                     // Add a little extra space to the right to avoid\r
 -                    // problems with IE6/IE7 scrollbars and to make it look\r
++                    // problems with IE7 scrollbars and to make it look\r
+                     // nicer.\r
+                     int extraSpace = 30;\r
\r
+                     boolean overflowRight = false;\r
+                     if (l + +w + extraSpace > browserWindowWidth) {\r
+                         overflowRight = true;\r
+                         // Part of the popup is outside the browser window\r
+                         // (to the right)\r
+                         l = browserWindowWidth - w - extraSpace;\r
+                     }\r
\r
+                     if (t + h + calendarToggle.getOffsetHeight() + 30 > browserWindowHeight) {\r
+                         // Part of the popup is outside the browser window\r
+                         // (below)\r
+                         t = browserWindowHeight - h\r
+                                 - calendarToggle.getOffsetHeight() - 30;\r
+                         if (!overflowRight) {\r
+                             // Show to the right of the popup button unless we\r
+                             // are in the lower right corner of the screen\r
+                             l += calendarToggle.getOffsetWidth();\r
+                         }\r
+                     }\r
\r
+                     // fix size\r
+                     popup.setWidth(w + "px");\r
+                     popup.setHeight(h + "px");\r
\r
+                     popup.setPopupPosition(l,\r
+                             t + calendarToggle.getOffsetHeight() + 2);\r
\r
+                     /*\r
+                      * We have to wait a while before focusing since the popup\r
+                      * needs to be opened before we can focus\r
+                      */\r
+                     Timer focusTimer = new Timer() {\r
+                         @Override\r
+                         public void run() {\r
+                             setFocus(true);\r
+                         }\r
+                     };\r
\r
+                     focusTimer.schedule(100);\r
+                 }\r
+             });\r
+         } else {\r
+             VConsole.error("Cannot reopen popup, it is already open!");\r
+         }\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see\r
+      * com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event\r
+      * .dom.client.ClickEvent)\r
+      */\r
+     public void onClick(ClickEvent event) {\r
+         if (event.getSource() == calendarToggle && isEnabled()) {\r
+             openCalendarPanel();\r
+         }\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see\r
+      * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt\r
+      * .event.logical.shared.CloseEvent)\r
+      */\r
+     public void onClose(CloseEvent<PopupPanel> event) {\r
+         if (event.getSource() == popup) {\r
+             buildDate();\r
+             if (!BrowserInfo.get().isTouchDevice()) {\r
+                 /*\r
+                  * Move focus to textbox, unless on touch device (avoids opening\r
+                  * virtual keyboard).\r
+                  */\r
+                 focus();\r
+             }\r
\r
+             // TODO resolve what the "Sigh." is all about and document it here\r
+             // Sigh.\r
+             Timer t = new Timer() {\r
+                 @Override\r
+                 public void run() {\r
+                     open = false;\r
+                 }\r
+             };\r
+             t.schedule(100);\r
+         }\r
+     }\r
\r
+     /**\r
+      * Sets focus to Calendar panel.\r
+      * \r
+      * @param focus\r
+      */\r
+     public void setFocus(boolean focus) {\r
+         calendar.setFocus(focus);\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#getFieldExtraWidth()\r
+      */\r
+     @Override\r
+     protected int getFieldExtraWidth() {\r
+         if (fieldExtraWidth < 0) {\r
+             fieldExtraWidth = super.getFieldExtraWidth();\r
+             fieldExtraWidth += calendarToggle.getOffsetWidth();\r
+         }\r
+         return fieldExtraWidth;\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see com.vaadin.terminal.gwt.client.ui.VTextualDate#buildDate()\r
+      */\r
+     @Override\r
+     protected void buildDate() {\r
+         // Save previous value\r
+         String previousValue = getText();\r
+         super.buildDate();\r
\r
+         // Restore previous value if the input could not be parsed\r
+         if (!parsable) {\r
+             setText(previousValue);\r
+         }\r
+     }\r
\r
+     /**\r
+      * Update the text field contents from the date. See {@link #buildDate()}.\r
+      * \r
+      * @param forceValid\r
+      *            true to force the text field to be updated, false to only\r
+      *            update if the parsable flag is true.\r
+      */\r
+     protected void buildDate(boolean forceValid) {\r
+         if (forceValid) {\r
+             parsable = true;\r
+         }\r
+         buildDate();\r
+     }\r
\r
+     /*\r
+      * (non-Javadoc)\r
+      * \r
+      * @see\r
+      * com.vaadin.terminal.gwt.client.ui.VDateField#onBrowserEvent(com.google\r
+      * .gwt.user.client.Event)\r
+      */\r
+     @Override\r
+     public void onBrowserEvent(com.google.gwt.user.client.Event event) {\r
+         super.onBrowserEvent(event);\r
+         if (DOM.eventGetType(event) == Event.ONKEYDOWN\r
+                 && event.getKeyCode() == getOpenCalenderPanelKey()) {\r
+             openCalendarPanel();\r
+             event.preventDefault();\r
+         }\r
+     }\r
\r
+     /**\r
+      * Get the key code that opens the calendar panel. By default it is the down\r
+      * key but you can override this to be whatever you like\r
+      * \r
+      * @return\r
+      */\r
+     protected int getOpenCalenderPanelKey() {\r
+         return KeyCodes.KEY_DOWN;\r
+     }\r
\r
+     /**\r
+      * Closes the open popup panel\r
+      */\r
+     public void closeCalendarPanel() {\r
+         if (open) {\r
+             popup.hide(true);\r
+         }\r
+     }\r
\r
+     private final String CALENDAR_TOGGLE_ID = "popupButton";\r
\r
+     @Override\r
+     public Element getSubPartElement(String subPart) {\r
+         if (subPart.equals(CALENDAR_TOGGLE_ID)) {\r
+             return calendarToggle.getElement();\r
+         }\r
\r
+         return super.getSubPartElement(subPart);\r
+     }\r
\r
+     @Override\r
+     public String getSubPartName(Element subElement) {\r
+         if (calendarToggle.getElement().isOrHasChild(subElement)) {\r
+             return CALENDAR_TOGGLE_ID;\r
+         }\r
\r
+         return super.getSubPartName(subElement);\r
+     }\r
\r
+ }\r
index 41b7efcf02d78031b4714711bb244dd1b144ad2a,553934bf9809bdaf8214431d9baf746b64876ffd..de68ae96a4f54d09663f12f3c9d48b062987be64
@@@ -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) {
index 6b55fa08024fa989d341e41f69781800e1951aab,9dfab44b93863e86cc160db61961e5bdc9a4517a..3632e90956f5034d1454867428a11a21f893f7dc
- /* 
- @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;
-     }
- }
+ /* \r
+ @VaadinApache2LicenseForJavaFiles@\r
+  */\r
+ // \r
+ package com.vaadin.terminal.gwt.client.ui;\r
\r
+ import com.google.gwt.core.client.Scheduler;\r
+ import com.google.gwt.core.client.Scheduler.ScheduledCommand;\r
+ import com.google.gwt.event.dom.client.KeyCodes;\r
+ import com.google.gwt.user.client.Command;\r
+ import com.google.gwt.user.client.DOM;\r
+ import com.google.gwt.user.client.Element;\r
+ import com.google.gwt.user.client.Event;\r
+ import com.google.gwt.user.client.Window;\r
+ import com.google.gwt.user.client.ui.HTML;\r
++import com.google.gwt.user.client.ui.Widget;\r
+ import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+ import com.vaadin.terminal.gwt.client.BrowserInfo;\r
+ import com.vaadin.terminal.gwt.client.ContainerResizedListener;\r
 -import com.vaadin.terminal.gwt.client.Paintable;\r
++import com.vaadin.terminal.gwt.client.VPaintableWidget;\r
+ import com.vaadin.terminal.gwt.client.UIDL;\r
+ import com.vaadin.terminal.gwt.client.Util;\r
+ import com.vaadin.terminal.gwt.client.VConsole;\r
\r
 -public class VSlider extends SimpleFocusablePanel implements Paintable, Field,\r
 -        ContainerResizedListener {\r
++public class VSlider extends SimpleFocusablePanel implements VPaintableWidget,\r
++        Field, ContainerResizedListener {\r
\r
+     public static final String CLASSNAME = "v-slider";\r
\r
+     /**\r
+      * Minimum size (width or height, depending on orientation) of the slider\r
+      * base.\r
+      */\r
+     private static final int MIN_SIZE = 50;\r
\r
+     ApplicationConnection client;\r
\r
+     String id;\r
\r
+     private boolean immediate;\r
+     private boolean disabled;\r
+     private boolean readonly;\r
 -    private boolean scrollbarStyle;\r
\r
+     private int acceleration = 1;\r
 -    private int handleSize;\r
+     private double min;\r
+     private double max;\r
+     private int resolution;\r
+     private Double value;\r
+     private boolean vertical;\r
 -    private boolean arrows;\r
\r
+     private final HTML feedback = new HTML("", false);\r
+     private final VOverlay feedbackPopup = new VOverlay(true, false, true) {\r
+         @Override\r
+         public void show() {\r
+             super.show();\r
+             updateFeedbackPosition();\r
+         }\r
+     };\r
\r
+     /* DOM element for slider's base */\r
+     private final Element base;\r
+     private final int BASE_BORDER_WIDTH = 1;\r
\r
+     /* DOM element for slider's handle */\r
+     private final Element handle;\r
\r
+     /* DOM element for decrement arrow */\r
+     private final Element smaller;\r
\r
+     /* DOM element for increment arrow */\r
+     private final Element bigger;\r
\r
+     /* Temporary dragging/animation variables */\r
+     private boolean dragging = false;\r
\r
+     private VLazyExecutor delayedValueUpdater = new VLazyExecutor(100,\r
+             new ScheduledCommand() {\r
\r
+                 public void execute() {\r
+                     updateValueToServer();\r
+                     acceleration = 1;\r
+                 }\r
+             });\r
\r
+     public VSlider() {\r
+         super();\r
\r
+         base = DOM.createDiv();\r
+         handle = DOM.createDiv();\r
+         smaller = DOM.createDiv();\r
+         bigger = DOM.createDiv();\r
\r
+         setStyleName(CLASSNAME);\r
+         DOM.setElementProperty(base, "className", CLASSNAME + "-base");\r
+         DOM.setElementProperty(handle, "className", CLASSNAME + "-handle");\r
+         DOM.setElementProperty(smaller, "className", CLASSNAME + "-smaller");\r
+         DOM.setElementProperty(bigger, "className", CLASSNAME + "-bigger");\r
\r
+         DOM.appendChild(getElement(), bigger);\r
+         DOM.appendChild(getElement(), smaller);\r
+         DOM.appendChild(getElement(), base);\r
+         DOM.appendChild(base, handle);\r
\r
+         // Hide initially\r
+         DOM.setStyleAttribute(smaller, "display", "none");\r
+         DOM.setStyleAttribute(bigger, "display", "none");\r
+         DOM.setStyleAttribute(handle, "visibility", "hidden");\r
\r
+         sinkEvents(Event.MOUSEEVENTS | Event.ONMOUSEWHEEL | Event.KEYEVENTS\r
+                 | Event.FOCUSEVENTS | Event.TOUCHEVENTS);\r
\r
+         feedbackPopup.addStyleName(CLASSNAME + "-feedback");\r
+         feedbackPopup.setWidget(feedback);\r
+     }\r
\r
+     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
\r
+         this.client = client;\r
+         id = uidl.getId();\r
\r
+         // Ensure correct implementation\r
+         if (client.updateComponent(this, uidl, true)) {\r
+             return;\r
+         }\r
\r
+         immediate = uidl.getBooleanAttribute("immediate");\r
+         disabled = uidl.getBooleanAttribute("disabled");\r
+         readonly = uidl.getBooleanAttribute("readonly");\r
\r
+         vertical = uidl.hasAttribute("vertical");\r
 -        arrows = uidl.hasAttribute("arrows");\r
\r
+         String style = "";\r
+         if (uidl.hasAttribute("style")) {\r
+             style = uidl.getStringAttribute("style");\r
+         }\r
\r
 -        scrollbarStyle = style.indexOf("scrollbar") > -1;\r
 -\r
 -        if (arrows) {\r
 -            DOM.setStyleAttribute(smaller, "display", "block");\r
 -            DOM.setStyleAttribute(bigger, "display", "block");\r
 -        }\r
 -\r
+         if (vertical) {\r
+             addStyleName(CLASSNAME + "-vertical");\r
+         } else {\r
+             removeStyleName(CLASSNAME + "-vertical");\r
+         }\r
\r
+         min = uidl.getDoubleAttribute("min");\r
+         max = uidl.getDoubleAttribute("max");\r
+         resolution = uidl.getIntAttribute("resolution");\r
+         value = new Double(uidl.getDoubleVariable("value"));\r
\r
+         setFeedbackValue(value);\r
\r
 -        handleSize = uidl.getIntAttribute("hsize");\r
 -\r
+         buildBase();\r
\r
+         if (!vertical) {\r
+             // Draw handle with a delay to allow base to gain maximum width\r
+             Scheduler.get().scheduleDeferred(new Command() {\r
+                 public void execute() {\r
+                     buildHandle();\r
+                     setValue(value, false);\r
+                 }\r
+             });\r
+         } else {\r
+             buildHandle();\r
+             setValue(value, false);\r
+         }\r
+     }\r
\r
+     private void setFeedbackValue(double value) {\r
+         String currentValue = "" + value;\r
+         if (resolution == 0) {\r
+             currentValue = "" + new Double(value).intValue();\r
+         }\r
+         feedback.setText(currentValue);\r
+     }\r
\r
+     private void updateFeedbackPosition() {\r
+         if (vertical) {\r
+             feedbackPopup.setPopupPosition(\r
+                     DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth(),\r
+                     DOM.getAbsoluteTop(handle) + handle.getOffsetHeight() / 2\r
+                             - feedbackPopup.getOffsetHeight() / 2);\r
+         } else {\r
+             feedbackPopup.setPopupPosition(\r
+                     DOM.getAbsoluteLeft(handle) + handle.getOffsetWidth() / 2\r
+                             - feedbackPopup.getOffsetWidth() / 2,\r
+                     DOM.getAbsoluteTop(handle)\r
+                             - feedbackPopup.getOffsetHeight());\r
+         }\r
+     }\r
\r
+     private void buildBase() {\r
+         final String styleAttribute = vertical ? "height" : "width";\r
+         final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
\r
+         final Element p = DOM.getParent(getElement());\r
+         if (DOM.getElementPropertyInt(p, domProperty) > 50) {\r
+             if (vertical) {\r
+                 setHeight();\r
+             } else {\r
+                 DOM.setStyleAttribute(base, styleAttribute, "");\r
+             }\r
+         } else {\r
+             // Set minimum size and adjust after all components have\r
+             // (supposedly) been drawn completely.\r
+             DOM.setStyleAttribute(base, styleAttribute, MIN_SIZE + "px");\r
+             Scheduler.get().scheduleDeferred(new Command() {\r
+                 public void execute() {\r
+                     final Element p = DOM.getParent(getElement());\r
+                     if (DOM.getElementPropertyInt(p, domProperty) > (MIN_SIZE + 5)) {\r
+                         if (vertical) {\r
+                             setHeight();\r
+                         } else {\r
+                             DOM.setStyleAttribute(base, styleAttribute, "");\r
+                         }\r
+                         // Ensure correct position\r
+                         setValue(value, false);\r
+                     }\r
+                 }\r
+             });\r
+         }\r
\r
+         // TODO attach listeners for focusing and arrow keys\r
+     }\r
\r
+     private void buildHandle() {\r
 -        final String styleAttribute = vertical ? "height" : "width";\r
+         final String handleAttribute = vertical ? "marginTop" : "marginLeft";\r
 -        final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
\r
+         DOM.setStyleAttribute(handle, handleAttribute, "0");\r
\r
 -        if (scrollbarStyle) {\r
 -            // Only stretch the handle if scrollbar style is set.\r
 -            int s = (int) (Double.parseDouble(DOM.getElementProperty(base,\r
 -                    domProperty)) / 100 * handleSize);\r
 -            if (handleSize == -1) {\r
 -                final int baseS = Integer.parseInt(DOM.getElementProperty(base,\r
 -                        domProperty));\r
 -                final double range = (max - min) * (resolution + 1) * 3;\r
 -                s = (int) (baseS - range);\r
 -            }\r
 -            if (s < 3) {\r
 -                s = 3;\r
 -            }\r
 -            DOM.setStyleAttribute(handle, styleAttribute, s + "px");\r
 -        } else {\r
 -            DOM.setStyleAttribute(handle, styleAttribute, "");\r
 -        }\r
 -\r
+         // Restore visibility\r
+         DOM.setStyleAttribute(handle, "visibility", "visible");\r
\r
+     }\r
\r
+     private void setValue(Double value, boolean updateToServer) {\r
+         if (value == null) {\r
+             return;\r
+         }\r
\r
+         if (value < min) {\r
+             value = min;\r
+         } else if (value > max) {\r
+             value = max;\r
+         }\r
\r
+         // Update handle position\r
+         final String styleAttribute = vertical ? "marginTop" : "marginLeft";\r
+         final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
+         final int handleSize = Integer.parseInt(DOM.getElementProperty(handle,\r
+                 domProperty));\r
+         final int baseSize = Integer.parseInt(DOM.getElementProperty(base,\r
+                 domProperty)) - (2 * BASE_BORDER_WIDTH);\r
\r
+         final int range = baseSize - handleSize;\r
+         double v = value.doubleValue();\r
\r
+         // Round value to resolution\r
+         if (resolution > 0) {\r
+             v = Math.round(v * Math.pow(10, resolution));\r
+             v = v / Math.pow(10, resolution);\r
+         } else {\r
+             v = Math.round(v);\r
+         }\r
+         final double valueRange = max - min;\r
+         double p = 0;\r
+         if (valueRange > 0) {\r
+             p = range * ((v - min) / valueRange);\r
+         }\r
+         if (p < 0) {\r
+             p = 0;\r
+         }\r
+         if (vertical) {\r
 -            // IE6 rounding behaves a little unstable, reduce one pixel so the\r
 -            // containing element (base) won't expand without limits\r
 -            p = range - p - (BrowserInfo.get().isIE6() ? 1 : 0);\r
++            p = range - p;\r
+         }\r
+         final double pos = p;\r
\r
+         DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px");\r
\r
+         // Update value\r
+         this.value = new Double(v);\r
+         setFeedbackValue(v);\r
\r
+         if (updateToServer) {\r
+             updateValueToServer();\r
+         }\r
+     }\r
\r
+     @Override\r
+     public void onBrowserEvent(Event event) {\r
+         if (disabled || readonly) {\r
+             return;\r
+         }\r
+         final Element targ = DOM.eventGetTarget(event);\r
\r
+         if (DOM.eventGetType(event) == Event.ONMOUSEWHEEL) {\r
+             processMouseWheelEvent(event);\r
+         } else if (dragging || targ == handle) {\r
+             processHandleEvent(event);\r
+         } else if (targ == smaller) {\r
+             decreaseValue(true);\r
+         } else if (targ == bigger) {\r
+             increaseValue(true);\r
+         } else if (DOM.eventGetType(event) == Event.MOUSEEVENTS) {\r
+             processBaseEvent(event);\r
+         } else if ((BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYPRESS)\r
+                 || (!BrowserInfo.get().isGecko() && DOM.eventGetType(event) == Event.ONKEYDOWN)) {\r
\r
+             if (handleNavigation(event.getKeyCode(), event.getCtrlKey(),\r
+                     event.getShiftKey())) {\r
\r
+                 feedbackPopup.show();\r
\r
+                 delayedValueUpdater.trigger();\r
\r
+                 DOM.eventPreventDefault(event);\r
+                 DOM.eventCancelBubble(event, true);\r
+             }\r
+         } else if (targ.equals(getElement())\r
+                 && DOM.eventGetType(event) == Event.ONFOCUS) {\r
+             feedbackPopup.show();\r
+         } else if (targ.equals(getElement())\r
+                 && DOM.eventGetType(event) == Event.ONBLUR) {\r
+             feedbackPopup.hide();\r
+         } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {\r
+             feedbackPopup.show();\r
+         }\r
 -        if(Util.isTouchEvent(event)) {\r
++        if (Util.isTouchEvent(event)) {\r
+             event.preventDefault(); // avoid simulated events\r
+             event.stopPropagation();\r
+         }\r
+     }\r
\r
+     private void processMouseWheelEvent(final Event event) {\r
+         final int dir = DOM.eventGetMouseWheelVelocityY(event);\r
\r
+         if (dir < 0) {\r
+             increaseValue(false);\r
+         } else {\r
+             decreaseValue(false);\r
+         }\r
\r
+         delayedValueUpdater.trigger();\r
\r
+         DOM.eventPreventDefault(event);\r
+         DOM.eventCancelBubble(event, true);\r
+     }\r
\r
+     private void processHandleEvent(Event event) {\r
+         switch (DOM.eventGetType(event)) {\r
+         case Event.ONMOUSEDOWN:\r
+         case Event.ONTOUCHSTART:\r
+             if (!disabled && !readonly) {\r
+                 focus();\r
+                 feedbackPopup.show();\r
+                 dragging = true;\r
+                 DOM.setElementProperty(handle, "className", CLASSNAME\r
+                         + "-handle " + CLASSNAME + "-handle-active");\r
+                 DOM.setCapture(getElement());\r
+                 DOM.eventPreventDefault(event); // prevent selecting text\r
+                 DOM.eventCancelBubble(event, true);\r
+                 event.stopPropagation();\r
+                 VConsole.log("Slider move start");\r
+             }\r
+             break;\r
+         case Event.ONMOUSEMOVE:\r
+         case Event.ONTOUCHMOVE:\r
+             if (dragging) {\r
+                 VConsole.log("Slider move");\r
+                 setValueByEvent(event, false);\r
+                 updateFeedbackPosition();\r
+                 event.stopPropagation();\r
+             }\r
+             break;\r
+         case Event.ONTOUCHEND:\r
+             feedbackPopup.hide();\r
+         case Event.ONMOUSEUP:\r
+             // feedbackPopup.hide();\r
+             VConsole.log("Slider move end");\r
+             dragging = false;\r
+             DOM.setElementProperty(handle, "className", CLASSNAME + "-handle");\r
+             DOM.releaseCapture(getElement());\r
+             setValueByEvent(event, true);\r
+             event.stopPropagation();\r
+             break;\r
+         default:\r
+             break;\r
+         }\r
+     }\r
\r
+     private void processBaseEvent(Event event) {\r
+         if (DOM.eventGetType(event) == Event.ONMOUSEDOWN) {\r
+             if (!disabled && !readonly && !dragging) {\r
+                 setValueByEvent(event, true);\r
+                 DOM.eventCancelBubble(event, true);\r
+             }\r
+         }\r
+     }\r
\r
+     private void decreaseValue(boolean updateToServer) {\r
+         setValue(new Double(value.doubleValue() - Math.pow(10, -resolution)),\r
+                 updateToServer);\r
+     }\r
\r
+     private void increaseValue(boolean updateToServer) {\r
+         setValue(new Double(value.doubleValue() + Math.pow(10, -resolution)),\r
+                 updateToServer);\r
+     }\r
\r
+     private void setValueByEvent(Event event, boolean updateToServer) {\r
+         double v = min; // Fallback to min\r
\r
+         final int coord = getEventPosition(event);\r
\r
+         final int handleSize, baseSize, baseOffset;\r
+         if (vertical) {\r
+             handleSize = handle.getOffsetHeight();\r
+             baseSize = base.getOffsetHeight();\r
+             baseOffset = base.getAbsoluteTop() - Window.getScrollTop()\r
+                     - handleSize / 2;\r
+         } else {\r
+             handleSize = handle.getOffsetWidth();\r
+             baseSize = base.getOffsetWidth();\r
+             baseOffset = base.getAbsoluteLeft() - Window.getScrollLeft()\r
+                     + handleSize / 2;\r
+         }\r
\r
+         if (vertical) {\r
+             v = ((baseSize - (coord - baseOffset)) / (double) (baseSize - handleSize))\r
+                     * (max - min) + min;\r
+         } else {\r
+             v = ((coord - baseOffset) / (double) (baseSize - handleSize))\r
+                     * (max - min) + min;\r
+         }\r
\r
+         if (v < min) {\r
+             v = min;\r
+         } else if (v > max) {\r
+             v = max;\r
+         }\r
\r
+         setValue(v, updateToServer);\r
+     }\r
\r
+     /**\r
+      * TODO consider extracting touches support to an impl class specific for\r
+      * webkit (only browser that really supports touches).\r
+      * \r
+      * @param event\r
+      * @return\r
+      */\r
+     protected int getEventPosition(Event event) {\r
+         if (vertical) {\r
+             return Util.getTouchOrMouseClientY(event);\r
+         } else {\r
+             return Util.getTouchOrMouseClientX(event);\r
+         }\r
+     }\r
\r
+     public void iLayout() {\r
+         if (vertical) {\r
+             setHeight();\r
+         }\r
+         // Update handle position\r
+         setValue(value, false);\r
+     }\r
\r
+     private void setHeight() {\r
+         // Calculate decoration size\r
+         DOM.setStyleAttribute(base, "height", "0");\r
+         DOM.setStyleAttribute(base, "overflow", "hidden");\r
+         int h = DOM.getElementPropertyInt(getElement(), "offsetHeight");\r
+         if (h < MIN_SIZE) {\r
+             h = MIN_SIZE;\r
+         }\r
+         DOM.setStyleAttribute(base, "height", h + "px");\r
+         DOM.setStyleAttribute(base, "overflow", "");\r
+     }\r
\r
+     private void updateValueToServer() {\r
+         client.updateVariable(id, "value", value.doubleValue(), immediate);\r
+     }\r
\r
+     /**\r
+      * Handles the keyboard events handled by the Slider\r
+      * \r
+      * @param event\r
+      *            The keyboard event received\r
+      * @return true iff the navigation event was handled\r
+      */\r
+     public boolean handleNavigation(int keycode, boolean ctrl, boolean shift) {\r
\r
+         // No support for ctrl moving\r
+         if (ctrl) {\r
+             return false;\r
+         }\r
\r
+         if ((keycode == getNavigationUpKey() && vertical)\r
+                 || (keycode == getNavigationRightKey() && !vertical)) {\r
+             if (shift) {\r
+                 for (int a = 0; a < acceleration; a++) {\r
+                     increaseValue(false);\r
+                 }\r
+                 acceleration++;\r
+             } else {\r
+                 increaseValue(false);\r
+             }\r
+             return true;\r
+         } else if (keycode == getNavigationDownKey() && vertical\r
+                 || (keycode == getNavigationLeftKey() && !vertical)) {\r
+             if (shift) {\r
+                 for (int a = 0; a < acceleration; a++) {\r
+                     decreaseValue(false);\r
+                 }\r
+                 acceleration++;\r
+             } else {\r
+                 decreaseValue(false);\r
+             }\r
+             return true;\r
+         }\r
\r
+         return false;\r
+     }\r
\r
+     /**\r
+      * Get the key that increases the vertical slider. By default it is the up\r
+      * arrow key but by overriding this you can change the key to whatever you\r
+      * want.\r
+      * \r
+      * @return The keycode of the key\r
+      */\r
+     protected int getNavigationUpKey() {\r
+         return KeyCodes.KEY_UP;\r
+     }\r
\r
+     /**\r
+      * Get the key that decreases the vertical slider. By default it is the down\r
+      * arrow key but by overriding this you can change the key to whatever you\r
+      * want.\r
+      * \r
+      * @return The keycode of the key\r
+      */\r
+     protected int getNavigationDownKey() {\r
+         return KeyCodes.KEY_DOWN;\r
+     }\r
\r
+     /**\r
+      * Get the key that decreases the horizontal slider. By default it is the\r
+      * left arrow key but by overriding this you can change the key to whatever\r
+      * you want.\r
+      * \r
+      * @return The keycode of the key\r
+      */\r
+     protected int getNavigationLeftKey() {\r
+         return KeyCodes.KEY_LEFT;\r
+     }\r
\r
+     /**\r
+      * Get the key that increases the horizontal slider. By default it is the\r
+      * right arrow key but by overriding this you can change the key to whatever\r
+      * you want.\r
+      * \r
+      * @return The keycode of the key\r
+      */\r
+     protected int getNavigationRightKey() {\r
+         return KeyCodes.KEY_RIGHT;\r
+     }\r
++\r
++    public Widget getWidgetForPaintable() {\r
++        return this;\r
++    }\r
+ }\r
index ed4953d463bb29449cd8c5e11c9e087dc8633b3b,56cdf05ddb0b0c6dd1e676602ab9d1c007d134b5..a522c7973643aa1c4eb7fbbab7c2e5f1c28d67d8
@@@ -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";
  
      @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);
                  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;
              }
          }
      }
 -      return width == null || "".equals(width);
 +
+     protected boolean isUndefinedWidth() {
++        return width == null || "".equals(width);
+     }
      /**
       * Returns pixels in x-axis reserved for other than textfield content.
       * 
index c1ef2bbac404017da72c9e181fa6e0b474b88e55,7b9ece24c9091f08918eece85d81ea242d3446ed..95ab0dc7735eab7cb9d19fa881bc81caf3d19a82
@@@ -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) {
Simple merge
index ec620ddcd5723b00cea9b905426844cf04c9a131,199a6805f6ac916d5c64e1ec612d266de5a738f1..6a946560cfdc4837c1892094dd08522c75e64199
@@@ -5132,60 -5152,13 +5135,69 @@@ public class Table extends AbstractSele
          return rowGenerator;
      }
  
 +    /**
 +     * Sets a converter for a property id.
 +     * <p>
 +     * The converter is used to format the the data for the given property id
 +     * before displaying it in the table.
 +     * </p>
 +     * 
 +     * @param propertyId
 +     *            The propertyId to format using the converter
 +     * @param converter
 +     *            The converter to use for the property id
 +     */
 +    public void setConverter(Object propertyId, Converter<String, ?> converter) {
 +        if (!getContainerPropertyIds().contains(propertyId)) {
 +            throw new IllegalArgumentException("PropertyId " + propertyId
 +                    + " must be in the container");
 +        }
 +        // FIXME: This check should be here but primitive types like Boolean
 +        // formatter for boolean property must be handled
 +
 +        // if (!converter.getSourceType().isAssignableFrom(getType(propertyId)))
 +        // {
 +        // throw new IllegalArgumentException("Property type ("
 +        // + getType(propertyId)
 +        // + ") must match converter source type ("
 +        // + converter.getSourceType() + ")");
 +        // }
 +        propertyValueConverters.put(propertyId,
 +                (Converter<String, Object>) converter);
 +        refreshRowCache();
 +    }
 +
 +    /**
 +     * Checks if there is a converter set explicitly for the given property id.
 +     * 
 +     * @param propertyId
 +     *            The propertyId to check
 +     * @return true if a converter has been set for the property id, false
 +     *         otherwise
 +     */
 +    protected boolean hasConverter(Object propertyId) {
 +        return propertyValueConverters.containsKey(propertyId);
 +    }
 +
 +    /**
 +     * Returns the converter used to format the given propertyId.
 +     * 
 +     * @param propertyId
 +     *            The propertyId to check
 +     * @return The converter used to format the propertyId or null if no
 +     *         converter has been set
 +     */
 +    public Converter<String, Object> getConverter(Object propertyId) {
 +        return propertyValueConverters.get(propertyId);
 +    }
 +
+     @Override
+     public void setVisible(boolean visible) {
+         if (!isVisible() && visible) {
+             // 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);
+     }
  }
index 60e4882044facc558f91c7621670324bbee73170,fa8defd14e364036adc930675bcff5ca45914106..1b37347dddb748430b858de04c3438e3b8a506f4
@@@ -1,16 -1,12 +1,16 @@@
  <?xml version="1.0"?>\r
  \r
 -<project name="Vaadin Integration Tests" basedir="." default="integration-test-all">\r
 +<project xmlns:antcontrib="antlib:net.sf.antcontrib"\r
 +      name="Vaadin Integration Tests" basedir="." default="integration-test-all">\r
 +\r
 +    <!-- Import common targets  -->\r
 +    <import file="../build/common.xml" />\r
  \r
        <!-- Target deploying demo.war -->\r
-       <fail unless="test.integration.server" message="test.integration.server must be set for integration tests to run"/>\r
-       \r
-       <fail unless="test.integration.user" message="test.integration.user must be set for integration tests to run"/>\r
-       <fail unless="test.integration.antfile" message="test.integration.antfile must be set for integration tests to run"/>\r
+       <fail unless="test.integration.server" message="test.integration.server must be set for integration tests to run" />\r
\r
+       <fail unless="test.integration.user" message="test.integration.user must be set for integration tests to run" />\r
+       <fail unless="test.integration.antfile" message="test.integration.antfile must be set for integration tests to run" />\r
  \r
        <!-- Test with these browsers -->\r
        <property name="test_browsers" value="winxp-firefox9" />\r
                        <param name="target-server" value="tomcat7" />\r
                </antcall>\r
        </target>\r
-       \r
 -\r
 -      <target name="integration-test-tomcat4">\r
 -              <antcall target="run-generic-integration-test">\r
 -                      <param name="startDelay" value="10" />\r
 -                      <param name="target-server" value="tomcat4" />\r
 -              </antcall>\r
 -      </target>\r
 -\r
        <target name="integration-test-tomcat5">\r
                <antcall target="run-generic-integration-test">\r
-                       <param name="startDelay" value="300" />\r
+                       <param name="startDelay" value="10" />\r
                        <param name="target-server" value="tomcat5" />\r
                </antcall>\r
-       </target>       \r
-       \r
+       </target>\r
\r
        <target name="integration-test-tomcat6">\r
                <antcall target="run-generic-integration-test">\r
-                       <param name="startDelay" value="300" />\r
+                       <param name="startDelay" value="10" />\r
                        <param name="target-server" value="tomcat6" />\r
                </antcall>\r
-       </target>       \r
-       \r
+       </target>\r
\r
        <target name="integration-test-jetty5">\r
                <antcall target="run-generic-integration-test">\r
-                       <param name="startDelay" value="300" />\r
                        <param name="target-server" value="jetty5" />\r
                </antcall>\r
        </target>\r
                        <param name="target-server" value="jetty7" />\r
                </antcall>\r
        </target>\r
-       \r
\r
+       <target name="integration-test-jetty8">\r
+               <antcall target="run-generic-integration-test">\r
+                       <param name="target-server" value="jetty8" />\r
+               </antcall>\r
+       </target>\r
\r
 -      <target name="integration-test-jboss3">\r
 -              <antcall target="run-generic-integration-test">\r
 -                      <param name="startDelay" value="10" />\r
 -                      <param name="target-server" value="jboss3" />\r
 -              </antcall>\r
 -      </target>\r
 -\r
        <target name="integration-test-jboss4">\r
                <antcall target="run-generic-integration-test">\r
-                       <param name="startDelay" value="300" />\r
+                       <param name="startDelay" value="10" />\r
                        <param name="target-server" value="jboss4" />\r
                </antcall>\r
        </target>\r
                        <param name="target-server" value="weblogicportal" />\r
                </antcall>\r
        </target>\r
-       \r
\r
        <target name="integration-test-GAE">\r
-               <antcall target="integration-test-deploy-to-GAE"/>\r
+               <antcall target="integration-test-deploy-to-GAE" />\r
                <antcall target="integration-test-test-GAE" />\r
        </target>\r
-                       \r
\r
        <!-- Upload demo, clean error screenshots and test deployment on all servers -->\r
 -      <target name="integration-test-all">\r
 -\r
 +      <target name="integration-test-all" depends="common.init-deps">\r
-               \r
                <parallel>\r
 -                      <trycatch property="tried">\r
 +                      <antcontrib:trycatch property="tried">\r
                                <try>\r
                                        <!-- Still running GAE test from the old server which requires its own lock -->\r
                                        <echo message="Getting lock" />\r
                                <catch>\r
                                        <echo message="Uploading of demo.war failed. ${tried}" />\r
                                </catch>\r
 -                      </trycatch>\r
 -\r
 +                      </antcontrib:trycatch>\r
-                                                       \r
                        <antcall target="integration-test-liferay6" />\r
                        <antcall target="integration-test-liferay6ee" />\r
                        <antcall target="integration-test-exo3" />\r
                        <antcall target="integration-test-jetty5" />\r
                        <antcall target="integration-test-jetty6" />\r
                        <antcall target="integration-test-jetty7" />\r
 -                      <antcall target="integration-test-tomcat4" />\r
+                       <antcall target="integration-test-jetty8" />\r
                        <antcall target="integration-test-tomcat5" />\r
                        <antcall target="integration-test-tomcat6" />\r
                        <antcall target="integration-test-tomcat7" />\r
        <target name="do-run-generic-test">\r
                <property name="target-host" value="${target-server}.devnet.vaadin.com" />\r
                <property name="target-port" value="8080" />\r
-               \r
 -\r
 -              <if>\r
 +              <antcontrib:if>\r
                        <isset property="startDelay" />\r
                        <then>\r
 -                              <math result="sleepTime" datatype="int">\r
 +                              <antcontrib:math result="sleepTime" datatype="int">\r
                                        <op op="rint">\r
                                                <op op="*">\r
-                                                       <num value="${startDelay}"/>\r
-                                                       <op op="random"/>\r
+                                                       <num value="${startDelay}" />\r
+                                                       <op op="random" />\r
                                                </op>\r
                                        </op>\r
 -                              </math>\r
 -                              <echo>Delaying startup of ${target-server} with ${sleepTime} seconds</echo>\r
 +                              </antcontrib:math>\r
 +                              <echo>Delaying startup of ${target-server} with ${sleepTime} seconds</echo>             \r
                                <sleep seconds="${sleepTime}" />\r
                        </then>\r
 -              </if>\r
 -\r
 -              <scp todir="${user}@${target-host}:." keyfile="${sshkey.file}" trust="yes" passphrase="${passphrase}">\r
 +              </antcontrib:if>\r
 +              \r
 +              <scp todir="${user}@${target-host}:." keyfile="${sshkey.file}" trust="yes" passphrase="${passphrase}" >\r
                        <fileset dir="integration_base_files">\r
                                <include name="*" />\r
                        </fileset>\r
                </scp>\r
-               \r
\r
                <!-- trycatch probably not needed any more as it just fails with the original message and doesn't do anything in the finally block -->\r
 -              <trycatch property="error_message">\r
 +              <antcontrib:trycatch property="error_message">\r
                        <try>\r
                                <!-- timeout in one hour (remote end should timeout in 55 minutes) -->\r
                                <sshexec host="${target-host}" outputproperty="lock-output" timeout="3600000" username="${user}" keyfile="${sshkey.file}" trust="yes" command="chmod +x *.sh; ant -f deploy.xml get-lock" />\r
                                        <param name="server-name" value="${target-server}" />\r
                                        <param name="deployment.url" value="http://${target-host}:${target-port}" />\r
                                </antcall>\r
-                               \r
\r
                                <!-- Run theme tests in all browsers if there's a property with the test files -->\r
 -                              <if>\r
 +                              <antcontrib:if>\r
                                        <isset property="testfiles-theme" />\r
 -                                      <then>\r
 +                                      <antcontrib:then>\r
                                                <antcall target="integration-test-theme">\r
                                                        <param name="server-name" value="${target-server}" />\r
                                                        <param name="deployment.url" value="http://${target-host}:${target-port}" />\r
                                                </antcall>\r
 -                                      </then>\r
 -                              </if>\r
 -\r
 +                                      </antcontrib:then>\r
 +                              </antcontrib:if>\r
 +                              \r
                                <!-- timeout in five minutes -->\r
-                               <sshexec host="${target-host}" outputproperty="stop-output" timeout="300000" username="${user}" keyfile="${sshkey.file}" trust="yes" command="ant -f deploy.xml shutdown-and-cleanup" failonerror="false" />\r
+                               <sshexec host="${target-host}" outputproperty="stop-output" timeout="600000" username="${user}" keyfile="${sshkey.file}" trust="yes" command="ant -f deploy.xml shutdown-and-cleanup" failonerror="false" />\r
                                <antcall target="echo-prefix">\r
                                        <param name="prefix" value="${target-server}: " />\r
                                        <param name="message" value="${stop-output}" />\r
                        <catch>\r
                                <fail message="${error_message}" />\r
                        </catch>\r
 -              </trycatch>\r
 +              </antcontrib:trycatch>\r
        </target>\r
-       \r
\r
        <target name="echo-prefix">\r
 -              <propertyregex property="message-prefixed" input="${prefix}${message}" regexp="\n" replace="\0${prefix}" global="true" defaultValue="${prefix}${message}" />\r
 +              <antcontrib:propertyregex property="message-prefixed" input="${prefix}${message}" regexp="\n" replace="\0${prefix}" global="true" defaultValue="${prefix}${message}" />\r
                <echo message="${message-prefixed}" />\r
        </target>\r
-       \r
\r
        <target name="run-generic-integration-test">\r
                <concat>##teamcity[testStarted name='${target-server}' flowId='${target-server}']</concat>\r
 -              <trycatch property="tried">\r
 +              <antcontrib:trycatch property="tried">\r
                        <try>\r
                                <antcall target="do-run-generic-test" />\r
                        </try>\r
                        <catch>\r
 -                              <antcallback target="teamcity-escape" return="tried-escaped">\r
 +                              <antcontrib:antcallback target="teamcity-escape" return="tried-escaped">\r
                                        <param name="returnTo" value="tried-escaped" />\r
                                        <param name="message" value="${tried}" />\r
 -                              </antcallback>\r
 +                              </antcontrib:antcallback>\r
                                <concat>##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}']</concat>\r
                        </catch>\r
 -              </trycatch>\r
 +              </antcontrib:trycatch>\r
                <concat>##teamcity[testFinished name='${target-server}' flowId='${target-server}']"</concat>\r
-       </target>       \r
+       </target>\r
  \r
        <target name="teamcity-escape">\r
                <property name="returnTo" value="return" />\r
-               \r
\r
                <!-- Should also perform other escaping (\u0085, \u2028 and \u2029) - see http://confluence.jetbrains.net/display/TCD65/Build+Script+Interaction+with+TeamCity -->\r
                <!-- Immutable properties -> needs to create a new one every time -->\r
 -              <propertyregex property="details-escaped1" input="${message}" regexp="['|\[\]]" replace="|\0" global="true" defaultValue="${message}" />\r
 -              <propertyregex property="details-escaped2" input="${details-escaped1}" regexp="\n" replace="|n" global="true" defaultValue="${details-escaped1}" />\r
 -              <propertyregex property="details-escaped3" input="${details-escaped2}" regexp="\r" replace="|r" global="true" defaultValue="${details-escaped2}" />\r
 +              <antcontrib:propertyregex property="details-escaped1" input="${message}" regexp="['|\[\]]" replace="|\0" global="true" defaultValue="${message}" />\r
 +              <antcontrib:propertyregex property="details-escaped2" input="${details-escaped1}" regexp="\n" replace="|n" global="true" defaultValue="${details-escaped1}" />\r
 +              <antcontrib:propertyregex property="details-escaped3" input="${details-escaped2}" regexp="\r" replace="|r" global="true" defaultValue="${details-escaped2}" />\r
-               \r
\r
                <property name="${returnTo}" value="${details-escaped3}" />\r
        </target>\r
-       \r
\r
        <target name="run-integration-test">\r
                <concat>##teamcity[testStarted name='${target-server}' flowId='${target-server}']</concat>\r
 -              <trycatch property="tried">\r
 +              <antcontrib:trycatch property="tried">\r
                        <try>\r
                                <antcall target="integration-test-${target-server}" />\r
                        </try>\r
                                </antcallback>\r
                                <concat>##teamcity[testFailed name='${target-server}' flowId='${target-server}' message='Integration test for ${target-server} failed.' details='${tried-escaped}']"</concat>\r
                        </catch>\r
 -              </trycatch>\r
 +              </antcontrib:trycatch>\r
                <concat>##teamcity[testFinished name='${target-server}' flowId='${target-server}']"</concat>\r
        </target>\r
-       \r
\r
        <target name="integration-test-get-lock">\r
                <sshexec host="${test.integration.server}" username="${user}" keyfile="${sshkey.file}" command="ant -f ${ant.hub} get-lock" />\r
        </target>\r
index 0000000000000000000000000000000000000000,e02c4f0b6e448d5979b417b720991867e6147f68..707fc020b604866fb549b8c1caac2ad1972edf27
mode 000000,100644..100644
--- /dev/null
@@@ -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<? extends ComponentContainer> c : getComponentContainers()) {
+             System.out.println(c.getName());
+         }
+         System.out.println();
+         System.out.println("Components");
+         System.out.println("==========");
+         for (Class<? extends Component> 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<Class<? extends Component>> getComponents() {
+         try {
+             return findClasses(Component.class, "com.vaadin.ui");
+         } catch (IOException e) {
+             e.printStackTrace();
+             return null;
+         }
+     }
++    public static List<Class<? extends Field>> getFields() {
++        try {
++            return findClasses(Field.class, "com.vaadin.ui");
++        } catch (IOException e) {
++            e.printStackTrace();
++            return null;
++        }
++    }
++
+     public static List<Class<? extends Object>> 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<Class<? extends ComponentContainer>> getComponentContainers() {
+         try {
+             return findClasses(ComponentContainer.class, "com.vaadin.ui");
+         } catch (IOException e) {
+             e.printStackTrace();
+             return null;
+         }
+     }
+     public static List<Class<? extends ComponentContainer>> getComponentContainersSupportingAddRemoveComponent() {
+         List<Class<? extends ComponentContainer>> 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<Class<? extends ComponentContainer>> getComponentContainersSupportingUnlimitedNumberOfComponents() {
+         List<Class<? extends ComponentContainer>> 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<Class<?>> 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 <T> List<Class<? extends T>> findClasses(Class<T> baseClass,
+             String basePackage) throws IOException {
+         return findClasses(baseClass, basePackage, new String[] {});
+     }
+     private static <T> List<Class<? extends T>> findClasses(Class<T> baseClass,
+             String basePackage, String[] ignoredPackages) throws IOException {
+         List<Class<? extends T>> classes = new ArrayList<Class<? extends T>>();
+         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<Class<? extends T>>() {
+             public int compare(Class<? extends T> o1, Class<? extends T> o2) {
+                 return o1.getName().compareTo(o2.getName());
+             }
+         });
+         return classes;
+     }
+     private static <T> List<Class<? extends T>> findClassesNoTests(
+             Class<T> baseClass, String basePackage, String[] ignoredPackages)
+             throws IOException {
+         List<Class<? extends T>> classes = findClasses(baseClass, basePackage,
+                 ignoredPackages);
+         List<Class<? extends T>> classesNoTests = new ArrayList<Class<? extends T>>();
+         for (Class<? extends T> 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 <T> void findPackages(JarURLConnection juc,
+             String javaPackage, Class<T> baseClass,
+             Collection<Class<? extends T>> result) throws IOException {
+         String prefix = "com/vaadin/ui";
+         Enumeration<JarEntry> 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 <T> void findPackages(File parent, String javaPackage,
+             Class<T> baseClass, Collection<Class<? extends T>> 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 <T> void addClassIfMatches(
+             Collection<Class<? extends T>> result,
+             String fullyQualifiedClassName, Class<T> baseClass) {
+         try {
+             // Try to load the class
+             Class<?> c = Class.forName(fullyQualifiedClassName);
+             if (baseClass.isAssignableFrom(c)
+                     && !Modifier.isAbstract(c.getModifiers())) {
+                 result.add((Class<? extends T>) 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 d4a8f5918c3d1dbd41979060ecbdd4c95632898a,39d45d2a74e7504d52a5f8f0c610f1dd94e69009..9d060c9a29e57edb4445cbdd488198ce976d79c1
                <fileset dir="${test-output-dir}" id="tests-fileset">
                        <include name="**/**.java" />
                </fileset>
 -
 -
 -              <for threadCount="30" parallel="true" keepgoing="true" param="target">
 +              
-               <antcontrib:for threadCount="40" parallel="true" keepgoing="true" param="target">
++              <antcontrib:for threadCount="30" parallel="true" keepgoing="true" param="target">
                        <path>
                                <fileset refid="tests-fileset" />
                        </path>
index 414c97c951cee89468bdf7ba65cb97c808697068,d7bc18e2f6d95b72730a1c09eef21ddd60eb89df..6bc6860607a448f7f3f54db45de9c1099ebeaee5
@@@ -29,14 -27,15 +29,14 @@@ import com.vaadin.ui.Root.LegacyWindow
  import com.vaadin.ui.Tree;\r
  import com.vaadin.ui.Tree.ItemStyleGenerator;\r
  import com.vaadin.ui.VerticalLayout;\r
 -import com.vaadin.ui.Window;\r
  \r
 -public class Components extends Application {\r
 +public class Components extends Application.LegacyApplication {\r
  \r
      private static final Object CAPTION = "c";\r
-     private Map<Class<? extends AbstractComponentTest<?>>, String> tests = new HashMap<Class<? extends AbstractComponentTest<?>>, String>();\r
+     private Map<Class<? extends AbstractComponentTest>, String> tests = new HashMap<Class<? extends AbstractComponentTest>, String>();\r
      private Tree naviTree;\r
      private HorizontalSplitPanel sp;\r
 -    private Window mainWindow;\r
 +    private LegacyWindow mainWindow;\r
      private final Embedded applicationEmbedder = new Embedded();\r
      private String baseUrl;\r
      private List<Class<? extends Component>> componentsWithoutTests = new ArrayList<Class<? extends Component>>();\r
index 85cc6ca5e1e6b87dc45be450817adf67534bd25b,ff3c304600948c43ac66c9c7a063500f5bec5af1..447b5b4be64d8b9b35789757545f32bb4924d7b6
@@@ -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 {
      }
  
      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++) {
      }
  
      @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 ";
      }
  
  }
index 0000000000000000000000000000000000000000,fe99cfaf2a2ae6a9a5c3185d1e73b6cb6c4e1c8e..3b0234d80542d5262d0c9eca4cf68f80e17c9284
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,91 +1,88 @@@
 -import com.vaadin.ui.Window;
+ 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;
 -        Window mainWindow = new Window("Synctest Application");
 -        mainWindow.setContent(buildLayout());
 -        setMainWindow(mainWindow);
+ public class ScrollDetachSynchronization extends TestBase {
+     @Override
+     public void setup() {
++        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;
+     }
+ }
index 8540e39c8c198391a73f07d79ef79a3de6dda8fd,f7d85f1a3c85b22394009b43ffbee6eb23d2dabb..bce96ebceda589d1e97dadbf0fbf6ae83778b61c
@@@ -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);
      }
index 0000000000000000000000000000000000000000,6aac7caddd8aa17792847d5f464a073cacdd45f1..c04c9d6c1321af0055949dfaf38984ccb3da4926
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,57 +1,59 @@@
 -        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());
 -                    }
 -                });
+ 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");
++        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;
+     }
+ }