]> source.dussan.org Git - vaadin-framework.git/commitdiff
#2904 Change client side class name prefixes I -> V (class names only, not yet CSS...
authorHenri Sara <henri.sara@itmill.com>
Mon, 11 May 2009 13:53:36 +0000 (13:53 +0000)
committerHenri Sara <henri.sara@itmill.com>
Mon, 11 May 2009 13:53:36 +0000 (13:53 +0000)
svn changeset:7742/svn branch:6.0

151 files changed:
src/com/vaadin/demo/colorpicker/gwt/client/ColorPickerWidgetSet.java
src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java [deleted file]
src/com/vaadin/demo/colorpicker/gwt/client/ui/VColorPicker.java [new file with mode: 0644]
src/com/vaadin/demo/coverflow/gwt/client/CoverflowWidgetSet.java
src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java [deleted file]
src/com/vaadin/demo/coverflow/gwt/client/ui/VCoverflow.java [new file with mode: 0644]
src/com/vaadin/demo/reservation/gwt/client/ReservationWidgetSet.java
src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java [deleted file]
src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java [deleted file]
src/com/vaadin/demo/reservation/gwt/client/ui/VCalendarField.java [new file with mode: 0644]
src/com/vaadin/demo/reservation/gwt/client/ui/VGoogleMap.java [new file with mode: 0644]
src/com/vaadin/demo/sampler/gwt/client/SamplerWidgetSet.java
src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java [deleted file]
src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java [deleted file]
src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java [deleted file]
src/com/vaadin/demo/sampler/gwt/client/ui/VActiveLink.java [new file with mode: 0644]
src/com/vaadin/demo/sampler/gwt/client/ui/VCodeLabel.java [new file with mode: 0644]
src/com/vaadin/demo/sampler/gwt/client/ui/VGoogleAnalytics.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/ComponentLocator.java
src/com/vaadin/terminal/gwt/client/DefaultWidgetSet.java
src/com/vaadin/terminal/gwt/client/ICaption.java [deleted file]
src/com/vaadin/terminal/gwt/client/ICaptionWrapper.java [deleted file]
src/com/vaadin/terminal/gwt/client/IDebugConsole.java [deleted file]
src/com/vaadin/terminal/gwt/client/IErrorMessage.java [deleted file]
src/com/vaadin/terminal/gwt/client/ITooltip.java [deleted file]
src/com/vaadin/terminal/gwt/client/UIDL.java
src/com/vaadin/terminal/gwt/client/VCaption.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/VDebugConsole.java [new file with mode: 0755]
src/com/vaadin/terminal/gwt/client/VErrorMessage.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/VTooltip.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/IAbsoluteLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IAccordion.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IButton.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ICalendarPanel.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ICheckBox.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IContextMenu.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ICustomComponent.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ICustomLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IDateField.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IDateFieldCalendar.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IEmbedded.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IFilterSelect.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IForm.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IFormLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IGridLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IHorizontalLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ILabel.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ILink.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IListSelect.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IMarginInfo.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IMenuBar.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/INativeSelect.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/INotification.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IOptionGroup.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IOptionGroupBase.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IOrderedLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IPanel.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IPasswordField.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IPopupCalendar.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IPopupView.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IProgressIndicator.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IScrollTable.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ISlider.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ISplitPanel.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ISplitPanelHorizontal.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ISplitPanelVertical.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITablePaging.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITabsheet.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITabsheetBase.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITabsheetPanel.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITextArea.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITextField.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITextualDate.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITime.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IToolkitOverlay.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITree.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/ITwinColSelect.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IUnknownComponent.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IUpload.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IUriFragmentUtility.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IVerticalLayout.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IView.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/IWindow.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/MenuBar.java
src/com/vaadin/terminal/gwt/client/ui/TreeAction.java
src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VAccordion.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VButton.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VDateField.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VForm.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VLabel.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VLink.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VListSelect.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VMarginInfo.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VNotification.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VPanel.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VPopupView.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VSlider.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTextArea.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTextField.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTime.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VToolkitOverlay.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTree.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VUpload.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VVerticalLayout.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VView.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VWindow.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/layout/CellBasedLayout.java
src/com/vaadin/terminal/gwt/client/ui/layout/ChildComponentContainer.java
src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextArea.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextToolbar$Strings.properties [deleted file]
src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextToolbar.java [deleted file]
src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextToolbar$Strings.properties [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextToolbar.java [new file with mode: 0644]
src/com/vaadin/ui/AbsoluteLayout.java
src/com/vaadin/ui/DateField.java
src/com/vaadin/ui/Layout.java

index 0a73b6eb5a11b36c5d78b7a714d044d51c72a6c7..ed6b32b6cd639adc591a71eb4cb1c70f737a0649 100644 (file)
@@ -4,7 +4,7 @@
 \r
 package com.vaadin.demo.colorpicker.gwt.client;\r
 \r
-import com.vaadin.demo.colorpicker.gwt.client.ui.IColorPicker;\r
+import com.vaadin.demo.colorpicker.gwt.client.ui.VColorPicker;\r
 import com.vaadin.terminal.gwt.client.DefaultWidgetSet;\r
 import com.vaadin.terminal.gwt.client.Paintable;\r
 import com.vaadin.terminal.gwt.client.UIDL;\r
@@ -15,7 +15,7 @@ public class ColorPickerWidgetSet extends DefaultWidgetSet {
     protected Class resolveWidgetType(UIDL uidl) {\r
         final String tag = uidl.getTag();\r
         if ("colorpicker".equals(tag)) {\r
-            return IColorPicker.class;\r
+            return VColorPicker.class;\r
         }\r
 \r
         // Let the DefaultWidgetSet handle resolution of default widgets\r
@@ -26,8 +26,8 @@ public class ColorPickerWidgetSet extends DefaultWidgetSet {
     @Override\r
     public Paintable createWidget(UIDL uidl) {\r
         final Class type = resolveWidgetType(uidl);\r
-        if (IColorPicker.class == type) {\r
-            return new IColorPicker();\r
+        if (VColorPicker.class == type) {\r
+            return new VColorPicker();\r
         }\r
 \r
         // Let the DefaultWidgetSet handle creation of default widgets\r
diff --git a/src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java b/src/com/vaadin/demo/colorpicker/gwt/client/ui/IColorPicker.java
deleted file mode 100644 (file)
index f238e9d..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.demo.colorpicker.gwt.client.ui;
-
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IColorPicker extends GwtColorPicker implements Paintable {
-
-    /** Set the CSS class name to allow styling. */
-    public static final String CLASSNAME = "example-colorpicker";
-
-    /** Component identifier in UIDL communications. */
-    String uidlId;
-
-    /** Reference to the server connection object. */
-    ApplicationConnection client;
-
-    /**
-     * The constructor should first call super() to initialize the component and
-     * then handle any initialization relevant to IT Mill Toolkit.
-     */
-    public IColorPicker() {
-        // The superclass has a lot of relevant initialization
-        super();
-
-        // This method call of the Paintable interface sets the component
-        // style name in DOM tree
-        setStyleName(CLASSNAME);
-    }
-
-    /**
-     * This method must be implemented to update the client-side component from
-     * UIDL data received from server.
-     * 
-     * This method is called when the page is loaded for the first time, and
-     * every time UI changes in the component are received from the server.
-     */
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // This call should be made first. Ensure correct implementation,
-        // and let the containing layout manage caption, etc.
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        // Save reference to server connection object to be able to send
-        // user interaction later
-        this.client = client;
-
-        // Save the UIDL identifier for the component
-        uidlId = uidl.getId();
-
-        // Get value received from server and actualize it in the GWT component
-        setColor(uidl.getStringVariable("colorname"));
-    }
-
-    /** Override the method to communicate the new value to server. */
-    @Override
-    public void setColor(String newcolor) {
-        // Ignore if no change
-        if (newcolor.equals(currentcolor.getText())) {
-            return;
-        }
-
-        // Let the original implementation to do whatever it needs to do
-        super.setColor(newcolor);
-
-        // Updating the state to the server can not be done before
-        // the server connection is known, i.e., before updateFromUIDL()
-        // has been called.
-        if (uidlId == null || client == null) {
-            return;
-        }
-
-        // Communicate the user interaction parameters to server. This call will
-        // initiate an AJAX request to the server.
-        client.updateVariable(uidlId, "colorname", newcolor, true);
-    }
-}
diff --git a/src/com/vaadin/demo/colorpicker/gwt/client/ui/VColorPicker.java b/src/com/vaadin/demo/colorpicker/gwt/client/ui/VColorPicker.java
new file mode 100644 (file)
index 0000000..7b90653
--- /dev/null
@@ -0,0 +1,82 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.demo.colorpicker.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VColorPicker extends GwtColorPicker implements Paintable {
+
+    /** Set the CSS class name to allow styling. */
+    public static final String CLASSNAME = "example-colorpicker";
+
+    /** Component identifier in UIDL communications. */
+    String uidlId;
+
+    /** Reference to the server connection object. */
+    ApplicationConnection client;
+
+    /**
+     * The constructor should first call super() to initialize the component and
+     * then handle any initialization relevant to IT Mill Toolkit.
+     */
+    public VColorPicker() {
+        // The superclass has a lot of relevant initialization
+        super();
+
+        // This method call of the Paintable interface sets the component
+        // style name in DOM tree
+        setStyleName(CLASSNAME);
+    }
+
+    /**
+     * This method must be implemented to update the client-side component from
+     * UIDL data received from server.
+     * 
+     * This method is called when the page is loaded for the first time, and
+     * every time UI changes in the component are received from the server.
+     */
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // This call should be made first. Ensure correct implementation,
+        // and let the containing layout manage caption, etc.
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        // Save reference to server connection object to be able to send
+        // user interaction later
+        this.client = client;
+
+        // Save the UIDL identifier for the component
+        uidlId = uidl.getId();
+
+        // Get value received from server and actualize it in the GWT component
+        setColor(uidl.getStringVariable("colorname"));
+    }
+
+    /** Override the method to communicate the new value to server. */
+    @Override
+    public void setColor(String newcolor) {
+        // Ignore if no change
+        if (newcolor.equals(currentcolor.getText())) {
+            return;
+        }
+
+        // Let the original implementation to do whatever it needs to do
+        super.setColor(newcolor);
+
+        // Updating the state to the server can not be done before
+        // the server connection is known, i.e., before updateFromUIDL()
+        // has been called.
+        if (uidlId == null || client == null) {
+            return;
+        }
+
+        // Communicate the user interaction parameters to server. This call will
+        // initiate an AJAX request to the server.
+        client.updateVariable(uidlId, "colorname", newcolor, true);
+    }
+}
index 38037a4ba08df6534c3e47bcef386a31f02a0739..e9fc76dae8e3cb06236b3ff816a9e5d233c0812c 100644 (file)
@@ -4,7 +4,7 @@
 
 package com.vaadin.demo.coverflow.gwt.client;
 
-import com.vaadin.demo.coverflow.gwt.client.ui.ICoverflow;
+import com.vaadin.demo.coverflow.gwt.client.ui.VCoverflow;
 import com.vaadin.terminal.gwt.client.DefaultWidgetSet;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
@@ -13,8 +13,8 @@ public class CoverflowWidgetSet extends DefaultWidgetSet {
     /** Creates a widget according to its class name. */
     public Paintable createWidget(UIDL uidl) {
         final Class classType = resolveWidgetType(uidl);
-        if (ICoverflow.class == classType) {
-            return new ICoverflow();
+        if (VCoverflow.class == classType) {
+            return new VCoverflow();
         }
 
         // Let the DefaultWidgetSet handle creation of default widgets
@@ -25,7 +25,7 @@ public class CoverflowWidgetSet extends DefaultWidgetSet {
     protected Class resolveWidgetType(UIDL uidl) {
         final String tag = uidl.getTag();
         if ("cover".equals(tag)) {
-            return ICoverflow.class;
+            return VCoverflow.class;
         }
 
         // Let the DefaultWidgetSet handle resolution of default widgets
diff --git a/src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java b/src/com/vaadin/demo/coverflow/gwt/client/ui/ICoverflow.java
deleted file mode 100644 (file)
index c09d18c..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-package com.vaadin.demo.coverflow.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTML;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class ICoverflow extends Composite implements Paintable {
-    private String uidlId;
-    protected ApplicationConnection client;
-    private ArrayList coverList = new ArrayList();
-
-    private Object _selected;
-    private boolean flashInited = false;
-    private HTML flash;
-    private boolean scrollbarVisibility = true;
-    private String backgroundGradientStart;
-    private String backgroundGradientEnd;
-    private boolean colorChanged = false;
-    private boolean sbVisibilityChanged = false;
-    private HashMap keyMap = new HashMap();
-
-    /**
-     * Constructor
-     */
-    public ICoverflow() {
-        flash = new HTML();
-
-        initWidget(flash);
-    }
-
-    /**
-     * This method accepts parses the uidl sent by the server
-     * 
-     * @param UIDL
-     *            uidl
-     * @param ApplicationConnection
-     *            client
-     */
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // Store variables
-        uidlId = uidl.getId();
-        this.client = client;
-        String tempColor;
-
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        // Has the scrollbar's visibility status changed?
-        if (uidl.hasAttribute("scrollbarVisibility")) {
-            boolean tempVis = uidl.getBooleanAttribute("scrollbarVisibility");
-            if (scrollbarVisibility != tempVis) {
-                scrollbarVisibility = tempVis;
-                sbVisibilityChanged = true;
-            }
-        }
-
-        // Has the start gradient changed?
-        if (uidl.hasAttribute("backgroundGradientStart")) {
-            tempColor = uidl.getStringAttribute("backgroundGradientStart")
-                    .toString();
-            if (tempColor != backgroundGradientStart) {
-                backgroundGradientStart = tempColor;
-                colorChanged = true;
-            }
-        }
-
-        // Has the end gradient changed?
-        if (uidl.hasAttribute("backgroundGradientEnd")) {
-            tempColor = uidl.getStringAttribute("backgroundGradientEnd")
-                    .toString();
-            if (tempColor != backgroundGradientEnd) {
-                backgroundGradientEnd = tempColor;
-                colorChanged = true;
-            }
-        }
-
-        final UIDL images = uidl.getChildUIDL(0);
-
-        // Check which covers should be removed. This array list contains all
-        // current
-        // covers. We remove from this list all covers which are sent with the
-        // repainted
-        // uidl. All remaining covers in this list should be "old" ones and are
-        // should
-        // be deleted.
-
-        ArrayList newList = new ArrayList();
-
-        // Iterate through all option elements
-        for (final Iterator i = images.getChildIterator(); i.hasNext();) {
-            final UIDL imgUidl = (UIDL) i.next();
-
-            // Make sure all required attributes exist
-            if (imgUidl.hasAttribute("caption") && imgUidl.hasAttribute("key")
-                    && imgUidl.hasAttribute("icon")) {
-                HashMap set = new HashMap();
-
-                // Update the key map
-                keyMap.put(imgUidl.getStringAttribute("caption"), imgUidl
-                        .getStringAttribute("key"));
-
-                // Get information
-
-                set.put("icon", client.translateToolkitUri(imgUidl
-                        .getStringAttribute("icon")));
-                set.put("caption", imgUidl.getStringAttribute("caption"));
-
-                newList.add(set);
-
-                // Is the current cover selected?
-                if (imgUidl.hasAttribute("selected")) {
-                    _selected = imgUidl.getStringAttribute("caption");
-                }
-            }
-        }
-
-        // Deleted items
-        ArrayList intersectList = new ArrayList();
-        intersectList.addAll(coverList);
-        intersectList.removeAll(newList);
-
-        if (flashInited) {
-            for (int i = 0; i < intersectList.size(); i++) {
-                HashMap cover = (HashMap) intersectList.get(i);
-                removeCover(uidlId, cover.get("caption").toString());
-            }
-        }
-
-        // Added items
-        intersectList = new ArrayList();
-        intersectList.addAll(newList);
-        intersectList.removeAll(coverList);
-
-        if (flashInited) {
-            for (int i = 0; i < intersectList.size(); i++) {
-                HashMap cover = (HashMap) intersectList.get(i);
-                addCover(uidlId, cover.get("caption").toString(), cover.get(
-                        "icon").toString());
-            }
-        }
-
-        coverList = newList;
-
-        // Has the flash been initialized?
-        if (!flashInited) {
-            colorChanged = false;
-            setFlash();
-            initializeMethods(uidlId);
-        }
-
-        // Inform flash of the selected cover
-        if (_selected != null && flashInited) {
-            selectCover(uidlId, _selected.toString());
-        }
-
-        if (colorChanged && flashInited) {
-            setBackgroundColor(uidlId, backgroundGradientStart,
-                    backgroundGradientEnd);
-            colorChanged = false;
-        }
-
-        if (sbVisibilityChanged && flashInited) {
-            toggleScrollbarVisibility(uidlId, scrollbarVisibility);
-            sbVisibilityChanged = false;
-        }
-
-    }
-
-    /**
-     * Inform the server which cover is selected
-     * 
-     * @param String
-     *            coverKey
-     */
-    public void setCover(String coverId) {
-        if (uidlId == null || client == null) {
-            return;
-        }
-
-        client.updateVariable(uidlId, "selected", new String[] { keyMap.get(
-                coverId).toString() }, true);
-    }
-
-    /**
-     * Initialize the native javascript functions needed for the flash <-> GWT
-     * communication
-     * 
-     * @param String
-     *            id
-     */
-    public native void initializeMethods(String id) /*-{
-          var app = this;
-          
-          if($wnd.itmill.coverflow == null)
-               var coverflow = [];
-          else
-               var coverflow = $wnd.itmill.coverflow;
-               
-          coverflow['getCovers_' + id] = function() {                
-               app.@com.vaadin.demo.coverflow.gwt.client.ui.ICoverflow::getCovers()();
-          };   
-          
-               coverflow['setCurrent_' + id] = function(selected) {
-               app.@com.vaadin.demo.coverflow.gwt.client.ui.ICoverflow::setCover(Ljava/lang/String;)(selected);
-          };
-          
-          $wnd.itmill.coverflow = coverflow;
-      }-*/;
-
-    /**
-     * This function sends all covers to the flash. We cannot do this directly
-     * in the updateFromUIDL method, because we cannot be sure if the flash has
-     * been loaded into the browser. The flash will call for this method when
-     * it's ready.
-     */
-    public void getCovers() {
-        // Loop through all stored coves
-        for (int i = 0; i < coverList.size(); i++) {
-            HashMap set = (HashMap) coverList.get(i);
-
-            try {
-                // Add the cover
-                addCover(uidlId, set.get("caption").toString(), set.get("icon")
-                        .toString());
-            } catch (Exception e) {
-                // Do not add covers lacking obligatory data
-            }
-        }
-        // The flash calls for this method, therefore we can be sure that the
-        // flash has been loaded
-        // into the browser.
-        flashInited = true;
-
-        // Set selected cover
-        if (_selected != null) {
-            selectCover(uidlId, _selected.toString());
-        }
-    }
-
-    /**
-     * This function is a native javascript function which adds covers to the
-     * actual flash. This method works as a bridge between GWT and flash.
-     * 
-     * @param id
-     * @param key
-     * @param caption
-     * @param icon
-     */
-    public native void addCover(String id, String caption, String icon) /*-{   
-          try {
-                   $doc['fxcoverflow' + id].addCover(caption.toString(), icon.toString());
-              }
-              catch(e) {
-                  $wnd.alert(e.message);
-              }   
-                       
-          }-*/;
-
-    /**
-     * This function tells the flash which cover should be selected.
-     * 
-     * @param id
-     * @param key
-     */
-    public native void selectCover(String id, String key) /*-{    
-               $doc["fxcoverflow" + id].selectCover(key.toString());
-       }-*/;
-
-    public native void setBackgroundColor(String id, String startGradient,
-            String endGradient) /*-{           
-               $doc["fxcoverflow" + id].setBackgroundColor("0x" + startGradient.toString(), "0x" + endGradient.toString());
-      }-*/;
-
-    public native void toggleScrollbarVisibility(String id, boolean visibility) /*-{           
-               $doc["fxcoverflow" + id].toggleScrollbarVisibility(visibility);
-       }-*/;
-
-    public native void removeCover(String id, String key) /*-{         
-               $doc["fxcoverflow" + id].removeCover(key);
-       }-*/;
-
-    /**
-     * Set the HTML coding of the flash movie. This isn't done until the
-     * updateFromUIDL method is called for the first time. The reason is that we
-     * use an id from the UIDL to uniquely identify all instances of this
-     * widget.
-     */
-    private void setFlash() {
-        String html = "<object id=\"fxcoverflow"
-                + uidlId
-                + "\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"100%\""
-                + " height=\"100%\" codebase=\"http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0\">"
-                + "<param name=\"movie\" value=\""
-                + GWT.getModuleBaseURL()
-                + "coverflowflash.swf\">"
-                + "<param name=\"quality\" value=\"high\">"
-                + "<param name=\"flashVars\" value=\"pid="
-                + uidlId
-                + "&sbVis="
-                + scrollbarVisibility
-                + "&bgS=0x"
-                + backgroundGradientStart
-                + "&bgE=0x"
-                + backgroundGradientEnd
-                + "\" />"
-                + "<embed name=\"fxcoverflow"
-                + uidlId
-                + "\" flashVars=\"pid="
-                + uidlId
-                + "&sbVis="
-                + scrollbarVisibility
-                + "&bgS=0x"
-                + backgroundGradientStart
-                + "&bgE=0x"
-                + backgroundGradientEnd
-                + "\" src=\""
-                + GWT.getModuleBaseURL()
-                + "coverflowflash.swf\" width=\"100%\" height=\"100%\" "
-                + "quality=\"high\" "
-                + "pluginspage=\"http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash\">"
-                + "</embed>" + "</object>";
-        flash.setHTML(html);
-    }
-}
\ No newline at end of file
diff --git a/src/com/vaadin/demo/coverflow/gwt/client/ui/VCoverflow.java b/src/com/vaadin/demo/coverflow/gwt/client/ui/VCoverflow.java
new file mode 100644 (file)
index 0000000..a09c9b1
--- /dev/null
@@ -0,0 +1,336 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+package com.vaadin.demo.coverflow.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VCoverflow extends Composite implements Paintable {
+    private String uidlId;
+    protected ApplicationConnection client;
+    private ArrayList coverList = new ArrayList();
+
+    private Object _selected;
+    private boolean flashInited = false;
+    private HTML flash;
+    private boolean scrollbarVisibility = true;
+    private String backgroundGradientStart;
+    private String backgroundGradientEnd;
+    private boolean colorChanged = false;
+    private boolean sbVisibilityChanged = false;
+    private HashMap keyMap = new HashMap();
+
+    /**
+     * Constructor
+     */
+    public VCoverflow() {
+        flash = new HTML();
+
+        initWidget(flash);
+    }
+
+    /**
+     * This method accepts parses the uidl sent by the server
+     * 
+     * @param UIDL
+     *            uidl
+     * @param ApplicationConnection
+     *            client
+     */
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // Store variables
+        uidlId = uidl.getId();
+        this.client = client;
+        String tempColor;
+
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        // Has the scrollbar's visibility status changed?
+        if (uidl.hasAttribute("scrollbarVisibility")) {
+            boolean tempVis = uidl.getBooleanAttribute("scrollbarVisibility");
+            if (scrollbarVisibility != tempVis) {
+                scrollbarVisibility = tempVis;
+                sbVisibilityChanged = true;
+            }
+        }
+
+        // Has the start gradient changed?
+        if (uidl.hasAttribute("backgroundGradientStart")) {
+            tempColor = uidl.getStringAttribute("backgroundGradientStart")
+                    .toString();
+            if (tempColor != backgroundGradientStart) {
+                backgroundGradientStart = tempColor;
+                colorChanged = true;
+            }
+        }
+
+        // Has the end gradient changed?
+        if (uidl.hasAttribute("backgroundGradientEnd")) {
+            tempColor = uidl.getStringAttribute("backgroundGradientEnd")
+                    .toString();
+            if (tempColor != backgroundGradientEnd) {
+                backgroundGradientEnd = tempColor;
+                colorChanged = true;
+            }
+        }
+
+        final UIDL images = uidl.getChildUIDL(0);
+
+        // Check which covers should be removed. This array list contains all
+        // current
+        // covers. We remove from this list all covers which are sent with the
+        // repainted
+        // uidl. All remaining covers in this list should be "old" ones and are
+        // should
+        // be deleted.
+
+        ArrayList newList = new ArrayList();
+
+        // Iterate through all option elements
+        for (final Iterator i = images.getChildIterator(); i.hasNext();) {
+            final UIDL imgUidl = (UIDL) i.next();
+
+            // Make sure all required attributes exist
+            if (imgUidl.hasAttribute("caption") && imgUidl.hasAttribute("key")
+                    && imgUidl.hasAttribute("icon")) {
+                HashMap set = new HashMap();
+
+                // Update the key map
+                keyMap.put(imgUidl.getStringAttribute("caption"), imgUidl
+                        .getStringAttribute("key"));
+
+                // Get information
+
+                set.put("icon", client.translateToolkitUri(imgUidl
+                        .getStringAttribute("icon")));
+                set.put("caption", imgUidl.getStringAttribute("caption"));
+
+                newList.add(set);
+
+                // Is the current cover selected?
+                if (imgUidl.hasAttribute("selected")) {
+                    _selected = imgUidl.getStringAttribute("caption");
+                }
+            }
+        }
+
+        // Deleted items
+        ArrayList intersectList = new ArrayList();
+        intersectList.addAll(coverList);
+        intersectList.removeAll(newList);
+
+        if (flashInited) {
+            for (int i = 0; i < intersectList.size(); i++) {
+                HashMap cover = (HashMap) intersectList.get(i);
+                removeCover(uidlId, cover.get("caption").toString());
+            }
+        }
+
+        // Added items
+        intersectList = new ArrayList();
+        intersectList.addAll(newList);
+        intersectList.removeAll(coverList);
+
+        if (flashInited) {
+            for (int i = 0; i < intersectList.size(); i++) {
+                HashMap cover = (HashMap) intersectList.get(i);
+                addCover(uidlId, cover.get("caption").toString(), cover.get(
+                        "icon").toString());
+            }
+        }
+
+        coverList = newList;
+
+        // Has the flash been initialized?
+        if (!flashInited) {
+            colorChanged = false;
+            setFlash();
+            initializeMethods(uidlId);
+        }
+
+        // Inform flash of the selected cover
+        if (_selected != null && flashInited) {
+            selectCover(uidlId, _selected.toString());
+        }
+
+        if (colorChanged && flashInited) {
+            setBackgroundColor(uidlId, backgroundGradientStart,
+                    backgroundGradientEnd);
+            colorChanged = false;
+        }
+
+        if (sbVisibilityChanged && flashInited) {
+            toggleScrollbarVisibility(uidlId, scrollbarVisibility);
+            sbVisibilityChanged = false;
+        }
+
+    }
+
+    /**
+     * Inform the server which cover is selected
+     * 
+     * @param String
+     *            coverKey
+     */
+    public void setCover(String coverId) {
+        if (uidlId == null || client == null) {
+            return;
+        }
+
+        client.updateVariable(uidlId, "selected", new String[] { keyMap.get(
+                coverId).toString() }, true);
+    }
+
+    /**
+     * Initialize the native javascript functions needed for the flash <-> GWT
+     * communication
+     * 
+     * @param String
+     *            id
+     */
+    public native void initializeMethods(String id) /*-{
+          var app = this;
+          
+          if($wnd.itmill.coverflow == null)
+               var coverflow = [];
+          else
+               var coverflow = $wnd.itmill.coverflow;
+               
+          coverflow['getCovers_' + id] = function() {                
+               app.@com.vaadin.demo.coverflow.gwt.client.ui.VCoverflow::getCovers()();
+          };   
+          
+               coverflow['setCurrent_' + id] = function(selected) {
+               app.@com.vaadin.demo.coverflow.gwt.client.ui.VCoverflow::setCover(Ljava/lang/String;)(selected);
+          };
+          
+          $wnd.itmill.coverflow = coverflow;
+      }-*/;
+
+    /**
+     * This function sends all covers to the flash. We cannot do this directly
+     * in the updateFromUIDL method, because we cannot be sure if the flash has
+     * been loaded into the browser. The flash will call for this method when
+     * it's ready.
+     */
+    public void getCovers() {
+        // Loop through all stored coves
+        for (int i = 0; i < coverList.size(); i++) {
+            HashMap set = (HashMap) coverList.get(i);
+
+            try {
+                // Add the cover
+                addCover(uidlId, set.get("caption").toString(), set.get("icon")
+                        .toString());
+            } catch (Exception e) {
+                // Do not add covers lacking obligatory data
+            }
+        }
+        // The flash calls for this method, therefore we can be sure that the
+        // flash has been loaded
+        // into the browser.
+        flashInited = true;
+
+        // Set selected cover
+        if (_selected != null) {
+            selectCover(uidlId, _selected.toString());
+        }
+    }
+
+    /**
+     * This function is a native javascript function which adds covers to the
+     * actual flash. This method works as a bridge between GWT and flash.
+     * 
+     * @param id
+     * @param key
+     * @param caption
+     * @param icon
+     */
+    public native void addCover(String id, String caption, String icon) /*-{   
+          try {
+                   $doc['fxcoverflow' + id].addCover(caption.toString(), icon.toString());
+              }
+              catch(e) {
+                  $wnd.alert(e.message);
+              }   
+                       
+          }-*/;
+
+    /**
+     * This function tells the flash which cover should be selected.
+     * 
+     * @param id
+     * @param key
+     */
+    public native void selectCover(String id, String key) /*-{    
+               $doc["fxcoverflow" + id].selectCover(key.toString());
+       }-*/;
+
+    public native void setBackgroundColor(String id, String startGradient,
+            String endGradient) /*-{           
+               $doc["fxcoverflow" + id].setBackgroundColor("0x" + startGradient.toString(), "0x" + endGradient.toString());
+      }-*/;
+
+    public native void toggleScrollbarVisibility(String id, boolean visibility) /*-{           
+               $doc["fxcoverflow" + id].toggleScrollbarVisibility(visibility);
+       }-*/;
+
+    public native void removeCover(String id, String key) /*-{         
+               $doc["fxcoverflow" + id].removeCover(key);
+       }-*/;
+
+    /**
+     * Set the HTML coding of the flash movie. This isn't done until the
+     * updateFromUIDL method is called for the first time. The reason is that we
+     * use an id from the UIDL to uniquely identify all instances of this
+     * widget.
+     */
+    private void setFlash() {
+        String html = "<object id=\"fxcoverflow"
+                + uidlId
+                + "\" classid=\"clsid:d27cdb6e-ae6d-11cf-96b8-444553540000\" width=\"100%\""
+                + " height=\"100%\" codebase=\"http://fpdownload.adobe.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0\">"
+                + "<param name=\"movie\" value=\""
+                + GWT.getModuleBaseURL()
+                + "coverflowflash.swf\">"
+                + "<param name=\"quality\" value=\"high\">"
+                + "<param name=\"flashVars\" value=\"pid="
+                + uidlId
+                + "&sbVis="
+                + scrollbarVisibility
+                + "&bgS=0x"
+                + backgroundGradientStart
+                + "&bgE=0x"
+                + backgroundGradientEnd
+                + "\" />"
+                + "<embed name=\"fxcoverflow"
+                + uidlId
+                + "\" flashVars=\"pid="
+                + uidlId
+                + "&sbVis="
+                + scrollbarVisibility
+                + "&bgS=0x"
+                + backgroundGradientStart
+                + "&bgE=0x"
+                + backgroundGradientEnd
+                + "\" src=\""
+                + GWT.getModuleBaseURL()
+                + "coverflowflash.swf\" width=\"100%\" height=\"100%\" "
+                + "quality=\"high\" "
+                + "pluginspage=\"http://www.adobe.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash\">"
+                + "</embed>" + "</object>";
+        flash.setHTML(html);
+    }
+}
\ No newline at end of file
index 9bf5f22061851e1705cf5d898d52f18413a12f15..01577a6917876b121f48da1441bc58fdd88f30b2 100644 (file)
@@ -4,8 +4,8 @@
 \r
 package com.vaadin.demo.reservation.gwt.client;\r
 \r
-import com.vaadin.demo.reservation.gwt.client.ui.ICalendarField;\r
-import com.vaadin.demo.reservation.gwt.client.ui.IGoogleMap;\r
+import com.vaadin.demo.reservation.gwt.client.ui.VCalendarField;\r
+import com.vaadin.demo.reservation.gwt.client.ui.VGoogleMap;\r
 import com.vaadin.terminal.gwt.client.DefaultWidgetSet;\r
 import com.vaadin.terminal.gwt.client.Paintable;\r
 import com.vaadin.terminal.gwt.client.UIDL;\r
@@ -14,10 +14,10 @@ public class ReservationWidgetSet extends DefaultWidgetSet {
     @Override\r
     public Paintable createWidget(UIDL uidl) {\r
         final Class type = resolveWidgetType(uidl);\r
-        if (IGoogleMap.class == type) {\r
-            return new IGoogleMap();\r
-        } else if (ICalendarField.class == type) {\r
-            return new ICalendarField();\r
+        if (VGoogleMap.class == type) {\r
+            return new VGoogleMap();\r
+        } else if (VCalendarField.class == type) {\r
+            return new VCalendarField();\r
         }\r
 \r
         return super.createWidget(uidl);\r
@@ -27,9 +27,9 @@ public class ReservationWidgetSet extends DefaultWidgetSet {
     protected Class resolveWidgetType(UIDL uidl) {\r
         final String tag = uidl.getTag();\r
         if ("googlemap".equals(tag)) {\r
-            return IGoogleMap.class;\r
+            return VGoogleMap.class;\r
         } else if ("calendarfield".equals(tag)) {\r
-            return ICalendarField.class;\r
+            return VCalendarField.class;\r
         }\r
         return super.resolveWidgetType(uidl);\r
     }\r
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java b/src/com/vaadin/demo/reservation/gwt/client/ui/ICalendarField.java
deleted file mode 100644 (file)
index a11321d..0000000
+++ /dev/null
@@ -1,294 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.demo.reservation.gwt.client.ui;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Date;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import com.google.gwt.i18n.client.DateTimeFormat;\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.Element;\r
-import com.google.gwt.user.client.ui.FlexTable;\r
-import com.google.gwt.user.client.ui.SimplePanel;\r
-import com.google.gwt.user.client.ui.SourcesTableEvents;\r
-import com.google.gwt.user.client.ui.TableListener;\r
-import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
-import com.vaadin.terminal.gwt.client.DateTimeService;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-import com.vaadin.terminal.gwt.client.ui.CalendarEntry;\r
-import com.vaadin.terminal.gwt.client.ui.ICalendarPanel;\r
-import com.vaadin.terminal.gwt.client.ui.IDateField;\r
-\r
-public class ICalendarField extends IDateField {\r
-\r
-    private final ICalendarPanel calPanel;\r
-\r
-    private SimplePanel hourPanel;\r
-\r
-    private FlexTable hourTable;\r
-\r
-    private final EntrySource entrySource;\r
-\r
-    private final TableListener ftListener = new HourTableListener();\r
-\r
-    private int realResolution = RESOLUTION_DAY;\r
-\r
-    private static final String CLASSNAME = IDateField.CLASSNAME\r
-            + "-entrycalendar";\r
-\r
-    public ICalendarField() {\r
-        super();\r
-        setStyleName(CLASSNAME);\r
-        calPanel = new ICalendarPanel(this);\r
-        add(calPanel);\r
-        entrySource = new EntrySource();\r
-        calPanel.setCalendarEntrySource(entrySource);\r
-        calPanel.addTableListener(new TableListener() {\r
-            public void onCellClicked(SourcesTableEvents sender, int row,\r
-                    int cell) {\r
-                buildDayView(date);\r
-            }\r
-        });\r
-    }\r
-\r
-    @Override\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        super.updateFromUIDL(uidl, client);\r
-        // We want to draw our own hour list\r
-        realResolution = currentResolution;\r
-        currentResolution = RESOLUTION_DAY;\r
-        if (uidl.hasAttribute("min")) {\r
-            final String mins = uidl.getStringAttribute("min");\r
-            final long min = (mins != null ? Long.parseLong(mins) : 0);\r
-            final String maxs = uidl.getStringAttribute("max");\r
-            final long max = (maxs != null ? Long.parseLong(maxs) : 0);\r
-            final Date minDate = (min > 0 ? new Date(min) : null);\r
-            final Date maxDate = (max > 0 ? new Date(max) : null);\r
-            calPanel.setLimits(minDate, maxDate);\r
-        }\r
-        entrySource.clear();\r
-        for (final Iterator cit = uidl.getChildIterator(); cit.hasNext();) {\r
-            final UIDL child = (UIDL) cit.next();\r
-            if (child.getTag().equals("items")) {\r
-                for (final Iterator iit = child.getChildIterator(); iit\r
-                        .hasNext();) {\r
-                    final UIDL item = (UIDL) iit.next();\r
-                    entrySource.addItem(item);\r
-                }\r
-                break;\r
-            }\r
-        }\r
-        calPanel.updateCalendar();\r
-        buildDayView(date);\r
-    }\r
-\r
-    protected void buildDayView(Date date) {\r
-        if (hourPanel == null) {\r
-            hourPanel = new SimplePanel();\r
-            hourPanel.setStyleName(CLASSNAME + "-hours");\r
-            calPanel.getFlexCellFormatter().setColSpan(8, 0, 7);\r
-            calPanel.setWidget(8, 0, hourPanel);\r
-        } else {\r
-            hourPanel.clear();\r
-        }\r
-        hourTable = new FlexTable();\r
-        hourTable.addTableListener(ftListener);\r
-        hourPanel.add(hourTable);\r
-        hourTable.setCellSpacing(1);\r
-\r
-        for (int i = 0; i < 24; i++) {\r
-            String style = (i % 2 == 0 ? "even" : "odd");\r
-            if (realResolution >= RESOLUTION_HOUR) {\r
-                if (this.date != null && this.date.getHours() == i) {\r
-                    style = "selected";\r
-                }\r
-            }\r
-            hourTable.getRowFormatter().setStyleName(i,\r
-                    CLASSNAME + "-row-" + style);\r
-            String hstr = (i < 10 ? "0" : "") + i + ":00";\r
-            if (dts.isTwelveHourClock()) {\r
-                final String ampm = (i < 12 ? "am" : "pm");\r
-                hstr = (i <= 12 ? i : i - 12) + ":00 " + ampm;\r
-            }\r
-            hourTable.setHTML(i, 0, "<span>" + hstr + "</span>");\r
-            hourTable.getCellFormatter()\r
-                    .setStyleName(i, 0, CLASSNAME + "-time");\r
-        }\r
-\r
-        final List entries = entrySource.getEntries(date,\r
-                DateTimeService.RESOLUTION_DAY);\r
-        int currentCol = 1;\r
-        for (final Iterator it = entries.iterator(); it.hasNext();) {\r
-            final CalendarEntry entry = (CalendarEntry) it.next();\r
-            int start = 0;\r
-            int hours = 24;\r
-            if (!entry.isNotime()) {\r
-                Date d = entry.getStart();\r
-                // TODO consider month&year as well\r
-                start = (d.getDate() < date.getDate() ? 0 : d.getHours());\r
-                d = entry.getEnd();\r
-                hours = (d.getDate() > date.getDate() ? 24 : d.getHours())\r
-                        - start;\r
-                if (hours < 1) {\r
-                    // We can't draw entries smaller than\r
-                    // one\r
-                    hours = 1;\r
-                }\r
-            }\r
-            int col = currentCol;\r
-            if (col > 1) {\r
-                while (!hourTable.isCellPresent(start, col - 1)) {\r
-                    col--;\r
-                }\r
-            }\r
-            hourTable.setHTML(start, col, "<span>"\r
-                    + (entry.getTitle() != null ? entry.getTitle() : "&nbsp")\r
-                    + "</span>");\r
-            hourTable.getFlexCellFormatter().setRowSpan(start, col, hours);\r
-            hourTable.getFlexCellFormatter().setStyleName(start, col,\r
-                    CLASSNAME + "-entry");\r
-            final String sn = entry.getStyleName();\r
-            if (sn != null && !sn.equals("")) {\r
-                hourTable.getFlexCellFormatter().addStyleName(start, col,\r
-                        CLASSNAME + "-" + entry.getStyleName());\r
-            }\r
-            final Element el = hourTable.getFlexCellFormatter().getElement(\r
-                    start, col);\r
-\r
-            String tooltip;\r
-            if (DateTimeService.isSameDay(entry.getStart(), entry.getEnd())) {\r
-                tooltip = (start < 10 ? "0" : "") + start + ":00";\r
-                if (dts.isTwelveHourClock()) {\r
-                    final String ampm = (start < 12 ? "am" : "pm");\r
-                    tooltip = (start <= 12 ? start : start - 12) + ":00 "\r
-                            + ampm;\r
-\r
-                }\r
-                tooltip += " (" + hours + "h) ";\r
-                if (entry.getTitle() != null) {\r
-                    tooltip += entry.getTitle() + "\n ";\r
-                }\r
-            } else {\r
-                tooltip = entry.getStringForDate(entry.getEnd()) + "\n ";\r
-            }\r
-            if (entry.getDescription() != null) {\r
-                tooltip += "\"" + entry.getDescription() + "\"";\r
-            }\r
-            DOM.setElementProperty(el, "title", tooltip);\r
-\r
-            currentCol++;\r
-        }\r
-\r
-        // int hour = new Date().getHours()+1; // scroll to current hour\r
-        Date d = (this.date != null ? this.date : new Date());\r
-        final int hour = d.getHours() + 1; // scroll to selected\r
-        // hour\r
-        final int h1 = hourPanel.getOffsetHeight() / 2;\r
-        final int oh = hourTable.getOffsetHeight();\r
-        final int h2 = (int) (hour / 24.0 * oh);\r
-        final int scrollTop = h2 - h1;\r
-        final Element el = hourPanel.getElement();\r
-        setScrollTop(el, scrollTop);\r
-\r
-    }\r
-\r
-    private native void setScrollTop(Element el, int scrollTop)\r
-    /*-{\r
-         el.scrollTop = scrollTop;\r
-    }-*/;\r
-\r
-    private class HourTableListener implements TableListener {\r
-\r
-        public void onCellClicked(SourcesTableEvents sender, int row, int cell) {\r
-            if (realResolution < RESOLUTION_HOUR || date == null) {\r
-                return;\r
-            }\r
-            date.setHours(row);\r
-            client.updateVariable(id, "hour", row, immediate);\r
-        }\r
-\r
-    }\r
-\r
-    private class EntrySource implements ICalendarPanel.CalendarEntrySource {\r
-\r
-        private final HashMap dates = new HashMap();\r
-\r
-        public void addItem(UIDL item) {\r
-            final String styleName = item.getStringAttribute("styleName");\r
-            // final Integer id = new Integer(item.getIntAttribute("id"));\r
-\r
-            DateTimeFormat dtf = DateTimeFormat\r
-                    .getFormat("d MM yyyy HH:mm:ss Z");\r
-\r
-            Date startDate = dtf.parse(item.getStringAttribute("start"));\r
-\r
-            // fix times with server-client difference\r
-            int diff = (startDate.getTimezoneOffset() - item\r
-                    .getIntAttribute("Z")) * 60000;\r
-            startDate = new Date(startDate.getTime() + diff);\r
-            Date endDate;\r
-            if (item.hasAttribute("end")) {\r
-                endDate = dtf.parse(item.getStringAttribute("end"));\r
-                endDate = new Date(endDate.getTime() + diff);\r
-            } else {\r
-                endDate = (Date) startDate.clone();\r
-            }\r
-            final String title = item.getStringAttribute("title");\r
-            final String desc = item.getStringAttribute("description");\r
-            final boolean notime = item.getBooleanAttribute("notime");\r
-            final CalendarEntry entry = new CalendarEntry(styleName, startDate,\r
-                    endDate, title, desc, notime);\r
-\r
-            // TODO should remove+readd if the same entry (id) is\r
-            // added again\r
-\r
-            for (final Date d = new Date(entry.getStart().getTime()); d\r
-                    .getYear() <= entry.getEnd().getYear()\r
-                    && d.getMonth() <= entry.getEnd().getYear()\r
-                    && d.getDate() <= entry.getEnd().getDate(); d.setTime(d\r
-                    .getTime() + 86400000)) {\r
-                final String key = d.getYear() + "" + d.getMonth() + ""\r
-                        + d.getDate();\r
-                ArrayList l = (ArrayList) dates.get(key);\r
-                if (l == null) {\r
-                    l = new ArrayList();\r
-                    dates.put(key, l);\r
-                }\r
-                l.add(entry);\r
-            }\r
-        }\r
-\r
-        public List getEntries(Date date, int resolution) {\r
-            final ArrayList res = new ArrayList();\r
-            if (date == null) {\r
-                return res;\r
-            }\r
-            final List entries = (List) dates.get(date.getYear() + ""\r
-                    + date.getMonth() + "" + date.getDate());\r
-\r
-            if (entries == null) {\r
-                return res;\r
-            }\r
-            for (final Iterator it = entries.iterator(); it.hasNext();) {\r
-                final CalendarEntry item = (CalendarEntry) it.next();\r
-                if (DateTimeService.isInRange(date, item.getStart(), item\r
-                        .getEnd(), resolution)) {\r
-                    res.add(item);\r
-                }\r
-            }\r
-\r
-            return res;\r
-        }\r
-\r
-        public void clear() {\r
-            dates.clear();\r
-        }\r
-\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java b/src/com/vaadin/demo/reservation/gwt/client/ui/IGoogleMap.java
deleted file mode 100644 (file)
index e69bcd1..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.demo.reservation.gwt.client.ui;\r
-\r
-import java.util.Iterator;\r
-\r
-import com.google.gwt.maps.client.InfoWindowContent;\r
-import com.google.gwt.maps.client.MapWidget;\r
-import com.google.gwt.maps.client.control.SmallMapControl;\r
-import com.google.gwt.maps.client.event.MarkerClickHandler;\r
-import com.google.gwt.maps.client.geom.LatLng;\r
-import com.google.gwt.maps.client.overlay.Marker;\r
-import com.google.gwt.user.client.ui.Composite;\r
-import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
-import com.vaadin.terminal.gwt.client.Paintable;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class IGoogleMap extends Composite implements Paintable {\r
-\r
-    public static final String CLASSNAME = "i-googlemap";\r
-\r
-    private final MapWidget widget = new MapWidget();\r
-\r
-    public IGoogleMap() {\r
-        initWidget(widget);\r
-        setWidth("200px");\r
-        setHeight("200px");\r
-        setStyleName(CLASSNAME);\r
-        widget.addControl(new SmallMapControl());\r
-\r
-    }\r
-\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        widget.clearOverlays();\r
-        LatLng pos = null;\r
-        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {\r
-            final UIDL u = (UIDL) it.next();\r
-            if (u.getTag().equals("markers")) {\r
-\r
-                for (final Iterator m = u.getChildIterator(); m.hasNext();) {\r
-                    final UIDL umarker = (UIDL) m.next();\r
-                    final String html = "<span>"\r
-                            + umarker.getStringAttribute("html") + "</span>";\r
-                    final double x = umarker.getDoubleAttribute("x");\r
-                    final double y = umarker.getDoubleAttribute("y");\r
-                    pos = LatLng.newInstance(x, y);\r
-                    final Marker marker = new Marker(pos);\r
-                    widget.addOverlay(marker);\r
-                    if (html != null) {\r
-                        addMarkerPopup(marker, html);\r
-                    }\r
-                }\r
-            }\r
-        }\r
-        if (uidl.hasAttribute("width")) {\r
-            widget.setWidth(uidl.getStringAttribute("width"));\r
-        }\r
-        if (uidl.hasAttribute("height")) {\r
-            widget.setHeight(uidl.getStringAttribute("height"));\r
-        }\r
-        if (uidl.hasAttribute("zoom")) {\r
-            widget.setZoomLevel(uidl.getIntAttribute("zoom"));\r
-        }\r
-        if (uidl.hasAttribute("centerX") && uidl.hasAttribute("centerY")) {\r
-            final LatLng center = LatLng.newInstance(uidl\r
-                    .getDoubleAttribute("centerX"), uidl\r
-                    .getDoubleAttribute("centerY"));\r
-            widget.setCenter(center);\r
-        } else if (pos != null) {\r
-            // use last marker position\r
-            widget.setCenter(pos);\r
-        }\r
-\r
-    }\r
-\r
-    private void addMarkerPopup(Marker marker, final String html) {\r
-        marker.addMarkerClickHandler(new MarkerClickHandler() {\r
-\r
-            public void onClick(MarkerClickEvent event) {\r
-                widget.getInfoWindow().open(event.getSender().getPoint(),\r
-                        new InfoWindowContent(html));\r
-\r
-            }\r
-\r
-        });\r
-\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ui/VCalendarField.java b/src/com/vaadin/demo/reservation/gwt/client/ui/VCalendarField.java
new file mode 100644 (file)
index 0000000..b4082f7
--- /dev/null
@@ -0,0 +1,294 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.demo.reservation.gwt.client.ui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import com.google.gwt.i18n.client.DateTimeFormat;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.Element;\r
+import com.google.gwt.user.client.ui.FlexTable;\r
+import com.google.gwt.user.client.ui.SimplePanel;\r
+import com.google.gwt.user.client.ui.SourcesTableEvents;\r
+import com.google.gwt.user.client.ui.TableListener;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.DateTimeService;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+import com.vaadin.terminal.gwt.client.ui.CalendarEntry;\r
+import com.vaadin.terminal.gwt.client.ui.VCalendarPanel;\r
+import com.vaadin.terminal.gwt.client.ui.VDateField;\r
+\r
+public class VCalendarField extends VDateField {\r
+\r
+    private final VCalendarPanel calPanel;\r
+\r
+    private SimplePanel hourPanel;\r
+\r
+    private FlexTable hourTable;\r
+\r
+    private final EntrySource entrySource;\r
+\r
+    private final TableListener ftListener = new HourTableListener();\r
+\r
+    private int realResolution = RESOLUTION_DAY;\r
+\r
+    private static final String CLASSNAME = VDateField.CLASSNAME\r
+            + "-entrycalendar";\r
+\r
+    public VCalendarField() {\r
+        super();\r
+        setStyleName(CLASSNAME);\r
+        calPanel = new VCalendarPanel(this);\r
+        add(calPanel);\r
+        entrySource = new EntrySource();\r
+        calPanel.setCalendarEntrySource(entrySource);\r
+        calPanel.addTableListener(new TableListener() {\r
+            public void onCellClicked(SourcesTableEvents sender, int row,\r
+                    int cell) {\r
+                buildDayView(date);\r
+            }\r
+        });\r
+    }\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        super.updateFromUIDL(uidl, client);\r
+        // We want to draw our own hour list\r
+        realResolution = currentResolution;\r
+        currentResolution = RESOLUTION_DAY;\r
+        if (uidl.hasAttribute("min")) {\r
+            final String mins = uidl.getStringAttribute("min");\r
+            final long min = (mins != null ? Long.parseLong(mins) : 0);\r
+            final String maxs = uidl.getStringAttribute("max");\r
+            final long max = (maxs != null ? Long.parseLong(maxs) : 0);\r
+            final Date minDate = (min > 0 ? new Date(min) : null);\r
+            final Date maxDate = (max > 0 ? new Date(max) : null);\r
+            calPanel.setLimits(minDate, maxDate);\r
+        }\r
+        entrySource.clear();\r
+        for (final Iterator cit = uidl.getChildIterator(); cit.hasNext();) {\r
+            final UIDL child = (UIDL) cit.next();\r
+            if (child.getTag().equals("items")) {\r
+                for (final Iterator iit = child.getChildIterator(); iit\r
+                        .hasNext();) {\r
+                    final UIDL item = (UIDL) iit.next();\r
+                    entrySource.addItem(item);\r
+                }\r
+                break;\r
+            }\r
+        }\r
+        calPanel.updateCalendar();\r
+        buildDayView(date);\r
+    }\r
+\r
+    protected void buildDayView(Date date) {\r
+        if (hourPanel == null) {\r
+            hourPanel = new SimplePanel();\r
+            hourPanel.setStyleName(CLASSNAME + "-hours");\r
+            calPanel.getFlexCellFormatter().setColSpan(8, 0, 7);\r
+            calPanel.setWidget(8, 0, hourPanel);\r
+        } else {\r
+            hourPanel.clear();\r
+        }\r
+        hourTable = new FlexTable();\r
+        hourTable.addTableListener(ftListener);\r
+        hourPanel.add(hourTable);\r
+        hourTable.setCellSpacing(1);\r
+\r
+        for (int i = 0; i < 24; i++) {\r
+            String style = (i % 2 == 0 ? "even" : "odd");\r
+            if (realResolution >= RESOLUTION_HOUR) {\r
+                if (this.date != null && this.date.getHours() == i) {\r
+                    style = "selected";\r
+                }\r
+            }\r
+            hourTable.getRowFormatter().setStyleName(i,\r
+                    CLASSNAME + "-row-" + style);\r
+            String hstr = (i < 10 ? "0" : "") + i + ":00";\r
+            if (dts.isTwelveHourClock()) {\r
+                final String ampm = (i < 12 ? "am" : "pm");\r
+                hstr = (i <= 12 ? i : i - 12) + ":00 " + ampm;\r
+            }\r
+            hourTable.setHTML(i, 0, "<span>" + hstr + "</span>");\r
+            hourTable.getCellFormatter()\r
+                    .setStyleName(i, 0, CLASSNAME + "-time");\r
+        }\r
+\r
+        final List entries = entrySource.getEntries(date,\r
+                DateTimeService.RESOLUTION_DAY);\r
+        int currentCol = 1;\r
+        for (final Iterator it = entries.iterator(); it.hasNext();) {\r
+            final CalendarEntry entry = (CalendarEntry) it.next();\r
+            int start = 0;\r
+            int hours = 24;\r
+            if (!entry.isNotime()) {\r
+                Date d = entry.getStart();\r
+                // TODO consider month&year as well\r
+                start = (d.getDate() < date.getDate() ? 0 : d.getHours());\r
+                d = entry.getEnd();\r
+                hours = (d.getDate() > date.getDate() ? 24 : d.getHours())\r
+                        - start;\r
+                if (hours < 1) {\r
+                    // We can't draw entries smaller than\r
+                    // one\r
+                    hours = 1;\r
+                }\r
+            }\r
+            int col = currentCol;\r
+            if (col > 1) {\r
+                while (!hourTable.isCellPresent(start, col - 1)) {\r
+                    col--;\r
+                }\r
+            }\r
+            hourTable.setHTML(start, col, "<span>"\r
+                    + (entry.getTitle() != null ? entry.getTitle() : "&nbsp")\r
+                    + "</span>");\r
+            hourTable.getFlexCellFormatter().setRowSpan(start, col, hours);\r
+            hourTable.getFlexCellFormatter().setStyleName(start, col,\r
+                    CLASSNAME + "-entry");\r
+            final String sn = entry.getStyleName();\r
+            if (sn != null && !sn.equals("")) {\r
+                hourTable.getFlexCellFormatter().addStyleName(start, col,\r
+                        CLASSNAME + "-" + entry.getStyleName());\r
+            }\r
+            final Element el = hourTable.getFlexCellFormatter().getElement(\r
+                    start, col);\r
+\r
+            String tooltip;\r
+            if (DateTimeService.isSameDay(entry.getStart(), entry.getEnd())) {\r
+                tooltip = (start < 10 ? "0" : "") + start + ":00";\r
+                if (dts.isTwelveHourClock()) {\r
+                    final String ampm = (start < 12 ? "am" : "pm");\r
+                    tooltip = (start <= 12 ? start : start - 12) + ":00 "\r
+                            + ampm;\r
+\r
+                }\r
+                tooltip += " (" + hours + "h) ";\r
+                if (entry.getTitle() != null) {\r
+                    tooltip += entry.getTitle() + "\n ";\r
+                }\r
+            } else {\r
+                tooltip = entry.getStringForDate(entry.getEnd()) + "\n ";\r
+            }\r
+            if (entry.getDescription() != null) {\r
+                tooltip += "\"" + entry.getDescription() + "\"";\r
+            }\r
+            DOM.setElementProperty(el, "title", tooltip);\r
+\r
+            currentCol++;\r
+        }\r
+\r
+        // int hour = new Date().getHours()+1; // scroll to current hour\r
+        Date d = (this.date != null ? this.date : new Date());\r
+        final int hour = d.getHours() + 1; // scroll to selected\r
+        // hour\r
+        final int h1 = hourPanel.getOffsetHeight() / 2;\r
+        final int oh = hourTable.getOffsetHeight();\r
+        final int h2 = (int) (hour / 24.0 * oh);\r
+        final int scrollTop = h2 - h1;\r
+        final Element el = hourPanel.getElement();\r
+        setScrollTop(el, scrollTop);\r
+\r
+    }\r
+\r
+    private native void setScrollTop(Element el, int scrollTop)\r
+    /*-{\r
+         el.scrollTop = scrollTop;\r
+    }-*/;\r
+\r
+    private class HourTableListener implements TableListener {\r
+\r
+        public void onCellClicked(SourcesTableEvents sender, int row, int cell) {\r
+            if (realResolution < RESOLUTION_HOUR || date == null) {\r
+                return;\r
+            }\r
+            date.setHours(row);\r
+            client.updateVariable(id, "hour", row, immediate);\r
+        }\r
+\r
+    }\r
+\r
+    private class EntrySource implements VCalendarPanel.CalendarEntrySource {\r
+\r
+        private final HashMap dates = new HashMap();\r
+\r
+        public void addItem(UIDL item) {\r
+            final String styleName = item.getStringAttribute("styleName");\r
+            // final Integer id = new Integer(item.getIntAttribute("id"));\r
+\r
+            DateTimeFormat dtf = DateTimeFormat\r
+                    .getFormat("d MM yyyy HH:mm:ss Z");\r
+\r
+            Date startDate = dtf.parse(item.getStringAttribute("start"));\r
+\r
+            // fix times with server-client difference\r
+            int diff = (startDate.getTimezoneOffset() - item\r
+                    .getIntAttribute("Z")) * 60000;\r
+            startDate = new Date(startDate.getTime() + diff);\r
+            Date endDate;\r
+            if (item.hasAttribute("end")) {\r
+                endDate = dtf.parse(item.getStringAttribute("end"));\r
+                endDate = new Date(endDate.getTime() + diff);\r
+            } else {\r
+                endDate = (Date) startDate.clone();\r
+            }\r
+            final String title = item.getStringAttribute("title");\r
+            final String desc = item.getStringAttribute("description");\r
+            final boolean notime = item.getBooleanAttribute("notime");\r
+            final CalendarEntry entry = new CalendarEntry(styleName, startDate,\r
+                    endDate, title, desc, notime);\r
+\r
+            // TODO should remove+readd if the same entry (id) is\r
+            // added again\r
+\r
+            for (final Date d = new Date(entry.getStart().getTime()); d\r
+                    .getYear() <= entry.getEnd().getYear()\r
+                    && d.getMonth() <= entry.getEnd().getYear()\r
+                    && d.getDate() <= entry.getEnd().getDate(); d.setTime(d\r
+                    .getTime() + 86400000)) {\r
+                final String key = d.getYear() + "" + d.getMonth() + ""\r
+                        + d.getDate();\r
+                ArrayList l = (ArrayList) dates.get(key);\r
+                if (l == null) {\r
+                    l = new ArrayList();\r
+                    dates.put(key, l);\r
+                }\r
+                l.add(entry);\r
+            }\r
+        }\r
+\r
+        public List getEntries(Date date, int resolution) {\r
+            final ArrayList res = new ArrayList();\r
+            if (date == null) {\r
+                return res;\r
+            }\r
+            final List entries = (List) dates.get(date.getYear() + ""\r
+                    + date.getMonth() + "" + date.getDate());\r
+\r
+            if (entries == null) {\r
+                return res;\r
+            }\r
+            for (final Iterator it = entries.iterator(); it.hasNext();) {\r
+                final CalendarEntry item = (CalendarEntry) it.next();\r
+                if (DateTimeService.isInRange(date, item.getStart(), item\r
+                        .getEnd(), resolution)) {\r
+                    res.add(item);\r
+                }\r
+            }\r
+\r
+            return res;\r
+        }\r
+\r
+        public void clear() {\r
+            dates.clear();\r
+        }\r
+\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/demo/reservation/gwt/client/ui/VGoogleMap.java b/src/com/vaadin/demo/reservation/gwt/client/ui/VGoogleMap.java
new file mode 100644 (file)
index 0000000..b2c8c1b
--- /dev/null
@@ -0,0 +1,91 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.demo.reservation.gwt.client.ui;\r
+\r
+import java.util.Iterator;\r
+\r
+import com.google.gwt.maps.client.InfoWindowContent;\r
+import com.google.gwt.maps.client.MapWidget;\r
+import com.google.gwt.maps.client.control.SmallMapControl;\r
+import com.google.gwt.maps.client.event.MarkerClickHandler;\r
+import com.google.gwt.maps.client.geom.LatLng;\r
+import com.google.gwt.maps.client.overlay.Marker;\r
+import com.google.gwt.user.client.ui.Composite;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.Paintable;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VGoogleMap extends Composite implements Paintable {\r
+\r
+    public static final String CLASSNAME = "i-googlemap";\r
+\r
+    private final MapWidget widget = new MapWidget();\r
+\r
+    public VGoogleMap() {\r
+        initWidget(widget);\r
+        setWidth("200px");\r
+        setHeight("200px");\r
+        setStyleName(CLASSNAME);\r
+        widget.addControl(new SmallMapControl());\r
+\r
+    }\r
+\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        widget.clearOverlays();\r
+        LatLng pos = null;\r
+        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {\r
+            final UIDL u = (UIDL) it.next();\r
+            if (u.getTag().equals("markers")) {\r
+\r
+                for (final Iterator m = u.getChildIterator(); m.hasNext();) {\r
+                    final UIDL umarker = (UIDL) m.next();\r
+                    final String html = "<span>"\r
+                            + umarker.getStringAttribute("html") + "</span>";\r
+                    final double x = umarker.getDoubleAttribute("x");\r
+                    final double y = umarker.getDoubleAttribute("y");\r
+                    pos = LatLng.newInstance(x, y);\r
+                    final Marker marker = new Marker(pos);\r
+                    widget.addOverlay(marker);\r
+                    if (html != null) {\r
+                        addMarkerPopup(marker, html);\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        if (uidl.hasAttribute("width")) {\r
+            widget.setWidth(uidl.getStringAttribute("width"));\r
+        }\r
+        if (uidl.hasAttribute("height")) {\r
+            widget.setHeight(uidl.getStringAttribute("height"));\r
+        }\r
+        if (uidl.hasAttribute("zoom")) {\r
+            widget.setZoomLevel(uidl.getIntAttribute("zoom"));\r
+        }\r
+        if (uidl.hasAttribute("centerX") && uidl.hasAttribute("centerY")) {\r
+            final LatLng center = LatLng.newInstance(uidl\r
+                    .getDoubleAttribute("centerX"), uidl\r
+                    .getDoubleAttribute("centerY"));\r
+            widget.setCenter(center);\r
+        } else if (pos != null) {\r
+            // use last marker position\r
+            widget.setCenter(pos);\r
+        }\r
+\r
+    }\r
+\r
+    private void addMarkerPopup(Marker marker, final String html) {\r
+        marker.addMarkerClickHandler(new MarkerClickHandler() {\r
+\r
+            public void onClick(MarkerClickEvent event) {\r
+                widget.getInfoWindow().open(event.getSender().getPoint(),\r
+                        new InfoWindowContent(html));\r
+\r
+            }\r
+\r
+        });\r
+\r
+    }\r
+\r
+}\r
index 2738b21990f9bd4d6863ea4ac670e2d9f894eb3b..24dde94a3ccf45d18b25af1024104b52883836ec 100644 (file)
@@ -1,8 +1,8 @@
 package com.vaadin.demo.sampler.gwt.client;
 
-import com.vaadin.demo.sampler.gwt.client.ui.IActiveLink;
-import com.vaadin.demo.sampler.gwt.client.ui.ICodeLabel;
-import com.vaadin.demo.sampler.gwt.client.ui.IGoogleAnalytics;
+import com.vaadin.demo.sampler.gwt.client.ui.VActiveLink;
+import com.vaadin.demo.sampler.gwt.client.ui.VCodeLabel;
+import com.vaadin.demo.sampler.gwt.client.ui.VGoogleAnalytics;
 import com.vaadin.terminal.gwt.client.DefaultWidgetSet;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
@@ -12,12 +12,12 @@ public class SamplerWidgetSet extends DefaultWidgetSet {
     @Override
     public Paintable createWidget(UIDL uidl) {
         final Class classType = resolveWidgetType(uidl);
-        if (IGoogleAnalytics.class == classType) {
-            return new IGoogleAnalytics();
-        } else if (ICodeLabel.class == classType) {
-            return new ICodeLabel();
-        } else if (IActiveLink.class == classType) {
-            return new IActiveLink();
+        if (VGoogleAnalytics.class == classType) {
+            return new VGoogleAnalytics();
+        } else if (VCodeLabel.class == classType) {
+            return new VCodeLabel();
+        } else if (VActiveLink.class == classType) {
+            return new VActiveLink();
         } else {
             return super.createWidget(uidl);
         }
@@ -27,11 +27,11 @@ public class SamplerWidgetSet extends DefaultWidgetSet {
     protected Class resolveWidgetType(UIDL uidl) {
         final String tag = uidl.getTag();
         if ("googleanalytics".equals(tag)) {
-            return IGoogleAnalytics.class;
+            return VGoogleAnalytics.class;
         } else if ("codelabel".equals(tag)) {
-            return ICodeLabel.class;
+            return VCodeLabel.class;
         } else if ("activelink".equals(tag)) {
-            return IActiveLink.class;
+            return VActiveLink.class;
         } else {
             return super.resolveWidgetType(uidl);
         }
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java b/src/com/vaadin/demo/sampler/gwt/client/ui/IActiveLink.java
deleted file mode 100644 (file)
index d539ef5..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-package com.vaadin.demo.sampler.gwt.client.ui;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.MouseListener;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.ui.ILink;
-
-public class IActiveLink extends ILink {
-
-    String id;
-    ApplicationConnection client;
-    boolean listening = false;
-
-    public IActiveLink() {
-        addMouseListener(new MouseListener() {
-            public void onMouseDown(Widget sender, int x, int y) {
-            }
-
-            public void onMouseEnter(Widget sender) {
-            }
-
-            public void onMouseLeave(Widget sender) {
-            }
-
-            public void onMouseMove(Widget sender, int x, int y) {
-            }
-
-            public void onMouseUp(Widget sender, int x, int y) {
-                Event e = DOM.eventGetCurrentEvent();
-                if (e.getButton() == Event.BUTTON_MIDDLE) {
-                    sendVariables();
-                }
-            }
-        });
-    }
-
-    /**
-     * Sends variables, returns true if default handler should be called (i.e if
-     * server is listening and the link was claimed to be opened by the client)
-     * 
-     * @return
-     */
-    private boolean sendVariables() {
-        Event e = DOM.eventGetCurrentEvent();
-        boolean opened = (e.getCtrlKey() || e.getAltKey() || e.getShiftKey()
-                || e.getMetaKey() || e.getButton() == Event.BUTTON_MIDDLE);
-
-        // Works as ILink if no-one is listening
-        if (listening) {
-            if (opened) {
-                // ILink will open, notify server
-                client.updateVariable(id, "opened", true, false);
-            } else {
-                e.preventDefault();
-            }
-            client.updateVariable(id, "activated", true, true);
-        }
-        return !listening || opened;
-    }
-
-    @Override
-    public void onClick(Widget sender) {
-
-        if (sendVariables()) {
-            // run default if not listening, or we claimed link was opened
-            super.onClick(sender);
-        }
-    }
-
-    @Override
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // Ensure correct implementation,
-        // but don't let container manage caption etc.
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-
-        // Save details
-        this.client = client;
-        id = uidl.getId();
-        listening = uidl.hasVariable("activated");
-
-        super.updateFromUIDL(uidl, client);
-    }
-
-}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java b/src/com/vaadin/demo/sampler/gwt/client/ui/ICodeLabel.java
deleted file mode 100644 (file)
index a97d74e..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-package com.vaadin.demo.sampler.gwt.client.ui;
-
-import com.google.gwt.dom.client.Element;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.ui.ILabel;
-
-public class ICodeLabel extends ILabel {
-
-    public ICodeLabel() {
-        super();
-    }
-
-    @Override
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        super.updateFromUIDL(uidl, client);
-        Element pre = getElement().getFirstChildElement();
-        if (null != pre) {
-            pre.setClassName("prettyprint");
-            prettyPrint();
-        }
-    }
-
-    private native void prettyPrint()
-    /*-{
-         $wnd.prettyPrint();
-     }-*/;
-
-}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java b/src/com/vaadin/demo/sampler/gwt/client/ui/IGoogleAnalytics.java
deleted file mode 100644 (file)
index 13e15fb..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.vaadin.demo.sampler.gwt.client.ui;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IGoogleAnalytics extends Widget implements Paintable {
-
-    public IGoogleAnalytics() {
-        setElement(Document.get().createDivElement());
-        if (BrowserInfo.get().isIE6()) {
-            getElement().getStyle().setProperty("overflow", "hidden");
-            getElement().getStyle().setProperty("height", "0");
-            getElement().getStyle().setProperty("width", "0");
-        }
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (isLocalHostUrl()) {
-            // Do not track localhost page views
-            return;
-        }
-        String trackerId = uidl.getStringAttribute("trackerid");
-        String pageId = uidl.getStringAttribute("pageid");
-        String domainName = uidl.getStringAttribute("domain");
-
-        String res = trackPageview(trackerId, pageId, domainName);
-        if (null != res) {
-            ApplicationConnection.getConsole().log(
-                    "WebAnalytics.trackPageview(" + trackerId + "," + pageId
-                            + "," + domainName + ") FAILED: " + res);
-        } else {
-            ApplicationConnection.getConsole().log(
-                    "WebAnalytics.trackPageview(" + trackerId + "," + pageId
-                            + "," + domainName + ") SUCCESS.");
-        }
-    }
-
-    private native boolean isLocalHostUrl()
-    /*-{
-        var location = $wnd.location;
-        var re = /^http:\/\/(localhost|127.0.0.1)/;
-        return re.test(location);
-    }-*/;
-
-    private native String trackPageview(String trackerId, String pageId,
-            String domainName)
-    /*-{
-        if (!$wnd._gat) {
-            return "Tracker not found (running offline?)";
-        }
-        try {
-            var pageTracker = $wnd._gat._getTracker(trackerId);
-            if (domainName) {
-                pageTracker._setDomainName(domainName);
-            }
-            if (pageId) {
-                pageTracker._trackPageview(pageId);
-            } else {
-                pageTracker._trackPageview();
-            }
-            return null;
-        } catch(err) {
-            return ""+err;
-        }
-    }-*/;
-}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/VActiveLink.java b/src/com/vaadin/demo/sampler/gwt/client/ui/VActiveLink.java
new file mode 100644 (file)
index 0000000..a95db45
--- /dev/null
@@ -0,0 +1,89 @@
+package com.vaadin.demo.sampler.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.MouseListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VLink;
+
+public class VActiveLink extends VLink {
+
+    String id;
+    ApplicationConnection client;
+    boolean listening = false;
+
+    public VActiveLink() {
+        addMouseListener(new MouseListener() {
+            public void onMouseDown(Widget sender, int x, int y) {
+            }
+
+            public void onMouseEnter(Widget sender) {
+            }
+
+            public void onMouseLeave(Widget sender) {
+            }
+
+            public void onMouseMove(Widget sender, int x, int y) {
+            }
+
+            public void onMouseUp(Widget sender, int x, int y) {
+                Event e = DOM.eventGetCurrentEvent();
+                if (e.getButton() == Event.BUTTON_MIDDLE) {
+                    sendVariables();
+                }
+            }
+        });
+    }
+
+    /**
+     * Sends variables, returns true if default handler should be called (i.e if
+     * server is listening and the link was claimed to be opened by the client)
+     * 
+     * @return
+     */
+    private boolean sendVariables() {
+        Event e = DOM.eventGetCurrentEvent();
+        boolean opened = (e.getCtrlKey() || e.getAltKey() || e.getShiftKey()
+                || e.getMetaKey() || e.getButton() == Event.BUTTON_MIDDLE);
+
+        // Works as VLink if no-one is listening
+        if (listening) {
+            if (opened) {
+                // VLink will open, notify server
+                client.updateVariable(id, "opened", true, false);
+            } else {
+                e.preventDefault();
+            }
+            client.updateVariable(id, "activated", true, true);
+        }
+        return !listening || opened;
+    }
+
+    @Override
+    public void onClick(Widget sender) {
+
+        if (sendVariables()) {
+            // run default if not listening, or we claimed link was opened
+            super.onClick(sender);
+        }
+    }
+
+    @Override
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // Ensure correct implementation,
+        // but don't let container manage caption etc.
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        // Save details
+        this.client = client;
+        id = uidl.getId();
+        listening = uidl.hasVariable("activated");
+
+        super.updateFromUIDL(uidl, client);
+    }
+
+}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/VCodeLabel.java b/src/com/vaadin/demo/sampler/gwt/client/ui/VCodeLabel.java
new file mode 100644 (file)
index 0000000..e4ba51d
--- /dev/null
@@ -0,0 +1,29 @@
+package com.vaadin.demo.sampler.gwt.client.ui;
+
+import com.google.gwt.dom.client.Element;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.ui.VLabel;
+
+public class VCodeLabel extends VLabel {
+
+    public VCodeLabel() {
+        super();
+    }
+
+    @Override
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        super.updateFromUIDL(uidl, client);
+        Element pre = getElement().getFirstChildElement();
+        if (null != pre) {
+            pre.setClassName("prettyprint");
+            prettyPrint();
+        }
+    }
+
+    private native void prettyPrint()
+    /*-{
+         $wnd.prettyPrint();
+     }-*/;
+
+}
diff --git a/src/com/vaadin/demo/sampler/gwt/client/ui/VGoogleAnalytics.java b/src/com/vaadin/demo/sampler/gwt/client/ui/VGoogleAnalytics.java
new file mode 100644 (file)
index 0000000..263a8af
--- /dev/null
@@ -0,0 +1,70 @@
+package com.vaadin.demo.sampler.gwt.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VGoogleAnalytics extends Widget implements Paintable {
+
+    public VGoogleAnalytics() {
+        setElement(Document.get().createDivElement());
+        if (BrowserInfo.get().isIE6()) {
+            getElement().getStyle().setProperty("overflow", "hidden");
+            getElement().getStyle().setProperty("height", "0");
+            getElement().getStyle().setProperty("width", "0");
+        }
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (isLocalHostUrl()) {
+            // Do not track localhost page views
+            return;
+        }
+        String trackerId = uidl.getStringAttribute("trackerid");
+        String pageId = uidl.getStringAttribute("pageid");
+        String domainName = uidl.getStringAttribute("domain");
+
+        String res = trackPageview(trackerId, pageId, domainName);
+        if (null != res) {
+            ApplicationConnection.getConsole().log(
+                    "WebAnalytics.trackPageview(" + trackerId + "," + pageId
+                            + "," + domainName + ") FAILED: " + res);
+        } else {
+            ApplicationConnection.getConsole().log(
+                    "WebAnalytics.trackPageview(" + trackerId + "," + pageId
+                            + "," + domainName + ") SUCCESS.");
+        }
+    }
+
+    private native boolean isLocalHostUrl()
+    /*-{
+        var location = $wnd.location;
+        var re = /^http:\/\/(localhost|127.0.0.1)/;
+        return re.test(location);
+    }-*/;
+
+    private native String trackPageview(String trackerId, String pageId,
+            String domainName)
+    /*-{
+        if (!$wnd._gat) {
+            return "Tracker not found (running offline?)";
+        }
+        try {
+            var pageTracker = $wnd._gat._getTracker(trackerId);
+            if (domainName) {
+                pageTracker._setDomainName(domainName);
+            }
+            if (pageId) {
+                pageTracker._trackPageview(pageId);
+            } else {
+                pageTracker._trackPageview();
+            }
+            return null;
+        } catch(err) {
+            return ""+err;
+        }
+    }-*/;
+}
index e4bb48c9ba5ade341117d4fb305aa7ef6b844b87..7324b12613a75a35c21f95782319c6c2cdbfa535 100755 (executable)
@@ -38,10 +38,10 @@ import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
 import com.vaadin.terminal.gwt.client.RenderInformation.Size;
 import com.vaadin.terminal.gwt.client.ui.Field;
-import com.vaadin.terminal.gwt.client.ui.IContextMenu;
-import com.vaadin.terminal.gwt.client.ui.INotification;
-import com.vaadin.terminal.gwt.client.ui.IView;
-import com.vaadin.terminal.gwt.client.ui.INotification.HideEvent;
+import com.vaadin.terminal.gwt.client.ui.VContextMenu;
+import com.vaadin.terminal.gwt.client.ui.VNotification;
+import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.terminal.gwt.client.ui.VNotification.HideEvent;
 
 /**
  * Entry point classes define <code>onModuleLoad()</code>.
@@ -78,14 +78,14 @@ public class ApplicationConnection {
 
     private final WidgetSet widgetSet;
 
-    private IContextMenu contextMenu = null;
+    private VContextMenu contextMenu = null;
 
     private Timer loadTimer;
     private Timer loadTimer2;
     private Timer loadTimer3;
     private Element loadElement;
 
-    private final IView view;
+    private final VView view;
 
     private boolean applicationRunning = false;
 
@@ -120,7 +120,7 @@ public class ApplicationConnection {
         configuration = cnf;
         windowName = configuration.getInitialWindowName();
         if (isDebugMode()) {
-            console = new IDebugConsole(this, cnf, !isQuietDebugMode());
+            console = new VDebugConsole(this, cnf, !isQuietDebugMode());
         } else {
             console = new NullConsole();
         }
@@ -135,7 +135,7 @@ public class ApplicationConnection {
 
         initializeClientHooks();
 
-        view = new IView(cnf.getRootPanelId());
+        view = new VView(cnf.getRootPanelId());
         showLoadingIndicator();
 
     }
@@ -386,12 +386,12 @@ public class ApplicationConnection {
                     + "</p>";
         }
         if (html.length() > 0) {
-            INotification n = new INotification(1000 * 60 * 45);
+            VNotification n = new VNotification(1000 * 60 * 45);
             n.addEventListener(new NotificationRedirect(configuration
                     .getCommunicationErrorUrl()));
             n
-                    .show(html, INotification.CENTERED_TOP,
-                            INotification.STYLE_SYSTEM);
+                    .show(html, VNotification.CENTERED_TOP,
+                            VNotification.STYLE_SYSTEM);
         } else {
             redirect(configuration.getCommunicationErrorUrl());
         }
@@ -694,10 +694,10 @@ public class ApplicationConnection {
 
                 if (html.length() != 0) {
                     /* 45 min */
-                    INotification n = new INotification(1000 * 60 * 45);
+                    VNotification n = new VNotification(1000 * 60 * 45);
                     n.addEventListener(new NotificationRedirect(url));
-                    n.show(html, INotification.CENTERED_TOP,
-                            INotification.STYLE_SYSTEM);
+                    n.show(html, VNotification.CENTERED_TOP,
+                            VNotification.STYLE_SYSTEM);
                 } else {
                     redirect(url);
                 }
@@ -1461,11 +1461,11 @@ public class ApplicationConnection {
     /**
      * Singleton method to get instance of app's context menu.
      * 
-     * @return IContextMenu object
+     * @return VContextMenu object
      */
-    public IContextMenu getContextMenu() {
+    public VContextMenu getContextMenu() {
         if (contextMenu == null) {
-            contextMenu = new IContextMenu();
+            contextMenu = new VContextMenu();
             DOM.setElementProperty(contextMenu.getElement(), "id",
                     "PID_TOOLKIT_CM");
         }
@@ -1506,7 +1506,7 @@ public class ApplicationConnection {
      * messages, such as session expired.
      * 
      */
-    private class NotificationRedirect implements INotification.EventListener {
+    private class NotificationRedirect implements VNotification.EventListener {
         String url;
 
         NotificationRedirect(String url) {
@@ -1540,7 +1540,7 @@ public class ApplicationConnection {
         }
     }
 
-    private final ITooltip tooltip = new ITooltip(this);
+    private final VTooltip tooltip = new VTooltip(this);
 
     /**
      * Component may want to delegate Tooltip handling to client. Layouts add
@@ -1626,7 +1626,7 @@ public class ApplicationConnection {
         makeUidlRequest("", true, false, true);
     }
 
-    public IView getView() {
+    public VView getView() {
         return view;
     }
 
index ccd00228762ca8571510cbc02497a6592f882cd1..82ec1a4735832c89c12edc3e98740599411c274b 100644 (file)
@@ -7,8 +7,8 @@ import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.ui.HasWidgets;
 import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ui.IView;
-import com.vaadin.terminal.gwt.client.ui.IWindow;
+import com.vaadin.terminal.gwt.client.ui.VView;
+import com.vaadin.terminal.gwt.client.ui.VWindow;
 import com.vaadin.terminal.gwt.client.ui.SubPartAware;
 
 /**
@@ -71,8 +71,8 @@ public class ComponentLocator {
             String subPartName = client.getContextMenu().getSubPartName(
                     targetElement);
             if (subPartName != null) {
-                // IContextMenu, singleton attached directly to rootpanel
-                return "/IContextMenu[0]" + SUBPART_SEPARATOR + subPartName;
+                // VContextMenu, singleton attached directly to rootpanel
+                return "/VContextMenu[0]" + SUBPART_SEPARATOR + subPartName;
 
             }
             return null;
@@ -226,14 +226,14 @@ public class ComponentLocator {
             return pid;
         }
 
-        if (w instanceof IView) {
+        if (w instanceof VView) {
             return "";
-        } else if (w instanceof IWindow) {
-            IWindow win = (IWindow) w;
-            ArrayList<IWindow> subWindowList = client.getView()
+        } else if (w instanceof VWindow) {
+            VWindow win = (VWindow) w;
+            ArrayList<VWindow> subWindowList = client.getView()
                     .getSubWindowList();
             int indexOfSubWindow = subWindowList.indexOf(win);
-            return PARENTCHILD_SEPARATOR + "IWindow[" + indexOfSubWindow + "]";
+            return PARENTCHILD_SEPARATOR + "VWindow[" + indexOfSubWindow + "]";
         }
 
         Widget parent = w.getParent();
@@ -283,9 +283,9 @@ public class ComponentLocator {
 
                 Iterator<? extends Widget> i;
                 String widgetClassName = split[0];
-                if (widgetClassName.equals("IWindow")) {
+                if (widgetClassName.equals("VWindow")) {
                     i = client.getView().getSubWindowList().iterator();
-                } else if (widgetClassName.equals("IContextMenu")) {
+                } else if (widgetClassName.equals("VContextMenu")) {
                     return client.getContextMenu();
                 } else {
                     i = parent.iterator();
index 104ca1d2325b4bf296d84451c262225e8534fbb5..9ac2337004197d1271e1dcb4f5a64c74440c9686 100644 (file)
@@ -5,48 +5,48 @@
 package com.vaadin.terminal.gwt.client;
 
 import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ui.IAbsoluteLayout;
-import com.vaadin.terminal.gwt.client.ui.IAccordion;
-import com.vaadin.terminal.gwt.client.ui.IButton;
-import com.vaadin.terminal.gwt.client.ui.ICheckBox;
-import com.vaadin.terminal.gwt.client.ui.ICustomComponent;
-import com.vaadin.terminal.gwt.client.ui.ICustomLayout;
-import com.vaadin.terminal.gwt.client.ui.IDateFieldCalendar;
-import com.vaadin.terminal.gwt.client.ui.IEmbedded;
-import com.vaadin.terminal.gwt.client.ui.IFilterSelect;
-import com.vaadin.terminal.gwt.client.ui.IForm;
-import com.vaadin.terminal.gwt.client.ui.IFormLayout;
-import com.vaadin.terminal.gwt.client.ui.IGridLayout;
-import com.vaadin.terminal.gwt.client.ui.IHorizontalLayout;
-import com.vaadin.terminal.gwt.client.ui.ILabel;
-import com.vaadin.terminal.gwt.client.ui.ILink;
-import com.vaadin.terminal.gwt.client.ui.IListSelect;
-import com.vaadin.terminal.gwt.client.ui.IMenuBar;
-import com.vaadin.terminal.gwt.client.ui.INativeSelect;
-import com.vaadin.terminal.gwt.client.ui.IOptionGroup;
-import com.vaadin.terminal.gwt.client.ui.IOrderedLayout;
-import com.vaadin.terminal.gwt.client.ui.IPanel;
-import com.vaadin.terminal.gwt.client.ui.IPasswordField;
-import com.vaadin.terminal.gwt.client.ui.IPopupCalendar;
-import com.vaadin.terminal.gwt.client.ui.IPopupView;
-import com.vaadin.terminal.gwt.client.ui.IProgressIndicator;
-import com.vaadin.terminal.gwt.client.ui.IScrollTable;
-import com.vaadin.terminal.gwt.client.ui.ISlider;
-import com.vaadin.terminal.gwt.client.ui.ISplitPanelHorizontal;
-import com.vaadin.terminal.gwt.client.ui.ISplitPanelVertical;
-import com.vaadin.terminal.gwt.client.ui.ITablePaging;
-import com.vaadin.terminal.gwt.client.ui.ITabsheet;
-import com.vaadin.terminal.gwt.client.ui.ITextArea;
-import com.vaadin.terminal.gwt.client.ui.ITextField;
-import com.vaadin.terminal.gwt.client.ui.ITextualDate;
-import com.vaadin.terminal.gwt.client.ui.ITree;
-import com.vaadin.terminal.gwt.client.ui.ITwinColSelect;
-import com.vaadin.terminal.gwt.client.ui.IUnknownComponent;
-import com.vaadin.terminal.gwt.client.ui.IUpload;
-import com.vaadin.terminal.gwt.client.ui.IUriFragmentUtility;
-import com.vaadin.terminal.gwt.client.ui.IVerticalLayout;
-import com.vaadin.terminal.gwt.client.ui.IWindow;
-import com.vaadin.terminal.gwt.client.ui.richtextarea.IRichTextArea;
+import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout;
+import com.vaadin.terminal.gwt.client.ui.VAccordion;
+import com.vaadin.terminal.gwt.client.ui.VButton;
+import com.vaadin.terminal.gwt.client.ui.VCheckBox;
+import com.vaadin.terminal.gwt.client.ui.VCustomComponent;
+import com.vaadin.terminal.gwt.client.ui.VCustomLayout;
+import com.vaadin.terminal.gwt.client.ui.VDateFieldCalendar;
+import com.vaadin.terminal.gwt.client.ui.VEmbedded;
+import com.vaadin.terminal.gwt.client.ui.VFilterSelect;
+import com.vaadin.terminal.gwt.client.ui.VForm;
+import com.vaadin.terminal.gwt.client.ui.VFormLayout;
+import com.vaadin.terminal.gwt.client.ui.VGridLayout;
+import com.vaadin.terminal.gwt.client.ui.VHorizontalLayout;
+import com.vaadin.terminal.gwt.client.ui.VLabel;
+import com.vaadin.terminal.gwt.client.ui.VLink;
+import com.vaadin.terminal.gwt.client.ui.VListSelect;
+import com.vaadin.terminal.gwt.client.ui.VMenuBar;
+import com.vaadin.terminal.gwt.client.ui.VNativeSelect;
+import com.vaadin.terminal.gwt.client.ui.VOptionGroup;
+import com.vaadin.terminal.gwt.client.ui.VOrderedLayout;
+import com.vaadin.terminal.gwt.client.ui.VPanel;
+import com.vaadin.terminal.gwt.client.ui.VPasswordField;
+import com.vaadin.terminal.gwt.client.ui.VPopupCalendar;
+import com.vaadin.terminal.gwt.client.ui.VPopupView;
+import com.vaadin.terminal.gwt.client.ui.VProgressIndicator;
+import com.vaadin.terminal.gwt.client.ui.VScrollTable;
+import com.vaadin.terminal.gwt.client.ui.VSlider;
+import com.vaadin.terminal.gwt.client.ui.VSplitPanelHorizontal;
+import com.vaadin.terminal.gwt.client.ui.VSplitPanelVertical;
+import com.vaadin.terminal.gwt.client.ui.VTablePaging;
+import com.vaadin.terminal.gwt.client.ui.VTabsheet;
+import com.vaadin.terminal.gwt.client.ui.VTextArea;
+import com.vaadin.terminal.gwt.client.ui.VTextField;
+import com.vaadin.terminal.gwt.client.ui.VTextualDate;
+import com.vaadin.terminal.gwt.client.ui.VTree;
+import com.vaadin.terminal.gwt.client.ui.VTwinColSelect;
+import com.vaadin.terminal.gwt.client.ui.VUnknownComponent;
+import com.vaadin.terminal.gwt.client.ui.VUpload;
+import com.vaadin.terminal.gwt.client.ui.VUriFragmentUtility;
+import com.vaadin.terminal.gwt.client.ui.VVerticalLayout;
+import com.vaadin.terminal.gwt.client.ui.VWindow;
+import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea;
 
 public class DefaultWidgetSet implements WidgetSet {
 
@@ -60,91 +60,91 @@ public class DefaultWidgetSet implements WidgetSet {
 
     public Paintable createWidget(UIDL uidl) {
         final Class classType = resolveWidgetType(uidl);
-        if (ICheckBox.class == classType) {
-            return new ICheckBox();
-        } else if (IButton.class == classType) {
-            return new IButton();
-        } else if (IWindow.class == classType) {
-            return new IWindow();
-        } else if (IOrderedLayout.class == classType) {
-            return new IOrderedLayout();
-        } else if (IVerticalLayout.class == classType) {
-            return new IVerticalLayout();
-        } else if (IHorizontalLayout.class == classType) {
-            return new IHorizontalLayout();
-        } else if (ILabel.class == classType) {
-            return new ILabel();
-        } else if (ILink.class == classType) {
-            return new ILink();
-        } else if (IGridLayout.class == classType) {
-            return new IGridLayout();
-        } else if (ITree.class == classType) {
-            return new ITree();
-        } else if (IOptionGroup.class == classType) {
-            return new IOptionGroup();
-        } else if (ITwinColSelect.class == classType) {
-            return new ITwinColSelect();
-        } else if (INativeSelect.class == classType) {
-            return new INativeSelect();
-        } else if (IListSelect.class == classType) {
-            return new IListSelect();
-        } else if (IPanel.class == classType) {
-            return new IPanel();
-        } else if (ITabsheet.class == classType) {
-            return new ITabsheet();
-        } else if (IEmbedded.class == classType) {
-            return new IEmbedded();
-        } else if (ICustomLayout.class == classType) {
-            return new ICustomLayout();
-        } else if (ICustomComponent.class == classType) {
-            return new ICustomComponent();
-        } else if (ITextArea.class == classType) {
-            return new ITextArea();
-        } else if (IPasswordField.class == classType) {
-            return new IPasswordField();
-        } else if (ITextField.class == classType) {
-            return new ITextField();
-        } else if (ITablePaging.class == classType) {
-            return new ITablePaging();
-        } else if (IScrollTable.class == classType) {
-            return new IScrollTable();
-        } else if (IDateFieldCalendar.class == classType) {
-            return new IDateFieldCalendar();
-        } else if (ITextualDate.class == classType) {
-            return new ITextualDate();
-        } else if (IPopupCalendar.class == classType) {
-            return new IPopupCalendar();
-        } else if (ISlider.class == classType) {
-            return new ISlider();
-        } else if (IForm.class == classType) {
-            return new IForm();
-        } else if (IFormLayout.class == classType) {
-            return new IFormLayout();
-        } else if (IUpload.class == classType) {
-            return new IUpload();
-        } else if (ISplitPanelHorizontal.class == classType) {
-            return new ISplitPanelHorizontal();
-        } else if (ISplitPanelVertical.class == classType) {
-            return new ISplitPanelVertical();
-        } else if (IFilterSelect.class == classType) {
-            return new IFilterSelect();
-        } else if (IProgressIndicator.class == classType) {
-            return new IProgressIndicator();
-        } else if (IRichTextArea.class == classType) {
-            return new IRichTextArea();
-        } else if (IAccordion.class == classType) {
-            return new IAccordion();
-        } else if (IMenuBar.class == classType) {
-            return new IMenuBar();
-        } else if (IPopupView.class == classType) {
-            return new IPopupView();
-        } else if (IUriFragmentUtility.class == classType) {
-            return new IUriFragmentUtility();
-        } else if (IAbsoluteLayout.class == classType) {
-            return new IAbsoluteLayout();
+        if (VCheckBox.class == classType) {
+            return new VCheckBox();
+        } else if (VButton.class == classType) {
+            return new VButton();
+        } else if (VWindow.class == classType) {
+            return new VWindow();
+        } else if (VOrderedLayout.class == classType) {
+            return new VOrderedLayout();
+        } else if (VVerticalLayout.class == classType) {
+            return new VVerticalLayout();
+        } else if (VHorizontalLayout.class == classType) {
+            return new VHorizontalLayout();
+        } else if (VLabel.class == classType) {
+            return new VLabel();
+        } else if (VLink.class == classType) {
+            return new VLink();
+        } else if (VGridLayout.class == classType) {
+            return new VGridLayout();
+        } else if (VTree.class == classType) {
+            return new VTree();
+        } else if (VOptionGroup.class == classType) {
+            return new VOptionGroup();
+        } else if (VTwinColSelect.class == classType) {
+            return new VTwinColSelect();
+        } else if (VNativeSelect.class == classType) {
+            return new VNativeSelect();
+        } else if (VListSelect.class == classType) {
+            return new VListSelect();
+        } else if (VPanel.class == classType) {
+            return new VPanel();
+        } else if (VTabsheet.class == classType) {
+            return new VTabsheet();
+        } else if (VEmbedded.class == classType) {
+            return new VEmbedded();
+        } else if (VCustomLayout.class == classType) {
+            return new VCustomLayout();
+        } else if (VCustomComponent.class == classType) {
+            return new VCustomComponent();
+        } else if (VTextArea.class == classType) {
+            return new VTextArea();
+        } else if (VPasswordField.class == classType) {
+            return new VPasswordField();
+        } else if (VTextField.class == classType) {
+            return new VTextField();
+        } else if (VTablePaging.class == classType) {
+            return new VTablePaging();
+        } else if (VScrollTable.class == classType) {
+            return new VScrollTable();
+        } else if (VDateFieldCalendar.class == classType) {
+            return new VDateFieldCalendar();
+        } else if (VTextualDate.class == classType) {
+            return new VTextualDate();
+        } else if (VPopupCalendar.class == classType) {
+            return new VPopupCalendar();
+        } else if (VSlider.class == classType) {
+            return new VSlider();
+        } else if (VForm.class == classType) {
+            return new VForm();
+        } else if (VFormLayout.class == classType) {
+            return new VFormLayout();
+        } else if (VUpload.class == classType) {
+            return new VUpload();
+        } else if (VSplitPanelHorizontal.class == classType) {
+            return new VSplitPanelHorizontal();
+        } else if (VSplitPanelVertical.class == classType) {
+            return new VSplitPanelVertical();
+        } else if (VFilterSelect.class == classType) {
+            return new VFilterSelect();
+        } else if (VProgressIndicator.class == classType) {
+            return new VProgressIndicator();
+        } else if (VRichTextArea.class == classType) {
+            return new VRichTextArea();
+        } else if (VAccordion.class == classType) {
+            return new VAccordion();
+        } else if (VMenuBar.class == classType) {
+            return new VMenuBar();
+        } else if (VPopupView.class == classType) {
+            return new VPopupView();
+        } else if (VUriFragmentUtility.class == classType) {
+            return new VUriFragmentUtility();
+        } else if (VAbsoluteLayout.class == classType) {
+            return new VAbsoluteLayout();
         }
 
-        return new IUnknownComponent();
+        return new VUnknownComponent();
 
     }
 
@@ -152,111 +152,111 @@ public class DefaultWidgetSet implements WidgetSet {
         final String tag = uidl.getTag();
         if ("button".equals(tag)) {
             if ("switch".equals(uidl.getStringAttribute("type"))) {
-                return ICheckBox.class;
+                return VCheckBox.class;
             } else {
-                return IButton.class;
+                return VButton.class;
             }
         } else if ("window".equals(tag)) {
-            return IWindow.class;
+            return VWindow.class;
         } else if ("orderedlayout".equals(tag)) {
-            return IOrderedLayout.class;
+            return VOrderedLayout.class;
         } else if ("verticallayout".equals(tag)) {
-            return IVerticalLayout.class;
+            return VVerticalLayout.class;
         } else if ("horizontallayout".equals(tag)) {
-            return IHorizontalLayout.class;
+            return VHorizontalLayout.class;
         } else if ("label".equals(tag)) {
-            return ILabel.class;
+            return VLabel.class;
         } else if ("link".equals(tag)) {
-            return ILink.class;
+            return VLink.class;
         } else if ("gridlayout".equals(tag)) {
-            return IGridLayout.class;
+            return VGridLayout.class;
         } else if ("tree".equals(tag)) {
-            return ITree.class;
+            return VTree.class;
         } else if ("select".equals(tag)) {
             if (uidl.hasAttribute("type")) {
                 final String type = uidl.getStringAttribute("type");
                 if (type.equals("twincol")) {
-                    return ITwinColSelect.class;
+                    return VTwinColSelect.class;
                 }
                 if (type.equals("optiongroup")) {
-                    return IOptionGroup.class;
+                    return VOptionGroup.class;
                 }
                 if (type.equals("native")) {
-                    return INativeSelect.class;
+                    return VNativeSelect.class;
                 }
                 if (type.equals("list")) {
-                    return IListSelect.class;
+                    return VListSelect.class;
                 }
             } else {
                 if (uidl.hasAttribute("selectmode")
                         && uidl.getStringAttribute("selectmode")
                                 .equals("multi")) {
-                    return IListSelect.class;
+                    return VListSelect.class;
                 } else {
-                    return IFilterSelect.class;
+                    return VFilterSelect.class;
                 }
             }
         } else if ("panel".equals(tag)) {
-            return IPanel.class;
+            return VPanel.class;
         } else if ("tabsheet".equals(tag)) {
-            return ITabsheet.class;
+            return VTabsheet.class;
         } else if ("accordion".equals(tag)) {
-            return IAccordion.class;
+            return VAccordion.class;
         } else if ("embedded".equals(tag)) {
-            return IEmbedded.class;
+            return VEmbedded.class;
         } else if ("customlayout".equals(tag)) {
-            return ICustomLayout.class;
+            return VCustomLayout.class;
         } else if ("customcomponent".equals(tag)) {
-            return ICustomComponent.class;
+            return VCustomComponent.class;
         } else if ("textfield".equals(tag)) {
             if (uidl.getBooleanAttribute("richtext")) {
-                return IRichTextArea.class;
+                return VRichTextArea.class;
             } else if (uidl.hasAttribute("multiline")) {
-                return ITextArea.class;
+                return VTextArea.class;
             } else if (uidl.getBooleanAttribute("secret")) {
-                return IPasswordField.class;
+                return VPasswordField.class;
             } else {
-                return ITextField.class;
+                return VTextField.class;
             }
         } else if ("table".equals(tag)) {
-            return IScrollTable.class;
+            return VScrollTable.class;
         } else if ("pagingtable".equals(tag)) {
-            return ITablePaging.class;
+            return VTablePaging.class;
         } else if ("datefield".equals(tag)) {
             if (uidl.hasAttribute("type")) {
                 if ("inline".equals(uidl.getStringAttribute("type"))) {
-                    return IDateFieldCalendar.class;
+                    return VDateFieldCalendar.class;
                 } else if ("popup".equals(uidl.getStringAttribute("type"))) {
-                    return IPopupCalendar.class;
+                    return VPopupCalendar.class;
                 }
             }
             // popup calendar is the default
-            return IPopupCalendar.class;
+            return VPopupCalendar.class;
         } else if ("slider".equals(tag)) {
-            return ISlider.class;
+            return VSlider.class;
         } else if ("form".equals(tag)) {
-            return IForm.class;
+            return VForm.class;
         } else if ("formlayout".equals(tag)) {
-            return IFormLayout.class;
+            return VFormLayout.class;
         } else if ("upload".equals(tag)) {
-            return IUpload.class;
+            return VUpload.class;
         } else if ("hsplitpanel".equals(tag)) {
-            return ISplitPanelHorizontal.class;
+            return VSplitPanelHorizontal.class;
         } else if ("vsplitpanel".equals(tag)) {
-            return ISplitPanelVertical.class;
+            return VSplitPanelVertical.class;
         } else if ("progressindicator".equals(tag)) {
-            return IProgressIndicator.class;
+            return VProgressIndicator.class;
         } else if ("menubar".equals(tag)) {
-            return IMenuBar.class;
+            return VMenuBar.class;
         } else if ("popupview".equals(tag)) {
-            return IPopupView.class;
+            return VPopupView.class;
         } else if ("urifragment".equals(tag)) {
-            return IUriFragmentUtility.class;
-        } else if (IAbsoluteLayout.TAGNAME.equals(tag)) {
-            return IAbsoluteLayout.class;
+            return VUriFragmentUtility.class;
+        } else if (VAbsoluteLayout.TAGNAME.equals(tag)) {
+            return VAbsoluteLayout.class;
         }
 
-        return IUnknownComponent.class;
+        return VUnknownComponent.class;
     }
 
     /**
diff --git a/src/com/vaadin/terminal/gwt/client/ICaption.java b/src/com/vaadin/terminal/gwt/client/ICaption.java
deleted file mode 100644 (file)
index 972a844..0000000
+++ /dev/null
@@ -1,443 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.HTML;
-import com.vaadin.terminal.gwt.client.ui.Icon;
-
-public class ICaption extends HTML {
-
-    public static final String CLASSNAME = "i-caption";
-
-    private final Paintable owner;
-
-    private Element errorIndicatorElement;
-
-    private Element requiredFieldIndicator;
-
-    private Icon icon;
-
-    private Element captionText;
-
-    private Element clearElement;
-
-    private final ApplicationConnection client;
-
-    private boolean placedAfterComponent = false;
-    private boolean iconOnloadHandled = false;
-
-    private int maxWidth = -1;
-
-    private static String ATTRIBUTE_ICON = "icon";
-    private static String ATTRIBUTE_CAPTION = "caption";
-    private static String ATTRIBUTE_DESCRIPTION = "description";
-    private static String ATTRIBUTE_REQUIRED = "required";
-    private static String ATTRIBUTE_ERROR = "error";
-    private static String ATTRIBUTE_HIDEERRORS = "hideErrors";
-
-    /**
-     * 
-     * @param component
-     *            optional owner of caption. If not set, getOwner will return
-     *            null
-     * @param client
-     */
-    public ICaption(Paintable component, ApplicationConnection client) {
-        super();
-        this.client = client;
-        owner = component;
-        setStyleName(CLASSNAME);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-
-    }
-
-    /**
-     * Updates the caption from UIDL.
-     * 
-     * @param uidl
-     * @return true if the position where the caption should be placed has
-     *         changed
-     */
-    public boolean updateCaption(UIDL uidl) {
-        setVisible(!uidl.getBooleanAttribute("invisible"));
-
-        boolean wasPlacedAfterComponent = placedAfterComponent;
-
-        placedAfterComponent = true;
-
-        String style = CLASSNAME;
-        if (uidl.hasAttribute("style")) {
-            final String[] styles = uidl.getStringAttribute("style").split(" ");
-            for (int i = 0; i < styles.length; i++) {
-                style += " " + CLASSNAME + "-" + styles[i];
-            }
-        }
-
-        if (uidl.hasAttribute("disabled")) {
-            style += " " + "i-disabled";
-        }
-
-        setStyleName(style);
-
-        if (uidl.hasAttribute(ATTRIBUTE_ICON)) {
-            if (icon == null) {
-                icon = new Icon(client);
-                icon.setWidth("0px");
-                icon.setHeight("0px");
-
-                DOM.insertChild(getElement(), icon.getElement(),
-                        getInsertPosition(ATTRIBUTE_ICON));
-            }
-            placedAfterComponent = false;
-
-            iconOnloadHandled = false;
-            icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON));
-
-        } else if (icon != null) {
-            // Remove existing
-            DOM.removeChild(getElement(), icon.getElement());
-            icon = null;
-        }
-
-        if (uidl.hasAttribute(ATTRIBUTE_CAPTION)) {
-            if (captionText == null) {
-                captionText = DOM.createDiv();
-                captionText.setClassName("i-captiontext");
-
-                DOM.insertChild(getElement(), captionText,
-                        getInsertPosition(ATTRIBUTE_CAPTION));
-            }
-
-            // Update caption text
-            String c = uidl.getStringAttribute(ATTRIBUTE_CAPTION);
-            if (c == null) {
-                c = "";
-            } else {
-                placedAfterComponent = false;
-            }
-            DOM.setInnerText(captionText, c);
-        } else if (captionText != null) {
-            // Remove existing
-            DOM.removeChild(getElement(), captionText);
-            captionText = null;
-        }
-
-        if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) {
-            if (captionText != null) {
-                addStyleDependentName("hasdescription");
-            } else {
-                removeStyleDependentName("hasdescription");
-            }
-        }
-
-        if (uidl.getBooleanAttribute(ATTRIBUTE_REQUIRED)) {
-            if (requiredFieldIndicator == null) {
-                requiredFieldIndicator = DOM.createDiv();
-                requiredFieldIndicator
-                        .setClassName("i-required-field-indicator");
-                DOM.setInnerText(requiredFieldIndicator, "*");
-
-                DOM.insertChild(getElement(), requiredFieldIndicator,
-                        getInsertPosition(ATTRIBUTE_REQUIRED));
-            }
-        } else if (requiredFieldIndicator != null) {
-            // Remove existing
-            DOM.removeChild(getElement(), requiredFieldIndicator);
-            requiredFieldIndicator = null;
-        }
-
-        if (uidl.hasAttribute(ATTRIBUTE_ERROR)
-                && !uidl.getBooleanAttribute(ATTRIBUTE_HIDEERRORS)) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "i-errorindicator");
-
-                DOM.insertChild(getElement(), errorIndicatorElement,
-                        getInsertPosition(ATTRIBUTE_ERROR));
-            }
-        } else if (errorIndicatorElement != null) {
-            // Remove existing
-            DOM.removeChild(getElement(), errorIndicatorElement);
-            errorIndicatorElement = null;
-        }
-
-        if (clearElement == null) {
-            clearElement = DOM.createDiv();
-            DOM.setStyleAttribute(clearElement, "clear", "both");
-            DOM.setStyleAttribute(clearElement, "width", "0px");
-            DOM.setStyleAttribute(clearElement, "height", "0px");
-            DOM.setStyleAttribute(clearElement, "overflow", "hidden");
-            DOM.appendChild(getElement(), clearElement);
-        }
-
-        return (wasPlacedAfterComponent != placedAfterComponent);
-    }
-
-    private int getInsertPosition(String element) {
-        int pos = 0;
-        if (element.equals(ATTRIBUTE_ICON)) {
-            return pos;
-        }
-        if (icon != null) {
-            pos++;
-        }
-
-        if (element.equals(ATTRIBUTE_CAPTION)) {
-            return pos;
-        }
-
-        if (captionText != null) {
-            pos++;
-        }
-
-        if (element.equals(ATTRIBUTE_REQUIRED)) {
-            return pos;
-        }
-        if (requiredFieldIndicator != null) {
-            pos++;
-        }
-
-        // if (element.equals(ATTRIBUTE_ERROR)) {
-        // }
-        return pos;
-
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        final Element target = DOM.eventGetTarget(event);
-        if (client != null && owner != null && target != getElement()) {
-            client.handleTooltipEvent(event, owner);
-        }
-
-        if (DOM.eventGetType(event) == Event.ONLOAD
-                && icon.getElement() == target && !iconOnloadHandled) {
-            icon.setWidth("");
-            icon.setHeight("");
-
-            /*
-             * IE6 pngFix causes two onload events to be fired and we want to
-             * react only to the first one
-             */
-            iconOnloadHandled = true;
-
-            // if max width defined, recalculate
-            if (maxWidth != -1) {
-                setMaxWidth(maxWidth);
-            } else {
-                String width = getElement().getStyle().getProperty("width");
-                if (width != null && !width.equals("")) {
-                    setWidth(getRequiredWidth() + "px");
-                }
-            }
-
-            /*
-             * The size of the icon might affect the size of the component so we
-             * must report the size change to the parent TODO consider moving
-             * the responsibility of reacting to ONLOAD from ICaption to layouts
-             */
-            if (owner != null) {
-                Util.notifyParentOfSizeChange(owner, true);
-            } else {
-                ApplicationConnection
-                        .getConsole()
-                        .log(
-                                "Warning: Icon load event was not propagated because ICaption owner is unknown.");
-            }
-        }
-    }
-
-    public static boolean isNeeded(UIDL uidl) {
-        if (uidl.getStringAttribute(ATTRIBUTE_CAPTION) != null) {
-            return true;
-        }
-        if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
-            return true;
-        }
-        if (uidl.hasAttribute(ATTRIBUTE_ICON)) {
-            return true;
-        }
-        if (uidl.hasAttribute(ATTRIBUTE_REQUIRED)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Returns Paintable for which this Caption belongs to.
-     * 
-     * @return owner Widget
-     */
-    public Paintable getOwner() {
-        return owner;
-    }
-
-    public boolean shouldBePlacedAfterComponent() {
-        return placedAfterComponent;
-    }
-
-    public int getRenderedWidth() {
-        int width = 0;
-
-        if (icon != null) {
-            width += Util.getRequiredWidth(icon.getElement());
-        }
-
-        if (captionText != null) {
-            width += Util.getRequiredWidth(captionText);
-        }
-        if (requiredFieldIndicator != null) {
-            width += Util.getRequiredWidth(requiredFieldIndicator);
-        }
-        if (errorIndicatorElement != null) {
-            width += Util.getRequiredWidth(errorIndicatorElement);
-        }
-
-        return width;
-
-    }
-
-    public int getRequiredWidth() {
-        int width = 0;
-
-        if (icon != null) {
-            width += Util.getRequiredWidth(icon.getElement());
-        }
-        if (captionText != null) {
-            int textWidth = captionText.getScrollWidth();
-            if (BrowserInfo.get().isFF3()) {
-                /*
-                 * In Firefox3 the caption might require more space than the
-                 * scrollWidth returns as scrollWidth is rounded down.
-                 */
-                int requiredWidth = Util.getRequiredWidth(captionText);
-                if (requiredWidth > textWidth) {
-                    textWidth = requiredWidth;
-                }
-
-            }
-            width += textWidth;
-        }
-        if (requiredFieldIndicator != null) {
-            width += Util.getRequiredWidth(requiredFieldIndicator);
-        }
-        if (errorIndicatorElement != null) {
-            width += Util.getRequiredWidth(errorIndicatorElement);
-        }
-
-        return width;
-
-    }
-
-    public int getHeight() {
-        int height = 0;
-        int h;
-
-        if (icon != null) {
-            h = icon.getOffsetHeight();
-            if (h > height) {
-                height = h;
-            }
-        }
-
-        if (captionText != null) {
-            h = captionText.getOffsetHeight();
-            if (h > height) {
-                height = h;
-            }
-        }
-        if (requiredFieldIndicator != null) {
-            h = requiredFieldIndicator.getOffsetHeight();
-            if (h > height) {
-                height = h;
-            }
-        }
-        if (errorIndicatorElement != null) {
-            h = errorIndicatorElement.getOffsetHeight();
-            if (h > height) {
-                height = h;
-            }
-        }
-
-        return height;
-    }
-
-    public void setAlignment(String alignment) {
-        DOM.setStyleAttribute(getElement(), "textAlign", alignment);
-    }
-
-    public void setMaxWidth(int maxWidth) {
-        this.maxWidth = maxWidth;
-        DOM.setStyleAttribute(getElement(), "width", maxWidth + "px");
-
-        if (icon != null) {
-            DOM.setStyleAttribute(icon.getElement(), "width", "");
-        }
-
-        if (captionText != null) {
-            DOM.setStyleAttribute(captionText, "width", "");
-        }
-
-        int requiredWidth = getRequiredWidth();
-        /*
-         * ApplicationConnection.getConsole().log( "Caption maxWidth: " +
-         * maxWidth + ", requiredWidth: " + requiredWidth);
-         */
-        if (requiredWidth > maxWidth) {
-            // Needs to truncate and clip
-            int availableWidth = maxWidth;
-
-            // DOM.setStyleAttribute(getElement(), "width", maxWidth + "px");
-            if (requiredFieldIndicator != null) {
-                availableWidth -= Util.getRequiredWidth(requiredFieldIndicator);
-            }
-
-            if (errorIndicatorElement != null) {
-                availableWidth -= Util.getRequiredWidth(errorIndicatorElement);
-            }
-
-            if (availableWidth < 0) {
-                availableWidth = 0;
-            }
-
-            if (icon != null) {
-                int iconRequiredWidth = Util
-                        .getRequiredWidth(icon.getElement());
-                if (availableWidth > iconRequiredWidth) {
-                    availableWidth -= iconRequiredWidth;
-                } else {
-                    DOM.setStyleAttribute(icon.getElement(), "width",
-                            availableWidth + "px");
-                    availableWidth = 0;
-                }
-            }
-            if (captionText != null) {
-                int captionWidth = Util.getRequiredWidth(captionText);
-                if (availableWidth > captionWidth) {
-                    availableWidth -= captionWidth;
-
-                } else {
-                    DOM.setStyleAttribute(captionText, "width", availableWidth
-                            + "px");
-                    availableWidth = 0;
-                }
-
-            }
-
-        }
-    }
-
-    protected Element getTextElement() {
-        return captionText;
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ICaptionWrapper.java b/src/com/vaadin/terminal/gwt/client/ICaptionWrapper.java
deleted file mode 100644 (file)
index 15f1c5e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.Widget;
-
-public class ICaptionWrapper extends FlowPanel {
-
-    public static final String CLASSNAME = "i-captionwrapper";
-    ICaption caption;
-    Paintable widget;
-
-    public ICaptionWrapper(Paintable toBeWrapped, ApplicationConnection client) {
-        caption = new ICaption(toBeWrapped, client);
-        add(caption);
-        widget = toBeWrapped;
-        add((Widget) widget);
-        setStyleName(CLASSNAME);
-    }
-
-    public void updateCaption(UIDL uidl) {
-        caption.updateCaption(uidl);
-        setVisible(!uidl.getBooleanAttribute("invisible"));
-    }
-
-    public Paintable getPaintable() {
-        return widget;
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/IDebugConsole.java b/src/com/vaadin/terminal/gwt/client/IDebugConsole.java
deleted file mode 100755 (executable)
index 6986aea..0000000
+++ /dev/null
@@ -1,466 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import java.util.List;
-import java.util.Set;
-
-import com.google.gwt.json.client.JSONArray;
-import com.google.gwt.json.client.JSONObject;
-import com.google.gwt.json.client.JSONValue;
-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.EventPreview;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.Window.Location;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.CheckBox;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.Tree;
-import com.google.gwt.user.client.ui.TreeItem;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ui.IToolkitOverlay;
-
-public final class IDebugConsole extends IToolkitOverlay implements Console {
-
-    /**
-     * Builds number. For example 0-custom_tag in 5.0.0-custom_tag.
-     */
-    public static final String VERSION;
-
-    /* Initialize version numbers from string replaced by build-script. */
-    static {
-        if ("@VERSION@".equals("@" + "VERSION" + "@")) {
-            VERSION = "5.9.9-INTERNAL-NONVERSIONED-DEBUG-BUILD";
-        } else {
-            VERSION = "@VERSION@";
-        }
-    }
-
-    Element caption = DOM.createDiv();
-
-    private Panel panel;
-
-    private Button clear = new Button("Clear console");
-    private Button restart = new Button("Restart app");
-    private Button forceLayout = new Button("Force layout");
-    private Button analyzeLayout = new Button("Analyze layouts");
-    private HorizontalPanel actions;
-    private boolean collapsed = false;
-
-    private boolean resizing;
-    private int startX;
-    private int startY;
-    private int initialW;
-    private int initialH;
-
-    private boolean moving = false;
-
-    private int origTop;
-
-    private int origLeft;
-
-    private ApplicationConnection client;
-
-    private static final String help = "Drag=move, shift-drag=resize, doubleclick=min/max."
-            + "Use debug=quiet to log only to browser console.";
-
-    public IDebugConsole(ApplicationConnection client,
-            ApplicationConfiguration cnf, boolean showWindow) {
-        super(false, false);
-
-        this.client = client;
-
-        panel = new FlowPanel();
-        if (showWindow) {
-            DOM.appendChild(getContainerElement(), caption);
-            setWidget(panel);
-            caption.setClassName("i-debug-console-caption");
-            setStyleName("i-debug-console");
-            DOM.setStyleAttribute(getElement(), "zIndex", 20000 + "");
-            DOM.setStyleAttribute(getElement(), "overflow", "hidden");
-
-            sinkEvents(Event.ONDBLCLICK);
-
-            sinkEvents(Event.MOUSEEVENTS);
-
-            panel.setStyleName("i-debug-console-content");
-
-            caption.setInnerHTML("Debug window");
-            caption.setTitle(help);
-
-            show();
-            minimize();
-
-            actions = new HorizontalPanel();
-            actions.add(clear);
-            actions.add(restart);
-            actions.add(forceLayout);
-            actions.add(analyzeLayout);
-
-            panel.add(actions);
-
-            panel.add(new HTML("<i>" + help + "</i>"));
-
-            clear.addClickListener(new ClickListener() {
-                public void onClick(Widget sender) {
-                    int width = panel.getOffsetWidth();
-                    int height = panel.getOffsetHeight();
-                    panel = new FlowPanel();
-                    panel.setPixelSize(width, height);
-                    panel.setStyleName("i-debug-console-content");
-                    panel.add(actions);
-                    setWidget(panel);
-                }
-            });
-
-            restart.addClickListener(new ClickListener() {
-                public void onClick(Widget sender) {
-
-                    String queryString = Window.Location.getQueryString();
-                    if (queryString != null
-                            && queryString.contains("restartApplications")) {
-                        Window.Location.reload();
-                    } else {
-                        String url = Location.getHref();
-                        String separator = "?";
-                        if (url.contains("?")) {
-                            separator = "&";
-                        }
-                        if (!url.contains("restartApplication")) {
-                            url += separator;
-                            url += "restartApplication";
-                        }
-                        if (!"".equals(Location.getHash())) {
-                            String hash = Location.getHash();
-                            url = url.replace(hash, "") + hash;
-                        }
-                        Window.Location.replace(url);
-                    }
-
-                }
-            });
-
-            forceLayout.addClickListener(new ClickListener() {
-                public void onClick(Widget sender) {
-                    IDebugConsole.this.client.forceLayout();
-                }
-            });
-
-            analyzeLayout.addClickListener(new ClickListener() {
-                public void onClick(Widget sender) {
-                    List<ApplicationConnection> runningApplications = ApplicationConfiguration
-                            .getRunningApplications();
-                    for (ApplicationConnection applicationConnection : runningApplications) {
-                        applicationConnection.analyzeLayouts();
-                    }
-                }
-            });
-            analyzeLayout
-                    .setTitle("Analyzes currently rendered view and "
-                            + "reports possible common problems in usage of relative sizes."
-                            + "Will cause server visit/rendering of whole screen + lose of"
-                            + " all non committed variables form client side.");
-
-        }
-
-        log("Toolkit application servlet version: " + cnf.getServletVersion());
-        log("Widget set is built on version: " + VERSION);
-        log("Application version: " + cnf.getApplicationVersion());
-
-        if (!cnf.getServletVersion().equals(VERSION)) {
-            error("Warning: your widget set seems to be built with a different "
-                    + "version than the one used on server. Unexpected "
-                    + "behavior may occur.");
-        }
-    }
-
-    private EventPreview dragpreview = new EventPreview() {
-
-        public boolean onEventPreview(Event event) {
-            onBrowserEvent(event);
-            return false;
-        }
-    };
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        switch (DOM.eventGetType(event)) {
-        case Event.ONMOUSEDOWN:
-            if (DOM.eventGetShiftKey(event)) {
-                resizing = true;
-                DOM.setCapture(getElement());
-                startX = DOM.eventGetScreenX(event);
-                startY = DOM.eventGetScreenY(event);
-                initialW = IDebugConsole.this.getOffsetWidth();
-                initialH = IDebugConsole.this.getOffsetHeight();
-                DOM.eventCancelBubble(event, true);
-                DOM.eventPreventDefault(event);
-                DOM.addEventPreview(dragpreview);
-            } else if (DOM.eventGetTarget(event) == caption) {
-                moving = true;
-                startX = DOM.eventGetScreenX(event);
-                startY = DOM.eventGetScreenY(event);
-                origTop = getAbsoluteTop();
-                origLeft = getAbsoluteLeft();
-                DOM.eventCancelBubble(event, true);
-                DOM.eventPreventDefault(event);
-                DOM.addEventPreview(dragpreview);
-            }
-
-            break;
-        case Event.ONMOUSEMOVE:
-            if (resizing) {
-                int deltaX = startX - DOM.eventGetScreenX(event);
-                int detalY = startY - DOM.eventGetScreenY(event);
-                int w = initialW - deltaX;
-                if (w < 30) {
-                    w = 30;
-                }
-                int h = initialH - detalY;
-                if (h < 40) {
-                    h = 40;
-                }
-                IDebugConsole.this.setPixelSize(w, h);
-                DOM.eventCancelBubble(event, true);
-                DOM.eventPreventDefault(event);
-            } else if (moving) {
-                int deltaX = startX - DOM.eventGetScreenX(event);
-                int detalY = startY - DOM.eventGetScreenY(event);
-                int left = origLeft - deltaX;
-                if (left < 0) {
-                    left = 0;
-                }
-                int top = origTop - detalY;
-                if (top < 0) {
-                    top = 0;
-                }
-                IDebugConsole.this.setPopupPosition(left, top);
-                DOM.eventCancelBubble(event, true);
-                DOM.eventPreventDefault(event);
-            }
-            break;
-        case Event.ONLOSECAPTURE:
-        case Event.ONMOUSEUP:
-            if (resizing) {
-                DOM.releaseCapture(getElement());
-                resizing = false;
-            } else if (moving) {
-                DOM.releaseCapture(getElement());
-                moving = false;
-            }
-            DOM.removeEventPreview(dragpreview);
-            break;
-        case Event.ONDBLCLICK:
-            if (DOM.eventGetTarget(event) == caption) {
-                if (collapsed) {
-                    panel.setVisible(true);
-                    setPixelSize(220, 300);
-                } else {
-                    panel.setVisible(false);
-                    setPixelSize(120, 20);
-                }
-                collapsed = !collapsed;
-            }
-            break;
-        default:
-            break;
-        }
-
-    }
-
-    private void minimize() {
-        setPixelSize(400, 150);
-        setPopupPosition(Window.getClientWidth() - 410, Window
-                .getClientHeight() - 160);
-    }
-
-    @Override
-    public void setPixelSize(int width, int height) {
-        panel.setHeight((height - 20) + "px");
-        panel.setWidth((width - 2) + "px");
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see com.vaadin.terminal.gwt.client.Console#log(java.lang.String)
-     */
-    public void log(String msg) {
-        panel.add(new HTML(msg));
-        System.out.println(msg);
-        consoleLog(msg);
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see
-     * com.vaadin.terminal.gwt.client.Console#error(java.lang.String)
-     */
-    public void error(String msg) {
-        panel.add((new HTML(msg)));
-        System.err.println(msg);
-        consoleErr(msg);
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see
-     * com.vaadin.terminal.gwt.client.Console#printObject(java.lang.
-     * Object)
-     */
-    public void printObject(Object msg) {
-        panel.add((new Label(msg.toString())));
-        consoleLog(msg.toString());
-    }
-
-    /*
-     * (non-Javadoc)
-     * 
-     * @see
-     * com.vaadin.terminal.gwt.client.Console#dirUIDL(com.vaadin
-     * .terminal.gwt.client.UIDL)
-     */
-    public void dirUIDL(UIDL u) {
-        panel.add(u.print_r());
-        consoleLog(u.getChildrenAsXML());
-    }
-
-    private static native void consoleLog(String msg)
-    /*-{
-         if($wnd.console && $wnd.console.log) {
-             $wnd.console.log(msg);
-         }
-     }-*/;
-
-    private static native void consoleErr(String msg)
-    /*-{
-         if($wnd.console) {
-             if ($wnd.console.error)
-                 $wnd.console.error(msg);
-             else if ($wnd.console.log)
-                 $wnd.console.log(msg);
-         }
-     }-*/;
-
-    public void printLayoutProblems(JSONArray array, ApplicationConnection ac,
-            Set<Paintable> zeroHeightComponents,
-            Set<Paintable> zeroWidthComponents) {
-        int size = array.size();
-        panel.add(new HTML("<div>************************</di>"
-                + "<h4>Layouts analyzed on server, total top level problems: "
-                + size + " </h4>"));
-        if (size > 0) {
-            Tree tree = new Tree();
-            TreeItem root = new TreeItem("Root problems");
-            for (int i = 0; i < size; i++) {
-                JSONObject error = array.get(i).isObject();
-                printLayoutError(error, root, ac);
-            }
-            panel.add(tree);
-            tree.addItem(root);
-
-        }
-        if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
-            panel.add(new HTML("<h4> Client side notifications</h4>"
-                    + " <em>Following relative sized components where "
-                    + "rendered to zero size container on client side."
-                    + " Note that these are not necessary invalid "
-                    + "states. Just reported here as they might be.</em>"));
-            if (zeroHeightComponents.size() > 0) {
-                panel.add(new HTML(
-                        "<p><strong>Vertically zero size:</strong><p>"));
-                printClientSideDetectedIssues(zeroHeightComponents, ac);
-            }
-            if (zeroWidthComponents.size() > 0) {
-                panel.add(new HTML(
-                        "<p><strong>Horizontally zero size:</strong><p>"));
-                printClientSideDetectedIssues(zeroWidthComponents, ac);
-            }
-        }
-        log("************************");
-    }
-
-    private void printClientSideDetectedIssues(
-            Set<Paintable> zeroHeightComponents, ApplicationConnection ac) {
-        for (final Paintable paintable : zeroHeightComponents) {
-            final Container layout = Util.getLayout((Widget) paintable);
-
-            VerticalPanel errorDetails = new VerticalPanel();
-            errorDetails.add(new Label("" + Util.getSimpleName(paintable)
-                    + " inside " + Util.getSimpleName(layout)));
-            final CheckBox emphasisInUi = new CheckBox(
-                    "Emphasis components parent in UI (actual component is not visible)");
-            emphasisInUi.addClickListener(new ClickListener() {
-                public void onClick(Widget sender) {
-                    if (paintable != null) {
-                        Element element2 = ((Widget) layout).getElement();
-                        Widget.setStyleName(element2, "invalidlayout",
-                                emphasisInUi.isChecked());
-                    }
-                }
-            });
-            errorDetails.add(emphasisInUi);
-            panel.add(errorDetails);
-        }
-    }
-
-    private void printLayoutError(JSONObject error, TreeItem parent,
-            final ApplicationConnection ac) {
-        final String pid = error.get("id").isString().stringValue();
-        final Paintable paintable = ac.getPaintable(pid);
-
-        TreeItem errorNode = new TreeItem();
-        VerticalPanel errorDetails = new VerticalPanel();
-        errorDetails.add(new Label(Util.getSimpleName(paintable) + " id: "
-                + pid));
-        if (error.containsKey("heightMsg")) {
-            errorDetails.add(new Label("Height problem: "
-                    + error.get("heightMsg")));
-        }
-        if (error.containsKey("widthMsg")) {
-            errorDetails.add(new Label("Width problem: "
-                    + error.get("widthMsg")));
-        }
-        final CheckBox emphasisInUi = new CheckBox("Emphasis component in UI");
-        emphasisInUi.addClickListener(new ClickListener() {
-            public void onClick(Widget sender) {
-                if (paintable != null) {
-                    Element element2 = ((Widget) paintable).getElement();
-                    Widget.setStyleName(element2, "invalidlayout", emphasisInUi
-                            .isChecked());
-                }
-            }
-        });
-        errorDetails.add(emphasisInUi);
-        errorNode.setWidget(errorDetails);
-        if (error.containsKey("subErrors")) {
-            HTML l = new HTML(
-                    "<em>Expand this node to show problems that may be dependent on this problem.</em>");
-            errorDetails.add(l);
-            JSONArray array = error.get("subErrors").isArray();
-            for (int i = 0; i < array.size(); i++) {
-                JSONValue value = array.get(i);
-                if (value != null && value.isObject() != null) {
-                    printLayoutError(value.isObject(), errorNode, ac);
-                } else {
-                    System.out.print(value);
-                }
-            }
-
-        }
-        parent.addItem(errorNode);
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/IErrorMessage.java b/src/com/vaadin/terminal/gwt/client/IErrorMessage.java
deleted file mode 100644 (file)
index 0f5f456..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client;
-
-import java.util.Iterator;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.HTML;
-import com.vaadin.terminal.gwt.client.ui.IToolkitOverlay;
-
-public class IErrorMessage extends FlowPanel {
-    public static final String CLASSNAME = "i-errormessage";
-
-    public IErrorMessage() {
-        super();
-        setStyleName(CLASSNAME);
-    }
-
-    public void updateFromUIDL(UIDL uidl) {
-        clear();
-        if (uidl.getChildCount() == 0) {
-            add(new HTML(" "));
-        } else {
-            for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
-                final Object child = it.next();
-                if (child instanceof String) {
-                    final String errorMessage = (String) child;
-                    add(new HTML(errorMessage));
-                } else if (child instanceof UIDL.XML) {
-                    final UIDL.XML xml = (UIDL.XML) child;
-                    add(new HTML(xml.getXMLAsString()));
-                } else {
-                    final IErrorMessage childError = new IErrorMessage();
-                    add(childError);
-                    childError.updateFromUIDL((UIDL) child);
-                }
-            }
-        }
-    }
-
-    /**
-     * Shows this error message next to given element.
-     * 
-     * @param indicatorElement
-     */
-    public void showAt(Element indicatorElement) {
-        IToolkitOverlay errorContainer = (IToolkitOverlay) getParent();
-        if (errorContainer == null) {
-            errorContainer = new IToolkitOverlay();
-            errorContainer.setWidget(this);
-        }
-        errorContainer.setPopupPosition(DOM.getAbsoluteLeft(indicatorElement)
-                + 2
-                * DOM.getElementPropertyInt(indicatorElement, "offsetHeight"),
-                DOM.getAbsoluteTop(indicatorElement)
-                        + 2
-                        * DOM.getElementPropertyInt(indicatorElement,
-                                "offsetHeight"));
-        errorContainer.show();
-
-    }
-
-    public void hide() {
-        final IToolkitOverlay errorContainer = (IToolkitOverlay) getParent();
-        if (errorContainer != null) {
-            errorContainer.hide();
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ITooltip.java b/src/com/vaadin/terminal/gwt/client/ITooltip.java
deleted file mode 100644 (file)
index bbea0b4..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-package com.vaadin.terminal.gwt.client;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.vaadin.terminal.gwt.client.ui.IToolkitOverlay;
-
-/**
- * TODO open for extension
- */
-public class ITooltip extends IToolkitOverlay {
-    private static final String CLASSNAME = "i-tooltip";
-    private static final int MARGIN = 4;
-    public static final int TOOLTIP_EVENTS = Event.ONKEYDOWN
-            | Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEMOVE
-            | Event.ONCLICK;
-    protected static final int MAX_WIDTH = 500;
-    private static final int QUICK_OPEN_TIMEOUT = 1000;
-    private static final int CLOSE_TIMEOUT = 300;
-    private static final int OPEN_DELAY = 750;
-    private static final int QUICK_OPEN_DELAY = 100;
-    IErrorMessage em = new IErrorMessage();
-    Element description = DOM.createDiv();
-    private Paintable tooltipOwner;
-    private boolean closing = false;
-    private boolean opening = false;
-    private ApplicationConnection ac;
-    // Open next tooltip faster. Disabled after 2 sec of showTooltip-silence.
-    private boolean justClosed = false;
-
-    public ITooltip(ApplicationConnection client) {
-        super(false, false, true);
-        ac = client;
-        setStyleName(CLASSNAME);
-        FlowPanel layout = new FlowPanel();
-        setWidget(layout);
-        layout.add(em);
-        DOM.setElementProperty(description, "className", CLASSNAME + "-text");
-        DOM.appendChild(layout.getElement(), description);
-    }
-
-    private void show(TooltipInfo info) {
-        boolean hasContent = false;
-        if (info.getErrorUidl() != null) {
-            em.setVisible(true);
-            em.updateFromUIDL(info.getErrorUidl());
-            hasContent = true;
-        } else {
-            em.setVisible(false);
-        }
-        if (info.getTitle() != null && !"".equals(info.getTitle())) {
-            DOM.setInnerHTML(description, info.getTitle());
-            DOM.setStyleAttribute(description, "display", "");
-            hasContent = true;
-        } else {
-            DOM.setInnerHTML(description, "");
-            DOM.setStyleAttribute(description, "display", "none");
-        }
-        if (hasContent) {
-            setPopupPositionAndShow(new PositionCallback() {
-                public void setPosition(int offsetWidth, int offsetHeight) {
-
-                    if (offsetWidth > MAX_WIDTH) {
-                        setWidth(MAX_WIDTH + "px");
-                    }
-
-                    offsetWidth = getOffsetWidth();
-
-                    int x = tooltipEventMouseX + 10 + Window.getScrollLeft();
-                    int y = tooltipEventMouseY + 10 + Window.getScrollTop();
-
-                    if (x + offsetWidth + MARGIN - Window.getScrollLeft() > Window
-                            .getClientWidth()) {
-                        x = Window.getClientWidth() - offsetWidth - MARGIN;
-                    }
-
-                    if (y + offsetHeight + MARGIN - Window.getScrollTop() > Window
-                            .getClientHeight()) {
-                        y = tooltipEventMouseY - 5 - offsetHeight;
-                    }
-
-                    setPopupPosition(x, y);
-                    sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
-                }
-            });
-        } else {
-            hide();
-        }
-    }
-
-    public void showTooltip(Paintable owner, Event event) {
-        if (closing && tooltipOwner == owner) {
-            // return to same tooltip, cancel closing
-            closeTimer.cancel();
-            closing = false;
-            justClosedTimer.cancel();
-            justClosed = false;
-            return;
-        }
-
-        if (closing) {
-            closeNow();
-        }
-
-        updatePosition(event);
-
-        if (opening) {
-            showTimer.cancel();
-        }
-        tooltipOwner = owner;
-        if (justClosed) {
-            showTimer.schedule(QUICK_OPEN_DELAY);
-        } else {
-            showTimer.schedule(OPEN_DELAY);
-        }
-        opening = true;
-    }
-
-    private void closeNow() {
-        if (closing) {
-            hide();
-            tooltipOwner = null;
-            setWidth("");
-            closing = false;
-        }
-    }
-
-    private Timer showTimer = new Timer() {
-        @Override
-        public void run() {
-            TooltipInfo info = ac.getTitleInfo(tooltipOwner);
-            if (null != info) {
-                show(info);
-            }
-            opening = false;
-        }
-    };
-
-    private Timer closeTimer = new Timer() {
-        @Override
-        public void run() {
-            closeNow();
-            justClosedTimer.schedule(2000);
-            justClosed = true;
-        }
-    };
-
-    private Timer justClosedTimer = new Timer() {
-        @Override
-        public void run() {
-            justClosed = false;
-        }
-    };
-
-    public void hideTooltip() {
-        if (opening) {
-            showTimer.cancel();
-            opening = false;
-            tooltipOwner = null;
-        }
-        if (!isAttached()) {
-            return;
-        }
-        if (closing) {
-            // already about to close
-            return;
-        }
-        closeTimer.schedule(CLOSE_TIMEOUT);
-        closing = true;
-        justClosed = true;
-        justClosedTimer.schedule(QUICK_OPEN_TIMEOUT);
-
-    }
-
-    private int tooltipEventMouseX;
-    private int tooltipEventMouseY;
-
-    public void updatePosition(Event event) {
-        tooltipEventMouseX = DOM.eventGetClientX(event);
-        tooltipEventMouseY = DOM.eventGetClientY(event);
-
-    }
-
-    public void handleTooltipEvent(Event event, Paintable owner) {
-        final int type = DOM.eventGetType(event);
-        if ((ITooltip.TOOLTIP_EVENTS & type) == type) {
-            if (type == Event.ONMOUSEOVER) {
-                showTooltip(owner, event);
-            } else if (type == Event.ONMOUSEMOVE) {
-                updatePosition(event);
-            } else {
-                hideTooltip();
-            }
-        } else {
-            // non-tooltip event, hide tooltip
-            hideTooltip();
-        }
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        final int type = DOM.eventGetType(event);
-        // cancel closing event if tooltip is mouseovered; the user might want
-        // to scroll of cut&paste
-
-        switch (type) {
-        case Event.ONMOUSEOVER:
-            closeTimer.cancel();
-            closing = false;
-            break;
-        case Event.ONMOUSEOUT:
-            hideTooltip();
-            break;
-        default:
-            // NOP
-        }
-    }
-
-}
index 2205f6b6dd5e9c985d82af1d9e05c0f18207d666..8429c8a0d9d66ad2ce0491ee15e909d136ab6b5a 100644 (file)
@@ -238,12 +238,12 @@ public class UIDL {
         return s;
     }
 
-    public IUIDLBrowser print_r() {
-        return new IUIDLBrowser();
+    public VUIDLBrowser print_r() {
+        return new VUIDLBrowser();
     }
 
-    private class IUIDLBrowser extends Tree {
-        public IUIDLBrowser() {
+    private class VUIDLBrowser extends Tree {
+        public VUIDLBrowser() {
 
             DOM.setStyleAttribute(getElement(), "position", "");
 
@@ -255,7 +255,7 @@ public class UIDL {
                 public void onTreeItemStateChanged(TreeItem item) {
                     if (item == root) {
                         removeItem(root);
-                        IUIDLBrowser.this.removeTreeListener(this);
+                        VUIDLBrowser.this.removeTreeListener(this);
                         addItem(dir());
                         final Iterator it = treeItemIterator();
                         while (it.hasNext()) {
diff --git a/src/com/vaadin/terminal/gwt/client/VCaption.java b/src/com/vaadin/terminal/gwt/client/VCaption.java
new file mode 100644 (file)
index 0000000..7306806
--- /dev/null
@@ -0,0 +1,443 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.ui.Icon;
+
+public class VCaption extends HTML {
+
+    public static final String CLASSNAME = "i-caption";
+
+    private final Paintable owner;
+
+    private Element errorIndicatorElement;
+
+    private Element requiredFieldIndicator;
+
+    private Icon icon;
+
+    private Element captionText;
+
+    private Element clearElement;
+
+    private final ApplicationConnection client;
+
+    private boolean placedAfterComponent = false;
+    private boolean iconOnloadHandled = false;
+
+    private int maxWidth = -1;
+
+    private static String ATTRIBUTE_ICON = "icon";
+    private static String ATTRIBUTE_CAPTION = "caption";
+    private static String ATTRIBUTE_DESCRIPTION = "description";
+    private static String ATTRIBUTE_REQUIRED = "required";
+    private static String ATTRIBUTE_ERROR = "error";
+    private static String ATTRIBUTE_HIDEERRORS = "hideErrors";
+
+    /**
+     * 
+     * @param component
+     *            optional owner of caption. If not set, getOwner will return
+     *            null
+     * @param client
+     */
+    public VCaption(Paintable component, ApplicationConnection client) {
+        super();
+        this.client = client;
+        owner = component;
+        setStyleName(CLASSNAME);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+
+    }
+
+    /**
+     * Updates the caption from UIDL.
+     * 
+     * @param uidl
+     * @return true if the position where the caption should be placed has
+     *         changed
+     */
+    public boolean updateCaption(UIDL uidl) {
+        setVisible(!uidl.getBooleanAttribute("invisible"));
+
+        boolean wasPlacedAfterComponent = placedAfterComponent;
+
+        placedAfterComponent = true;
+
+        String style = CLASSNAME;
+        if (uidl.hasAttribute("style")) {
+            final String[] styles = uidl.getStringAttribute("style").split(" ");
+            for (int i = 0; i < styles.length; i++) {
+                style += " " + CLASSNAME + "-" + styles[i];
+            }
+        }
+
+        if (uidl.hasAttribute("disabled")) {
+            style += " " + "i-disabled";
+        }
+
+        setStyleName(style);
+
+        if (uidl.hasAttribute(ATTRIBUTE_ICON)) {
+            if (icon == null) {
+                icon = new Icon(client);
+                icon.setWidth("0px");
+                icon.setHeight("0px");
+
+                DOM.insertChild(getElement(), icon.getElement(),
+                        getInsertPosition(ATTRIBUTE_ICON));
+            }
+            placedAfterComponent = false;
+
+            iconOnloadHandled = false;
+            icon.setUri(uidl.getStringAttribute(ATTRIBUTE_ICON));
+
+        } else if (icon != null) {
+            // Remove existing
+            DOM.removeChild(getElement(), icon.getElement());
+            icon = null;
+        }
+
+        if (uidl.hasAttribute(ATTRIBUTE_CAPTION)) {
+            if (captionText == null) {
+                captionText = DOM.createDiv();
+                captionText.setClassName("i-captiontext");
+
+                DOM.insertChild(getElement(), captionText,
+                        getInsertPosition(ATTRIBUTE_CAPTION));
+            }
+
+            // Update caption text
+            String c = uidl.getStringAttribute(ATTRIBUTE_CAPTION);
+            if (c == null) {
+                c = "";
+            } else {
+                placedAfterComponent = false;
+            }
+            DOM.setInnerText(captionText, c);
+        } else if (captionText != null) {
+            // Remove existing
+            DOM.removeChild(getElement(), captionText);
+            captionText = null;
+        }
+
+        if (uidl.hasAttribute(ATTRIBUTE_DESCRIPTION)) {
+            if (captionText != null) {
+                addStyleDependentName("hasdescription");
+            } else {
+                removeStyleDependentName("hasdescription");
+            }
+        }
+
+        if (uidl.getBooleanAttribute(ATTRIBUTE_REQUIRED)) {
+            if (requiredFieldIndicator == null) {
+                requiredFieldIndicator = DOM.createDiv();
+                requiredFieldIndicator
+                        .setClassName("i-required-field-indicator");
+                DOM.setInnerText(requiredFieldIndicator, "*");
+
+                DOM.insertChild(getElement(), requiredFieldIndicator,
+                        getInsertPosition(ATTRIBUTE_REQUIRED));
+            }
+        } else if (requiredFieldIndicator != null) {
+            // Remove existing
+            DOM.removeChild(getElement(), requiredFieldIndicator);
+            requiredFieldIndicator = null;
+        }
+
+        if (uidl.hasAttribute(ATTRIBUTE_ERROR)
+                && !uidl.getBooleanAttribute(ATTRIBUTE_HIDEERRORS)) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = DOM.createDiv();
+                DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
+                DOM.setElementProperty(errorIndicatorElement, "className",
+                        "i-errorindicator");
+
+                DOM.insertChild(getElement(), errorIndicatorElement,
+                        getInsertPosition(ATTRIBUTE_ERROR));
+            }
+        } else if (errorIndicatorElement != null) {
+            // Remove existing
+            DOM.removeChild(getElement(), errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+
+        if (clearElement == null) {
+            clearElement = DOM.createDiv();
+            DOM.setStyleAttribute(clearElement, "clear", "both");
+            DOM.setStyleAttribute(clearElement, "width", "0px");
+            DOM.setStyleAttribute(clearElement, "height", "0px");
+            DOM.setStyleAttribute(clearElement, "overflow", "hidden");
+            DOM.appendChild(getElement(), clearElement);
+        }
+
+        return (wasPlacedAfterComponent != placedAfterComponent);
+    }
+
+    private int getInsertPosition(String element) {
+        int pos = 0;
+        if (element.equals(ATTRIBUTE_ICON)) {
+            return pos;
+        }
+        if (icon != null) {
+            pos++;
+        }
+
+        if (element.equals(ATTRIBUTE_CAPTION)) {
+            return pos;
+        }
+
+        if (captionText != null) {
+            pos++;
+        }
+
+        if (element.equals(ATTRIBUTE_REQUIRED)) {
+            return pos;
+        }
+        if (requiredFieldIndicator != null) {
+            pos++;
+        }
+
+        // if (element.equals(ATTRIBUTE_ERROR)) {
+        // }
+        return pos;
+
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        final Element target = DOM.eventGetTarget(event);
+        if (client != null && owner != null && target != getElement()) {
+            client.handleTooltipEvent(event, owner);
+        }
+
+        if (DOM.eventGetType(event) == Event.ONLOAD
+                && icon.getElement() == target && !iconOnloadHandled) {
+            icon.setWidth("");
+            icon.setHeight("");
+
+            /*
+             * IE6 pngFix causes two onload events to be fired and we want to
+             * react only to the first one
+             */
+            iconOnloadHandled = true;
+
+            // if max width defined, recalculate
+            if (maxWidth != -1) {
+                setMaxWidth(maxWidth);
+            } else {
+                String width = getElement().getStyle().getProperty("width");
+                if (width != null && !width.equals("")) {
+                    setWidth(getRequiredWidth() + "px");
+                }
+            }
+
+            /*
+             * The size of the icon might affect the size of the component so we
+             * must report the size change to the parent TODO consider moving
+             * the responsibility of reacting to ONLOAD from VCaption to layouts
+             */
+            if (owner != null) {
+                Util.notifyParentOfSizeChange(owner, true);
+            } else {
+                ApplicationConnection
+                        .getConsole()
+                        .log(
+                                "Warning: Icon load event was not propagated because VCaption owner is unknown.");
+            }
+        }
+    }
+
+    public static boolean isNeeded(UIDL uidl) {
+        if (uidl.getStringAttribute(ATTRIBUTE_CAPTION) != null) {
+            return true;
+        }
+        if (uidl.hasAttribute(ATTRIBUTE_ERROR)) {
+            return true;
+        }
+        if (uidl.hasAttribute(ATTRIBUTE_ICON)) {
+            return true;
+        }
+        if (uidl.hasAttribute(ATTRIBUTE_REQUIRED)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns Paintable for which this Caption belongs to.
+     * 
+     * @return owner Widget
+     */
+    public Paintable getOwner() {
+        return owner;
+    }
+
+    public boolean shouldBePlacedAfterComponent() {
+        return placedAfterComponent;
+    }
+
+    public int getRenderedWidth() {
+        int width = 0;
+
+        if (icon != null) {
+            width += Util.getRequiredWidth(icon.getElement());
+        }
+
+        if (captionText != null) {
+            width += Util.getRequiredWidth(captionText);
+        }
+        if (requiredFieldIndicator != null) {
+            width += Util.getRequiredWidth(requiredFieldIndicator);
+        }
+        if (errorIndicatorElement != null) {
+            width += Util.getRequiredWidth(errorIndicatorElement);
+        }
+
+        return width;
+
+    }
+
+    public int getRequiredWidth() {
+        int width = 0;
+
+        if (icon != null) {
+            width += Util.getRequiredWidth(icon.getElement());
+        }
+        if (captionText != null) {
+            int textWidth = captionText.getScrollWidth();
+            if (BrowserInfo.get().isFF3()) {
+                /*
+                 * In Firefox3 the caption might require more space than the
+                 * scrollWidth returns as scrollWidth is rounded down.
+                 */
+                int requiredWidth = Util.getRequiredWidth(captionText);
+                if (requiredWidth > textWidth) {
+                    textWidth = requiredWidth;
+                }
+
+            }
+            width += textWidth;
+        }
+        if (requiredFieldIndicator != null) {
+            width += Util.getRequiredWidth(requiredFieldIndicator);
+        }
+        if (errorIndicatorElement != null) {
+            width += Util.getRequiredWidth(errorIndicatorElement);
+        }
+
+        return width;
+
+    }
+
+    public int getHeight() {
+        int height = 0;
+        int h;
+
+        if (icon != null) {
+            h = icon.getOffsetHeight();
+            if (h > height) {
+                height = h;
+            }
+        }
+
+        if (captionText != null) {
+            h = captionText.getOffsetHeight();
+            if (h > height) {
+                height = h;
+            }
+        }
+        if (requiredFieldIndicator != null) {
+            h = requiredFieldIndicator.getOffsetHeight();
+            if (h > height) {
+                height = h;
+            }
+        }
+        if (errorIndicatorElement != null) {
+            h = errorIndicatorElement.getOffsetHeight();
+            if (h > height) {
+                height = h;
+            }
+        }
+
+        return height;
+    }
+
+    public void setAlignment(String alignment) {
+        DOM.setStyleAttribute(getElement(), "textAlign", alignment);
+    }
+
+    public void setMaxWidth(int maxWidth) {
+        this.maxWidth = maxWidth;
+        DOM.setStyleAttribute(getElement(), "width", maxWidth + "px");
+
+        if (icon != null) {
+            DOM.setStyleAttribute(icon.getElement(), "width", "");
+        }
+
+        if (captionText != null) {
+            DOM.setStyleAttribute(captionText, "width", "");
+        }
+
+        int requiredWidth = getRequiredWidth();
+        /*
+         * ApplicationConnection.getConsole().log( "Caption maxWidth: " +
+         * maxWidth + ", requiredWidth: " + requiredWidth);
+         */
+        if (requiredWidth > maxWidth) {
+            // Needs to truncate and clip
+            int availableWidth = maxWidth;
+
+            // DOM.setStyleAttribute(getElement(), "width", maxWidth + "px");
+            if (requiredFieldIndicator != null) {
+                availableWidth -= Util.getRequiredWidth(requiredFieldIndicator);
+            }
+
+            if (errorIndicatorElement != null) {
+                availableWidth -= Util.getRequiredWidth(errorIndicatorElement);
+            }
+
+            if (availableWidth < 0) {
+                availableWidth = 0;
+            }
+
+            if (icon != null) {
+                int iconRequiredWidth = Util
+                        .getRequiredWidth(icon.getElement());
+                if (availableWidth > iconRequiredWidth) {
+                    availableWidth -= iconRequiredWidth;
+                } else {
+                    DOM.setStyleAttribute(icon.getElement(), "width",
+                            availableWidth + "px");
+                    availableWidth = 0;
+                }
+            }
+            if (captionText != null) {
+                int captionWidth = Util.getRequiredWidth(captionText);
+                if (availableWidth > captionWidth) {
+                    availableWidth -= captionWidth;
+
+                } else {
+                    DOM.setStyleAttribute(captionText, "width", availableWidth
+                            + "px");
+                    availableWidth = 0;
+                }
+
+            }
+
+        }
+    }
+
+    protected Element getTextElement() {
+        return captionText;
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java b/src/com/vaadin/terminal/gwt/client/VCaptionWrapper.java
new file mode 100644 (file)
index 0000000..f67eb77
--- /dev/null
@@ -0,0 +1,32 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Widget;
+
+public class VCaptionWrapper extends FlowPanel {
+
+    public static final String CLASSNAME = "i-captionwrapper";
+    VCaption caption;
+    Paintable widget;
+
+    public VCaptionWrapper(Paintable toBeWrapped, ApplicationConnection client) {
+        caption = new VCaption(toBeWrapped, client);
+        add(caption);
+        widget = toBeWrapped;
+        add((Widget) widget);
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateCaption(UIDL uidl) {
+        caption.updateCaption(uidl);
+        setVisible(!uidl.getBooleanAttribute("invisible"));
+    }
+
+    public Paintable getPaintable() {
+        return widget;
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VDebugConsole.java b/src/com/vaadin/terminal/gwt/client/VDebugConsole.java
new file mode 100755 (executable)
index 0000000..aa7663a
--- /dev/null
@@ -0,0 +1,466 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.json.client.JSONArray;
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONValue;
+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.EventPreview;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.Window.Location;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.TreeItem;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ui.VToolkitOverlay;
+
+public final class VDebugConsole extends VToolkitOverlay implements Console {
+
+    /**
+     * Builds number. For example 0-custom_tag in 5.0.0-custom_tag.
+     */
+    public static final String VERSION;
+
+    /* Initialize version numbers from string replaced by build-script. */
+    static {
+        if ("@VERSION@".equals("@" + "VERSION" + "@")) {
+            VERSION = "5.9.9-INTERNAL-NONVERSIONED-DEBUG-BUILD";
+        } else {
+            VERSION = "@VERSION@";
+        }
+    }
+
+    Element caption = DOM.createDiv();
+
+    private Panel panel;
+
+    private Button clear = new Button("Clear console");
+    private Button restart = new Button("Restart app");
+    private Button forceLayout = new Button("Force layout");
+    private Button analyzeLayout = new Button("Analyze layouts");
+    private HorizontalPanel actions;
+    private boolean collapsed = false;
+
+    private boolean resizing;
+    private int startX;
+    private int startY;
+    private int initialW;
+    private int initialH;
+
+    private boolean moving = false;
+
+    private int origTop;
+
+    private int origLeft;
+
+    private ApplicationConnection client;
+
+    private static final String help = "Drag=move, shift-drag=resize, doubleclick=min/max."
+            + "Use debug=quiet to log only to browser console.";
+
+    public VDebugConsole(ApplicationConnection client,
+            ApplicationConfiguration cnf, boolean showWindow) {
+        super(false, false);
+
+        this.client = client;
+
+        panel = new FlowPanel();
+        if (showWindow) {
+            DOM.appendChild(getContainerElement(), caption);
+            setWidget(panel);
+            caption.setClassName("i-debug-console-caption");
+            setStyleName("i-debug-console");
+            DOM.setStyleAttribute(getElement(), "zIndex", 20000 + "");
+            DOM.setStyleAttribute(getElement(), "overflow", "hidden");
+
+            sinkEvents(Event.ONDBLCLICK);
+
+            sinkEvents(Event.MOUSEEVENTS);
+
+            panel.setStyleName("i-debug-console-content");
+
+            caption.setInnerHTML("Debug window");
+            caption.setTitle(help);
+
+            show();
+            minimize();
+
+            actions = new HorizontalPanel();
+            actions.add(clear);
+            actions.add(restart);
+            actions.add(forceLayout);
+            actions.add(analyzeLayout);
+
+            panel.add(actions);
+
+            panel.add(new HTML("<i>" + help + "</i>"));
+
+            clear.addClickListener(new ClickListener() {
+                public void onClick(Widget sender) {
+                    int width = panel.getOffsetWidth();
+                    int height = panel.getOffsetHeight();
+                    panel = new FlowPanel();
+                    panel.setPixelSize(width, height);
+                    panel.setStyleName("i-debug-console-content");
+                    panel.add(actions);
+                    setWidget(panel);
+                }
+            });
+
+            restart.addClickListener(new ClickListener() {
+                public void onClick(Widget sender) {
+
+                    String queryString = Window.Location.getQueryString();
+                    if (queryString != null
+                            && queryString.contains("restartApplications")) {
+                        Window.Location.reload();
+                    } else {
+                        String url = Location.getHref();
+                        String separator = "?";
+                        if (url.contains("?")) {
+                            separator = "&";
+                        }
+                        if (!url.contains("restartApplication")) {
+                            url += separator;
+                            url += "restartApplication";
+                        }
+                        if (!"".equals(Location.getHash())) {
+                            String hash = Location.getHash();
+                            url = url.replace(hash, "") + hash;
+                        }
+                        Window.Location.replace(url);
+                    }
+
+                }
+            });
+
+            forceLayout.addClickListener(new ClickListener() {
+                public void onClick(Widget sender) {
+                    VDebugConsole.this.client.forceLayout();
+                }
+            });
+
+            analyzeLayout.addClickListener(new ClickListener() {
+                public void onClick(Widget sender) {
+                    List<ApplicationConnection> runningApplications = ApplicationConfiguration
+                            .getRunningApplications();
+                    for (ApplicationConnection applicationConnection : runningApplications) {
+                        applicationConnection.analyzeLayouts();
+                    }
+                }
+            });
+            analyzeLayout
+                    .setTitle("Analyzes currently rendered view and "
+                            + "reports possible common problems in usage of relative sizes."
+                            + "Will cause server visit/rendering of whole screen + lose of"
+                            + " all non committed variables form client side.");
+
+        }
+
+        log("Toolkit application servlet version: " + cnf.getServletVersion());
+        log("Widget set is built on version: " + VERSION);
+        log("Application version: " + cnf.getApplicationVersion());
+
+        if (!cnf.getServletVersion().equals(VERSION)) {
+            error("Warning: your widget set seems to be built with a different "
+                    + "version than the one used on server. Unexpected "
+                    + "behavior may occur.");
+        }
+    }
+
+    private EventPreview dragpreview = new EventPreview() {
+
+        public boolean onEventPreview(Event event) {
+            onBrowserEvent(event);
+            return false;
+        }
+    };
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        switch (DOM.eventGetType(event)) {
+        case Event.ONMOUSEDOWN:
+            if (DOM.eventGetShiftKey(event)) {
+                resizing = true;
+                DOM.setCapture(getElement());
+                startX = DOM.eventGetScreenX(event);
+                startY = DOM.eventGetScreenY(event);
+                initialW = VDebugConsole.this.getOffsetWidth();
+                initialH = VDebugConsole.this.getOffsetHeight();
+                DOM.eventCancelBubble(event, true);
+                DOM.eventPreventDefault(event);
+                DOM.addEventPreview(dragpreview);
+            } else if (DOM.eventGetTarget(event) == caption) {
+                moving = true;
+                startX = DOM.eventGetScreenX(event);
+                startY = DOM.eventGetScreenY(event);
+                origTop = getAbsoluteTop();
+                origLeft = getAbsoluteLeft();
+                DOM.eventCancelBubble(event, true);
+                DOM.eventPreventDefault(event);
+                DOM.addEventPreview(dragpreview);
+            }
+
+            break;
+        case Event.ONMOUSEMOVE:
+            if (resizing) {
+                int deltaX = startX - DOM.eventGetScreenX(event);
+                int detalY = startY - DOM.eventGetScreenY(event);
+                int w = initialW - deltaX;
+                if (w < 30) {
+                    w = 30;
+                }
+                int h = initialH - detalY;
+                if (h < 40) {
+                    h = 40;
+                }
+                VDebugConsole.this.setPixelSize(w, h);
+                DOM.eventCancelBubble(event, true);
+                DOM.eventPreventDefault(event);
+            } else if (moving) {
+                int deltaX = startX - DOM.eventGetScreenX(event);
+                int detalY = startY - DOM.eventGetScreenY(event);
+                int left = origLeft - deltaX;
+                if (left < 0) {
+                    left = 0;
+                }
+                int top = origTop - detalY;
+                if (top < 0) {
+                    top = 0;
+                }
+                VDebugConsole.this.setPopupPosition(left, top);
+                DOM.eventCancelBubble(event, true);
+                DOM.eventPreventDefault(event);
+            }
+            break;
+        case Event.ONLOSECAPTURE:
+        case Event.ONMOUSEUP:
+            if (resizing) {
+                DOM.releaseCapture(getElement());
+                resizing = false;
+            } else if (moving) {
+                DOM.releaseCapture(getElement());
+                moving = false;
+            }
+            DOM.removeEventPreview(dragpreview);
+            break;
+        case Event.ONDBLCLICK:
+            if (DOM.eventGetTarget(event) == caption) {
+                if (collapsed) {
+                    panel.setVisible(true);
+                    setPixelSize(220, 300);
+                } else {
+                    panel.setVisible(false);
+                    setPixelSize(120, 20);
+                }
+                collapsed = !collapsed;
+            }
+            break;
+        default:
+            break;
+        }
+
+    }
+
+    private void minimize() {
+        setPixelSize(400, 150);
+        setPopupPosition(Window.getClientWidth() - 410, Window
+                .getClientHeight() - 160);
+    }
+
+    @Override
+    public void setPixelSize(int width, int height) {
+        panel.setHeight((height - 20) + "px");
+        panel.setWidth((width - 2) + "px");
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.terminal.gwt.client.Console#log(java.lang.String)
+     */
+    public void log(String msg) {
+        panel.add(new HTML(msg));
+        System.out.println(msg);
+        consoleLog(msg);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.terminal.gwt.client.Console#error(java.lang.String)
+     */
+    public void error(String msg) {
+        panel.add((new HTML(msg)));
+        System.err.println(msg);
+        consoleErr(msg);
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.terminal.gwt.client.Console#printObject(java.lang.
+     * Object)
+     */
+    public void printObject(Object msg) {
+        panel.add((new Label(msg.toString())));
+        consoleLog(msg.toString());
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.terminal.gwt.client.Console#dirUIDL(com.vaadin
+     * .terminal.gwt.client.UIDL)
+     */
+    public void dirUIDL(UIDL u) {
+        panel.add(u.print_r());
+        consoleLog(u.getChildrenAsXML());
+    }
+
+    private static native void consoleLog(String msg)
+    /*-{
+         if($wnd.console && $wnd.console.log) {
+             $wnd.console.log(msg);
+         }
+     }-*/;
+
+    private static native void consoleErr(String msg)
+    /*-{
+         if($wnd.console) {
+             if ($wnd.console.error)
+                 $wnd.console.error(msg);
+             else if ($wnd.console.log)
+                 $wnd.console.log(msg);
+         }
+     }-*/;
+
+    public void printLayoutProblems(JSONArray array, ApplicationConnection ac,
+            Set<Paintable> zeroHeightComponents,
+            Set<Paintable> zeroWidthComponents) {
+        int size = array.size();
+        panel.add(new HTML("<div>************************</di>"
+                + "<h4>Layouts analyzed on server, total top level problems: "
+                + size + " </h4>"));
+        if (size > 0) {
+            Tree tree = new Tree();
+            TreeItem root = new TreeItem("Root problems");
+            for (int i = 0; i < size; i++) {
+                JSONObject error = array.get(i).isObject();
+                printLayoutError(error, root, ac);
+            }
+            panel.add(tree);
+            tree.addItem(root);
+
+        }
+        if (zeroHeightComponents.size() > 0 || zeroWidthComponents.size() > 0) {
+            panel.add(new HTML("<h4> Client side notifications</h4>"
+                    + " <em>Following relative sized components where "
+                    + "rendered to zero size container on client side."
+                    + " Note that these are not necessary invalid "
+                    + "states. Just reported here as they might be.</em>"));
+            if (zeroHeightComponents.size() > 0) {
+                panel.add(new HTML(
+                        "<p><strong>Vertically zero size:</strong><p>"));
+                printClientSideDetectedIssues(zeroHeightComponents, ac);
+            }
+            if (zeroWidthComponents.size() > 0) {
+                panel.add(new HTML(
+                        "<p><strong>Horizontally zero size:</strong><p>"));
+                printClientSideDetectedIssues(zeroWidthComponents, ac);
+            }
+        }
+        log("************************");
+    }
+
+    private void printClientSideDetectedIssues(
+            Set<Paintable> zeroHeightComponents, ApplicationConnection ac) {
+        for (final Paintable paintable : zeroHeightComponents) {
+            final Container layout = Util.getLayout((Widget) paintable);
+
+            VerticalPanel errorDetails = new VerticalPanel();
+            errorDetails.add(new Label("" + Util.getSimpleName(paintable)
+                    + " inside " + Util.getSimpleName(layout)));
+            final CheckBox emphasisInUi = new CheckBox(
+                    "Emphasis components parent in UI (actual component is not visible)");
+            emphasisInUi.addClickListener(new ClickListener() {
+                public void onClick(Widget sender) {
+                    if (paintable != null) {
+                        Element element2 = ((Widget) layout).getElement();
+                        Widget.setStyleName(element2, "invalidlayout",
+                                emphasisInUi.isChecked());
+                    }
+                }
+            });
+            errorDetails.add(emphasisInUi);
+            panel.add(errorDetails);
+        }
+    }
+
+    private void printLayoutError(JSONObject error, TreeItem parent,
+            final ApplicationConnection ac) {
+        final String pid = error.get("id").isString().stringValue();
+        final Paintable paintable = ac.getPaintable(pid);
+
+        TreeItem errorNode = new TreeItem();
+        VerticalPanel errorDetails = new VerticalPanel();
+        errorDetails.add(new Label(Util.getSimpleName(paintable) + " id: "
+                + pid));
+        if (error.containsKey("heightMsg")) {
+            errorDetails.add(new Label("Height problem: "
+                    + error.get("heightMsg")));
+        }
+        if (error.containsKey("widthMsg")) {
+            errorDetails.add(new Label("Width problem: "
+                    + error.get("widthMsg")));
+        }
+        final CheckBox emphasisInUi = new CheckBox("Emphasis component in UI");
+        emphasisInUi.addClickListener(new ClickListener() {
+            public void onClick(Widget sender) {
+                if (paintable != null) {
+                    Element element2 = ((Widget) paintable).getElement();
+                    Widget.setStyleName(element2, "invalidlayout", emphasisInUi
+                            .isChecked());
+                }
+            }
+        });
+        errorDetails.add(emphasisInUi);
+        errorNode.setWidget(errorDetails);
+        if (error.containsKey("subErrors")) {
+            HTML l = new HTML(
+                    "<em>Expand this node to show problems that may be dependent on this problem.</em>");
+            errorDetails.add(l);
+            JSONArray array = error.get("subErrors").isArray();
+            for (int i = 0; i < array.size(); i++) {
+                JSONValue value = array.get(i);
+                if (value != null && value.isObject() != null) {
+                    printLayoutError(value.isObject(), errorNode, ac);
+                } else {
+                    System.out.print(value);
+                }
+            }
+
+        }
+        parent.addItem(errorNode);
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VErrorMessage.java b/src/com/vaadin/terminal/gwt/client/VErrorMessage.java
new file mode 100644 (file)
index 0000000..8181740
--- /dev/null
@@ -0,0 +1,73 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client;
+
+import java.util.Iterator;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.ui.VToolkitOverlay;
+
+public class VErrorMessage extends FlowPanel {
+    public static final String CLASSNAME = "i-errormessage";
+
+    public VErrorMessage() {
+        super();
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateFromUIDL(UIDL uidl) {
+        clear();
+        if (uidl.getChildCount() == 0) {
+            add(new HTML(" "));
+        } else {
+            for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
+                final Object child = it.next();
+                if (child instanceof String) {
+                    final String errorMessage = (String) child;
+                    add(new HTML(errorMessage));
+                } else if (child instanceof UIDL.XML) {
+                    final UIDL.XML xml = (UIDL.XML) child;
+                    add(new HTML(xml.getXMLAsString()));
+                } else {
+                    final VErrorMessage childError = new VErrorMessage();
+                    add(childError);
+                    childError.updateFromUIDL((UIDL) child);
+                }
+            }
+        }
+    }
+
+    /**
+     * Shows this error message next to given element.
+     * 
+     * @param indicatorElement
+     */
+    public void showAt(Element indicatorElement) {
+        VToolkitOverlay errorContainer = (VToolkitOverlay) getParent();
+        if (errorContainer == null) {
+            errorContainer = new VToolkitOverlay();
+            errorContainer.setWidget(this);
+        }
+        errorContainer.setPopupPosition(DOM.getAbsoluteLeft(indicatorElement)
+                + 2
+                * DOM.getElementPropertyInt(indicatorElement, "offsetHeight"),
+                DOM.getAbsoluteTop(indicatorElement)
+                        + 2
+                        * DOM.getElementPropertyInt(indicatorElement,
+                                "offsetHeight"));
+        errorContainer.show();
+
+    }
+
+    public void hide() {
+        final VToolkitOverlay errorContainer = (VToolkitOverlay) getParent();
+        if (errorContainer != null) {
+            errorContainer.hide();
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/VTooltip.java b/src/com/vaadin/terminal/gwt/client/VTooltip.java
new file mode 100644 (file)
index 0000000..9e02dc4
--- /dev/null
@@ -0,0 +1,225 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+package com.vaadin.terminal.gwt.client;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.vaadin.terminal.gwt.client.ui.VToolkitOverlay;
+
+/**
+ * TODO open for extension
+ */
+public class VTooltip extends VToolkitOverlay {
+    private static final String CLASSNAME = "i-tooltip";
+    private static final int MARGIN = 4;
+    public static final int TOOLTIP_EVENTS = Event.ONKEYDOWN
+            | Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONMOUSEMOVE
+            | Event.ONCLICK;
+    protected static final int MAX_WIDTH = 500;
+    private static final int QUICK_OPEN_TIMEOUT = 1000;
+    private static final int CLOSE_TIMEOUT = 300;
+    private static final int OPEN_DELAY = 750;
+    private static final int QUICK_OPEN_DELAY = 100;
+    VErrorMessage em = new VErrorMessage();
+    Element description = DOM.createDiv();
+    private Paintable tooltipOwner;
+    private boolean closing = false;
+    private boolean opening = false;
+    private ApplicationConnection ac;
+    // Open next tooltip faster. Disabled after 2 sec of showTooltip-silence.
+    private boolean justClosed = false;
+
+    public VTooltip(ApplicationConnection client) {
+        super(false, false, true);
+        ac = client;
+        setStyleName(CLASSNAME);
+        FlowPanel layout = new FlowPanel();
+        setWidget(layout);
+        layout.add(em);
+        DOM.setElementProperty(description, "className", CLASSNAME + "-text");
+        DOM.appendChild(layout.getElement(), description);
+    }
+
+    private void show(TooltipInfo info) {
+        boolean hasContent = false;
+        if (info.getErrorUidl() != null) {
+            em.setVisible(true);
+            em.updateFromUIDL(info.getErrorUidl());
+            hasContent = true;
+        } else {
+            em.setVisible(false);
+        }
+        if (info.getTitle() != null && !"".equals(info.getTitle())) {
+            DOM.setInnerHTML(description, info.getTitle());
+            DOM.setStyleAttribute(description, "display", "");
+            hasContent = true;
+        } else {
+            DOM.setInnerHTML(description, "");
+            DOM.setStyleAttribute(description, "display", "none");
+        }
+        if (hasContent) {
+            setPopupPositionAndShow(new PositionCallback() {
+                public void setPosition(int offsetWidth, int offsetHeight) {
+
+                    if (offsetWidth > MAX_WIDTH) {
+                        setWidth(MAX_WIDTH + "px");
+                    }
+
+                    offsetWidth = getOffsetWidth();
+
+                    int x = tooltipEventMouseX + 10 + Window.getScrollLeft();
+                    int y = tooltipEventMouseY + 10 + Window.getScrollTop();
+
+                    if (x + offsetWidth + MARGIN - Window.getScrollLeft() > Window
+                            .getClientWidth()) {
+                        x = Window.getClientWidth() - offsetWidth - MARGIN;
+                    }
+
+                    if (y + offsetHeight + MARGIN - Window.getScrollTop() > Window
+                            .getClientHeight()) {
+                        y = tooltipEventMouseY - 5 - offsetHeight;
+                    }
+
+                    setPopupPosition(x, y);
+                    sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT);
+                }
+            });
+        } else {
+            hide();
+        }
+    }
+
+    public void showTooltip(Paintable owner, Event event) {
+        if (closing && tooltipOwner == owner) {
+            // return to same tooltip, cancel closing
+            closeTimer.cancel();
+            closing = false;
+            justClosedTimer.cancel();
+            justClosed = false;
+            return;
+        }
+
+        if (closing) {
+            closeNow();
+        }
+
+        updatePosition(event);
+
+        if (opening) {
+            showTimer.cancel();
+        }
+        tooltipOwner = owner;
+        if (justClosed) {
+            showTimer.schedule(QUICK_OPEN_DELAY);
+        } else {
+            showTimer.schedule(OPEN_DELAY);
+        }
+        opening = true;
+    }
+
+    private void closeNow() {
+        if (closing) {
+            hide();
+            tooltipOwner = null;
+            setWidth("");
+            closing = false;
+        }
+    }
+
+    private Timer showTimer = new Timer() {
+        @Override
+        public void run() {
+            TooltipInfo info = ac.getTitleInfo(tooltipOwner);
+            if (null != info) {
+                show(info);
+            }
+            opening = false;
+        }
+    };
+
+    private Timer closeTimer = new Timer() {
+        @Override
+        public void run() {
+            closeNow();
+            justClosedTimer.schedule(2000);
+            justClosed = true;
+        }
+    };
+
+    private Timer justClosedTimer = new Timer() {
+        @Override
+        public void run() {
+            justClosed = false;
+        }
+    };
+
+    public void hideTooltip() {
+        if (opening) {
+            showTimer.cancel();
+            opening = false;
+            tooltipOwner = null;
+        }
+        if (!isAttached()) {
+            return;
+        }
+        if (closing) {
+            // already about to close
+            return;
+        }
+        closeTimer.schedule(CLOSE_TIMEOUT);
+        closing = true;
+        justClosed = true;
+        justClosedTimer.schedule(QUICK_OPEN_TIMEOUT);
+
+    }
+
+    private int tooltipEventMouseX;
+    private int tooltipEventMouseY;
+
+    public void updatePosition(Event event) {
+        tooltipEventMouseX = DOM.eventGetClientX(event);
+        tooltipEventMouseY = DOM.eventGetClientY(event);
+
+    }
+
+    public void handleTooltipEvent(Event event, Paintable owner) {
+        final int type = DOM.eventGetType(event);
+        if ((VTooltip.TOOLTIP_EVENTS & type) == type) {
+            if (type == Event.ONMOUSEOVER) {
+                showTooltip(owner, event);
+            } else if (type == Event.ONMOUSEMOVE) {
+                updatePosition(event);
+            } else {
+                hideTooltip();
+            }
+        } else {
+            // non-tooltip event, hide tooltip
+            hideTooltip();
+        }
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        final int type = DOM.eventGetType(event);
+        // cancel closing event if tooltip is mouseovered; the user might want
+        // to scroll of cut&paste
+
+        switch (type) {
+        case Event.ONMOUSEOVER:
+            closeTimer.cancel();
+            closing = false;
+            break;
+        case Event.ONMOUSEOUT:
+            hideTooltip();
+            break;
+        default:
+            // NOP
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/IAbsoluteLayout.java
deleted file mode 100644 (file)
index 06134e9..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.Map.Entry;
-
-import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.ICaption;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IAbsoluteLayout extends ComplexPanel implements Container {
-
-    /** Tag name for widget creation */
-    public static final String TAGNAME = "absolutelayout";
-
-    /** Class name, prefix in styling */
-    public static final String CLASSNAME = "i-absolutelayout";
-
-    private DivElement marginElement;
-
-    protected final Element canvas = DOM.createDiv();
-
-    private int excessPixelsHorizontal;
-
-    private int excessPixelsVertical;
-
-    private Object previousStyleName;
-
-    private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>();
-
-    protected ApplicationConnection client;
-
-    private boolean rendering;
-
-    public IAbsoluteLayout() {
-        setElement(Document.get().createDivElement());
-        setStyleName(CLASSNAME);
-        marginElement = Document.get().createDivElement();
-        canvas.getStyle().setProperty("position", "relative");
-        marginElement.appendChild(canvas);
-        getElement().appendChild(marginElement);
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        // TODO needs some special handling for components with only on edge
-        // horizontally or vertically defined
-        AbsoluteWrapper wrapper = (AbsoluteWrapper) child.getParent();
-        int w;
-        if (wrapper.left != null && wrapper.right != null) {
-            w = wrapper.getOffsetWidth();
-        } else if (wrapper.right != null) {
-            // left == null
-            // available width == right edge == offsetleft + width
-            w = wrapper.getOffsetWidth() + wrapper.getElement().getOffsetLeft();
-        } else {
-            // left != null && right == null || left == null &&
-            // right == null
-            // available width == canvas width - offset left
-            w = canvas.getOffsetWidth() - wrapper.getElement().getOffsetLeft();
-        }
-        int h;
-        if (wrapper.top != null && wrapper.bottom != null) {
-            h = wrapper.getOffsetHeight();
-        } else if (wrapper.bottom != null) {
-            // top not defined, available space 0... bottom of wrapper
-            h = wrapper.getElement().getOffsetTop() + wrapper.getOffsetHeight();
-        } else {
-            // top defined or both undefined, available space == canvas - top
-            h = canvas.getOffsetHeight() - wrapper.getElement().getOffsetTop();
-        }
-
-        return new RenderSpace(w, h);
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        for (Iterator<Entry<String, AbsoluteWrapper>> iterator = pidToComponentWrappper
-                .entrySet().iterator(); iterator.hasNext();) {
-            if (iterator.next().getValue().paintable == component) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        for (Widget wrapper : getChildren()) {
-            AbsoluteWrapper w = (AbsoluteWrapper) wrapper;
-            if (w.getWidget() == oldComponent) {
-                w.setWidget(newComponent);
-                return;
-            }
-        }
-    }
-
-    public boolean requestLayout(Set<Paintable> children) {
-        // component inside an absolute panel never affects parent nor the
-        // layout
-        return true;
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        AbsoluteWrapper parent2 = (AbsoluteWrapper) ((Widget) component)
-                .getParent();
-        parent2.updateCaption(uidl);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-        this.client = client;
-        // TODO margin handling
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-
-        HashSet<String> unrenderedPids = new HashSet<String>(
-                pidToComponentWrappper.keySet());
-
-        for (Iterator<UIDL> childIterator = uidl.getChildIterator(); childIterator
-                .hasNext();) {
-            UIDL cc = childIterator.next();
-            UIDL componentUIDL = cc.getChildUIDL(0);
-            unrenderedPids.remove(componentUIDL.getId());
-            getWrapper(client, componentUIDL).updateFromUIDL(cc);
-        }
-
-        for (String pid : unrenderedPids) {
-            AbsoluteWrapper absoluteWrapper = pidToComponentWrappper.get(pid);
-            pidToComponentWrappper.remove(pid);
-            absoluteWrapper.destroy();
-        }
-        rendering = false;
-    }
-
-    private AbsoluteWrapper getWrapper(ApplicationConnection client,
-            UIDL componentUIDL) {
-        AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL
-                .getId());
-        if (wrapper == null) {
-            wrapper = new AbsoluteWrapper(client.getPaintable(componentUIDL));
-            pidToComponentWrappper.put(componentUIDL.getId(), wrapper);
-            add(wrapper);
-        }
-        return wrapper;
-
-    }
-
-    @Override
-    public void add(Widget child) {
-        super.add(child, canvas);
-    }
-
-    @Override
-    public void setStyleName(String style) {
-        super.setStyleName(style);
-        if (previousStyleName == null || !previousStyleName.equals(style)) {
-            excessPixelsHorizontal = -1;
-            excessPixelsVertical = -1;
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        super.setWidth(width);
-        // TODO do this so that canvas gets the sized properly (the area
-        // inside marginals)
-        canvas.getStyle().setProperty("width", width);
-
-        if (!rendering) {
-            if (BrowserInfo.get().isIE6()) {
-                relayoutWrappersForIe6();
-            }
-            relayoutRelativeChildren();
-        }
-    }
-
-    private void relayoutRelativeChildren() {
-        for (Widget widget : getChildren()) {
-            if (widget instanceof AbsoluteWrapper) {
-                AbsoluteWrapper w = (AbsoluteWrapper) widget;
-                client.handleComponentRelativeSize(w.getWidget());
-                w.updateCaptionPosition();
-            }
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        // TODO do this so that canvas gets the sized properly (the area
-        // inside marginals)
-        canvas.getStyle().setProperty("height", height);
-
-        if (!rendering) {
-            if (BrowserInfo.get().isIE6()) {
-                relayoutWrappersForIe6();
-            }
-            relayoutRelativeChildren();
-        }
-    }
-
-    private void relayoutWrappersForIe6() {
-        for (Widget wrapper : getChildren()) {
-            if (wrapper instanceof AbsoluteWrapper) {
-                ((AbsoluteWrapper) wrapper).ie6Layout();
-            }
-        }
-    }
-
-    public class AbsoluteWrapper extends SimplePanel {
-        private String css;
-        private String left;
-        private String top;
-        private String right;
-        private String bottom;
-        private String zIndex;
-
-        private Paintable paintable;
-        private ICaption caption;
-
-        public AbsoluteWrapper(Paintable paintable) {
-            this.paintable = paintable;
-            setStyleName(CLASSNAME + "-wrapper");
-        }
-
-        public void updateCaption(UIDL uidl) {
-
-            boolean captionIsNeeded = ICaption.isNeeded(uidl);
-            if (captionIsNeeded) {
-                if (caption == null) {
-                    caption = new ICaption(paintable, client);
-                    IAbsoluteLayout.this.add(caption);
-                }
-                caption.updateCaption(uidl);
-                updateCaptionPosition();
-            } else {
-                if (caption != null) {
-                    caption.removeFromParent();
-                    caption = null;
-                }
-            }
-        }
-
-        public void destroy() {
-            if (caption != null) {
-                caption.removeFromParent();
-            }
-            client.unregisterPaintable(paintable);
-            removeFromParent();
-        }
-
-        public void updateFromUIDL(UIDL componentUIDL) {
-            setPosition(componentUIDL.getStringAttribute("css"));
-            if (getWidget() != paintable) {
-                setWidget((Widget) paintable);
-            }
-            UIDL childUIDL = componentUIDL.getChildUIDL(0);
-            paintable.updateFromUIDL(childUIDL, client);
-            if (childUIDL.hasAttribute("cached")) {
-                // child may need relative size adjustment if wrapper details
-                // have changed this could be optimized (check if wrapper size
-                // has changed)
-                client.handleComponentRelativeSize((Widget) paintable);
-            }
-        }
-
-        public void setPosition(String stringAttribute) {
-            if (css == null || !css.equals(stringAttribute)) {
-                css = stringAttribute;
-                top = right = bottom = left = zIndex = null;
-                if (!css.equals("")) {
-                    String[] properties = css.split(";");
-                    for (int i = 0; i < properties.length; i++) {
-                        String[] keyValue = properties[i].split(":");
-                        if (keyValue[0].equals("left")) {
-                            left = keyValue[1];
-                        } else if (keyValue[0].equals("top")) {
-                            top = keyValue[1];
-                        } else if (keyValue[0].equals("right")) {
-                            right = keyValue[1];
-                        } else if (keyValue[0].equals("bottom")) {
-                            bottom = keyValue[1];
-                        } else if (keyValue[0].equals("z-index")) {
-                            zIndex = keyValue[1];
-                        }
-                    }
-                }
-                // ensure ne values
-                Style style = getElement().getStyle();
-                style.setProperty("zIndex", zIndex);
-                style.setProperty("top", top);
-                style.setProperty("left", left);
-                style.setProperty("right", right);
-                style.setProperty("bottom", bottom);
-
-                if (BrowserInfo.get().isIE6()) {
-                    ie6Layout();
-                }
-            }
-            updateCaptionPosition();
-        }
-
-        private void updateCaptionPosition() {
-            if (caption != null) {
-                Style style = caption.getElement().getStyle();
-                style.setProperty("position", "absolute");
-                style.setPropertyPx("left", getElement().getOffsetLeft());
-                style.setPropertyPx("top", getElement().getOffsetTop()
-                        - caption.getHeight());
-            }
-        }
-
-        private void ie6Layout() {
-            // special handling for IE6 is needed, it does not support
-            // setting both left/right or top/bottom
-            Style style = getElement().getStyle();
-            if (bottom != null && top != null) {
-                // define height for wrapper to simulate bottom property
-                int bottompixels = measureForIE6(bottom);
-                ApplicationConnection.getConsole().log("ALB" + bottompixels);
-                int height = canvas.getOffsetHeight() - bottompixels
-                        - getElement().getOffsetTop();
-                ApplicationConnection.getConsole().log("ALB" + height);
-                if (height < 0) {
-                    height = 0;
-                }
-                style.setPropertyPx("height", height);
-            } else {
-                // reset possibly existing value
-                style.setProperty("height", "");
-            }
-            if (left != null && right != null) {
-                // define width for wrapper to simulate right property
-                int rightPixels = measureForIE6(right);
-                ApplicationConnection.getConsole().log("ALR" + rightPixels);
-                int width = canvas.getOffsetWidth() - rightPixels
-                        - getElement().getOffsetWidth();
-                ApplicationConnection.getConsole().log("ALR" + width);
-                if (width < 0) {
-                    width = 0;
-                }
-                style.setPropertyPx("width", width);
-            } else {
-                // reset possibly existing value
-                style.setProperty("width", "");
-            }
-        }
-
-    }
-
-    private Element measureElement;
-
-    private int measureForIE6(String cssLength) {
-        if (measureElement == null) {
-            measureElement = DOM.createDiv();
-            measureElement.getStyle().setProperty("position", "absolute");
-            canvas.appendChild(measureElement);
-        }
-        measureElement.getStyle().setProperty("width", cssLength);
-        return measureElement.getOffsetWidth();
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IAccordion.java b/src/com/vaadin/terminal/gwt/client/ui/IAccordion.java
deleted file mode 100644 (file)
index 43c92ca..0000000
+++ /dev/null
@@ -1,647 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.ICaption;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderInformation;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class IAccordion extends ITabsheetBase implements
-        ContainerResizedListener {
-
-    public static final String CLASSNAME = "i-accordion";
-
-    private Set<Paintable> paintables = new HashSet<Paintable>();
-
-    private String height;
-
-    private String width = "";
-
-    private HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>();
-
-    private RenderSpace renderSpace = new RenderSpace(0, 0, true);
-
-    private StackItem openTab = null;
-
-    private boolean rendering = false;
-
-    private int selectedUIDLItemIndex = -1;
-
-    private RenderInformation renderInformation = new RenderInformation();
-
-    public IAccordion() {
-        super(CLASSNAME);
-        // IE6 needs this to calculate offsetHeight correctly
-        if (BrowserInfo.get().isIE6()) {
-            DOM.setStyleAttribute(getElement(), "zoom", "1");
-        }
-    }
-
-    @Override
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-        selectedUIDLItemIndex = -1;
-        super.updateFromUIDL(uidl, client);
-        /*
-         * Render content after all tabs have been created and we know how large
-         * the content area is
-         */
-        if (selectedUIDLItemIndex >= 0) {
-            StackItem selectedItem = getStackItem(selectedUIDLItemIndex);
-            UIDL selectedTabUIDL = lazyUpdateMap.remove(selectedItem);
-            open(selectedUIDLItemIndex);
-
-            selectedItem.setContent(selectedTabUIDL);
-        } else if (!uidl.getBooleanAttribute("cached") && openTab != null) {
-            close(openTab);
-        }
-
-        iLayout();
-        // finally render possible hidden tabs
-        if (lazyUpdateMap.size() > 0) {
-            for (Iterator iterator = lazyUpdateMap.keySet().iterator(); iterator
-                    .hasNext();) {
-                StackItem item = (StackItem) iterator.next();
-                item.setContent(lazyUpdateMap.get(item));
-            }
-            lazyUpdateMap.clear();
-        }
-
-        renderInformation.updateSize(getElement());
-
-        rendering = false;
-    }
-
-    @Override
-    protected void renderTab(UIDL tabUidl, int index, boolean selected,
-            boolean hidden) {
-        StackItem item;
-        int itemIndex;
-        if (getWidgetCount() <= index) {
-            // Create stackItem and render caption
-            item = new StackItem(tabUidl);
-            if (getWidgetCount() == 0) {
-                item.addStyleDependentName("first");
-            }
-            itemIndex = getWidgetCount();
-            add(item, getElement());
-        } else {
-            item = getStackItem(index);
-            item = moveStackItemIfNeeded(item, index, tabUidl);
-            itemIndex = index;
-        }
-        item.updateCaption(tabUidl);
-
-        item.setVisible(!hidden);
-
-        if (selected) {
-            selectedUIDLItemIndex = itemIndex;
-        }
-
-        if (tabUidl.getChildCount() > 0) {
-            lazyUpdateMap.put(item, tabUidl.getChildUIDL(0));
-        }
-    }
-
-    /**
-     * This method tries to find out if a tab has been rendered with a different
-     * index previously. If this is the case it re-orders the children so the
-     * same StackItem is used for rendering this time. E.g. if the first tab has
-     * been removed all tabs which contain cached content must be moved 1 step
-     * up to preserve the cached content.
-     * 
-     * @param item
-     * @param newIndex
-     * @param tabUidl
-     * @return
-     */
-    private StackItem moveStackItemIfNeeded(StackItem item, int newIndex,
-            UIDL tabUidl) {
-        UIDL tabContentUIDL = null;
-        Paintable tabContent = null;
-        if (tabUidl.getChildCount() > 0) {
-            tabContentUIDL = tabUidl.getChildUIDL(0);
-            tabContent = client.getPaintable(tabContentUIDL);
-        }
-
-        Widget itemWidget = item.getComponent();
-        if (tabContent != null) {
-            if (tabContent != itemWidget) {
-                /*
-                 * This is not the same widget as before, find out if it has
-                 * been moved
-                 */
-                int oldIndex = -1;
-                StackItem oldItem = null;
-                for (int i = 0; i < getWidgetCount(); i++) {
-                    Widget w = getWidget(i);
-                    oldItem = (StackItem) w;
-                    if (tabContent == oldItem.getComponent()) {
-                        oldIndex = i;
-                        break;
-                    }
-                }
-
-                if (oldIndex != -1 && oldIndex > newIndex) {
-                    /*
-                     * The tab has previously been rendered in another position
-                     * so we must move the cached content to correct position.
-                     * We move only items with oldIndex > newIndex to prevent
-                     * moving items already rendered in this update. If for
-                     * instance tabs 1,2,3 are removed and added as 3,2,1 we
-                     * cannot re-use "1" when we get to the third tab.
-                     */
-                    insert(oldItem, getElement(), newIndex, true);
-                    return oldItem;
-                }
-            }
-        } else {
-            // Tab which has never been loaded. Must assure we use an empty
-            // StackItem
-            Widget oldWidget = item.getComponent();
-            if (oldWidget != null) {
-                item = new StackItem(tabUidl);
-                insert(item, getElement(), newIndex, true);
-            }
-        }
-        return item;
-    }
-
-    private void open(int itemIndex) {
-        StackItem item = (StackItem) getWidget(itemIndex);
-        boolean alreadyOpen = false;
-        if (openTab != null) {
-            if (openTab.isOpen()) {
-                if (openTab == item) {
-                    alreadyOpen = true;
-                } else {
-                    openTab.close();
-                }
-            }
-        }
-
-        if (!alreadyOpen) {
-            item.open();
-            activeTabIndex = itemIndex;
-            openTab = item;
-        }
-
-        // Update the size for the open tab
-        updateOpenTabSize();
-    }
-
-    private void close(StackItem item) {
-        if (!item.isOpen()) {
-            return;
-        }
-
-        item.close();
-        activeTabIndex = -1;
-        openTab = null;
-
-    }
-
-    @Override
-    protected void selectTab(final int index, final UIDL contentUidl) {
-        StackItem item = getStackItem(index);
-        if (index != activeTabIndex) {
-            open(index);
-            iLayout();
-            // TODO Check if this is needed
-            client.runDescendentsLayout(this);
-
-        }
-        item.setContent(contentUidl);
-    }
-
-    public void onSelectTab(StackItem item) {
-        final int index = getWidgetIndex(item);
-        if (index != activeTabIndex && !disabled && !readonly
-                && !disabledTabKeys.contains(tabKeys.get(index))) {
-            addStyleDependentName("loading");
-            client
-                    .updateVariable(id, "selected", "" + tabKeys.get(index),
-                            true);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        super.setWidth(width);
-        this.width = width;
-        if (!rendering) {
-            updateOpenTabSize();
-
-            if (isDynamicHeight()) {
-                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client,
-                        openTab, this);
-                updateOpenTabSize();
-            }
-
-            if (isDynamicHeight()) {
-                openTab.setHeightFromWidget();
-            }
-            iLayout();
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        this.height = height;
-
-        if (!rendering) {
-            updateOpenTabSize();
-        }
-
-    }
-
-    /**
-     * Sets the size of the open tab
-     */
-    private void updateOpenTabSize() {
-        if (openTab == null) {
-            renderSpace.setHeight(0);
-            renderSpace.setWidth(0);
-            return;
-        }
-
-        // WIDTH
-        if (!isDynamicWidth()) {
-            int w = getOffsetWidth();
-            openTab.setWidth(w);
-            renderSpace.setWidth(w);
-        } else {
-            renderSpace.setWidth(0);
-        }
-
-        // HEIGHT
-        if (!isDynamicHeight()) {
-            int usedPixels = 0;
-            for (Widget w : getChildren()) {
-                StackItem item = (StackItem) w;
-                if (item == openTab) {
-                    usedPixels += item.getCaptionHeight();
-                } else {
-                    // This includes the captionNode borders
-                    usedPixels += item.getHeight();
-                }
-            }
-
-            int offsetHeight = getOffsetHeight();
-
-            int spaceForOpenItem = offsetHeight - usedPixels;
-
-            if (spaceForOpenItem < 0) {
-                spaceForOpenItem = 0;
-            }
-
-            renderSpace.setHeight(spaceForOpenItem);
-            openTab.setHeight(spaceForOpenItem);
-        } else {
-            renderSpace.setHeight(0);
-            openTab.setHeightFromWidget();
-
-        }
-
-    }
-
-    public void iLayout() {
-        if (openTab == null) {
-            return;
-        }
-
-        if (isDynamicWidth()) {
-            int maxWidth = 40;
-            for (Widget w : getChildren()) {
-                StackItem si = (StackItem) w;
-                int captionWidth = si.getCaptionWidth();
-                if (captionWidth > maxWidth) {
-                    maxWidth = captionWidth;
-                }
-            }
-            int widgetWidth = openTab.getWidgetWidth();
-            if (widgetWidth > maxWidth) {
-                maxWidth = widgetWidth;
-            }
-            super.setWidth(maxWidth + "px");
-            openTab.setWidth(maxWidth);
-        }
-
-        Util.runWebkitOverflowAutoFix(openTab.getContainerElement());
-
-    }
-
-    /**
-     * 
-     */
-    protected class StackItem extends ComplexPanel implements ClickListener {
-
-        public void setHeight(int height) {
-            if (height == -1) {
-                super.setHeight("");
-                DOM.setStyleAttribute(content, "height", "0px");
-            } else {
-                super.setHeight((height + getCaptionHeight()) + "px");
-                DOM.setStyleAttribute(content, "height", height + "px");
-                DOM
-                        .setStyleAttribute(content, "top", getCaptionHeight()
-                                + "px");
-
-            }
-        }
-
-        public Widget getComponent() {
-            if (getWidgetCount() < 2) {
-                return null;
-            }
-            return getWidget(1);
-        }
-
-        @Override
-        public void setVisible(boolean visible) {
-            super.setVisible(visible);
-        }
-
-        public void setHeightFromWidget() {
-            Widget paintable = getPaintable();
-            if (paintable == null) {
-                return;
-            }
-
-            int paintableHeight = (paintable).getElement().getOffsetHeight();
-            setHeight(paintableHeight);
-
-        }
-
-        /**
-         * Returns caption width including padding
-         * 
-         * @return
-         */
-        public int getCaptionWidth() {
-            if (caption == null) {
-                return 0;
-            }
-
-            int captionWidth = caption.getRequiredWidth();
-            int padding = Util.measureHorizontalPaddingAndBorder(caption
-                    .getElement(), 18);
-            return captionWidth + padding;
-        }
-
-        public void setWidth(int width) {
-            if (width == -1) {
-                super.setWidth("");
-            } else {
-                super.setWidth(width + "px");
-            }
-        }
-
-        public int getHeight() {
-            return getOffsetHeight();
-        }
-
-        public int getCaptionHeight() {
-            return captionNode.getOffsetHeight();
-        }
-
-        private ICaption caption;
-        private boolean open = false;
-        private Element content = DOM.createDiv();
-        private Element captionNode = DOM.createDiv();
-
-        public StackItem(UIDL tabUidl) {
-            setElement(DOM.createDiv());
-            caption = new ICaption(null, client);
-            caption.addClickListener(this);
-            if (BrowserInfo.get().isIE6()) {
-                DOM.setEventListener(captionNode, this);
-                DOM.sinkEvents(captionNode, Event.BUTTON_LEFT);
-            }
-            super.add(caption, captionNode);
-            DOM.appendChild(captionNode, caption.getElement());
-            DOM.appendChild(getElement(), captionNode);
-            DOM.appendChild(getElement(), content);
-            setStylePrimaryName(CLASSNAME + "-item");
-            DOM.setElementProperty(content, "className", CLASSNAME
-                    + "-item-content");
-            DOM.setElementProperty(captionNode, "className", CLASSNAME
-                    + "-item-caption");
-            close();
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            onSelectTab(this);
-        }
-
-        public Element getContainerElement() {
-            return content;
-        }
-
-        public Widget getPaintable() {
-            if (getWidgetCount() > 1) {
-                return getWidget(1);
-            } else {
-                return null;
-            }
-        }
-
-        public void replacePaintable(Paintable newPntbl) {
-            if (getWidgetCount() > 1) {
-                client.unregisterPaintable((Paintable) getWidget(1));
-                paintables.remove(getWidget(1));
-                remove(1);
-            }
-            add((Widget) newPntbl, content);
-            paintables.add(newPntbl);
-        }
-
-        public void open() {
-            open = true;
-            DOM.setStyleAttribute(content, "top", getCaptionHeight() + "px");
-            DOM.setStyleAttribute(content, "left", "0px");
-            DOM.setStyleAttribute(content, "visibility", "");
-            addStyleDependentName("open");
-        }
-
-        public void hide() {
-            DOM.setStyleAttribute(content, "visibility", "hidden");
-        }
-
-        public void close() {
-            DOM.setStyleAttribute(content, "visibility", "hidden");
-            DOM.setStyleAttribute(content, "top", "-100000px");
-            DOM.setStyleAttribute(content, "left", "-100000px");
-            removeStyleDependentName("open");
-            setHeight(-1);
-            open = false;
-        }
-
-        public boolean isOpen() {
-            return open;
-        }
-
-        public void setContent(UIDL contentUidl) {
-            final Paintable newPntbl = client.getPaintable(contentUidl);
-            if (getPaintable() == null) {
-                add((Widget) newPntbl, content);
-                paintables.add(newPntbl);
-            } else if (getPaintable() != newPntbl) {
-                replacePaintable(newPntbl);
-            }
-            newPntbl.updateFromUIDL(contentUidl, client);
-            if (contentUidl.getBooleanAttribute("cached")) {
-                /*
-                 * The size of a cached, relative sized component must be
-                 * updated to report correct size.
-                 */
-                client.handleComponentRelativeSize((Widget) newPntbl);
-            }
-            if (isOpen() && isDynamicHeight()) {
-                setHeightFromWidget();
-            }
-        }
-
-        public void onClick(Widget sender) {
-            onSelectTab(this);
-        }
-
-        public void updateCaption(UIDL uidl) {
-            caption.updateCaption(uidl);
-        }
-
-        public int getWidgetWidth() {
-            return DOM.getFirstChild(content).getOffsetWidth();
-        }
-
-        public boolean contains(Paintable p) {
-            return (getPaintable() == p);
-        }
-
-        public boolean isCaptionVisible() {
-            return caption.isVisible();
-        }
-
-    }
-
-    @Override
-    protected void clearPaintables() {
-        clear();
-    }
-
-    public boolean isDynamicHeight() {
-        return height == null || height.equals("");
-    }
-
-    public boolean isDynamicWidth() {
-        return width == null || width.equals("");
-    }
-
-    @Override
-    protected Iterator getPaintableIterator() {
-        return paintables.iterator();
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (paintables.contains(component)) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        for (Widget w : getChildren()) {
-            StackItem item = (StackItem) w;
-            if (item.getPaintable() == oldComponent) {
-                item.replacePaintable((Paintable) newComponent);
-                return;
-            }
-        }
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        /* Accordion does not render its children's captions */
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        if (!isDynamicHeight() && !isDynamicWidth()) {
-            /*
-             * If the height and width has been specified for this container the
-             * child components cannot make the size of the layout change
-             */
-
-            return true;
-        }
-
-        updateOpenTabSize();
-
-        if (renderInformation.updateSize(getElement())) {
-            /*
-             * Size has changed so we let the child components know about the
-             * new size.
-             */
-            iLayout();
-            // TODO Check if this is needed
-            client.runDescendentsLayout(this);
-
-            return false;
-        } else {
-            /*
-             * Size has not changed so we do not need to propagate the event
-             * further
-             */
-            return true;
-        }
-
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        return renderSpace;
-    }
-
-    @Override
-    protected int getTabCount() {
-        return getWidgetCount();
-    }
-
-    @Override
-    protected void removeTab(int index) {
-        StackItem item = getStackItem(index);
-        remove(item);
-    }
-
-    @Override
-    protected Paintable getTab(int index) {
-        if (index < getWidgetCount()) {
-            return (Paintable) (getStackItem(index)).getPaintable();
-        }
-
-        return null;
-    }
-
-    private StackItem getStackItem(int index) {
-        return (StackItem) getWidget(index);
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IButton.java b/src/com/vaadin/terminal/gwt/client/ui/IButton.java
deleted file mode 100644 (file)
index 4a1dcba..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.ClickListener;
-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.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class IButton extends Button implements Paintable {
-
-    private String width = null;
-
-    public static final String CLASSNAME = "i-button";
-    
-    // Used only for IE, because it doesn't support :active CSS selector
-    private static final String CLASSNAME_DOWN = "i-pressed";
-
-    String id;
-
-    ApplicationConnection client;
-
-    private Element errorIndicatorElement;
-
-    private final Element captionElement = DOM.createSpan();
-
-    private Icon icon;
-
-    /**
-     * Helper flat to handle special-case where the button is moved from under
-     * mouse while clicking it. In this case mouse leaves the button without
-     * moving.
-     */
-    private boolean clickPending;
-
-    public IButton() {
-        setStyleName(CLASSNAME);
-
-        DOM.appendChild(getElement(), captionElement);
-
-        addClickListener(new ClickListener() {
-            public void onClick(Widget sender) {
-                if (id == null || client == null) {
-                    return;
-                }
-                /*
-                 * TODO isolate workaround. Safari don't always seem to fire
-                 * onblur previously focused component before button is clicked.
-                 */
-                IButton.this.setFocus(true);
-                client.updateVariable(id, "state", true, true);
-                clickPending = false;
-            }
-        });
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-        sinkEvents(Event.ONMOUSEDOWN);
-        sinkEvents(Event.ONMOUSEUP);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
-        // Ensure correct implementation,
-        // but don't let container manage caption etc.
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-
-        // Save details
-        this.client = client;
-        id = uidl.getId();
-
-        // Set text
-        setText(uidl.getStringAttribute("caption"));
-
-        // handle error
-        if (uidl.hasAttribute("error")) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "i-errorindicator");
-            }
-            DOM.insertChild(getElement(), errorIndicatorElement, 0);
-
-            // Fix for IE6, IE7
-            if (BrowserInfo.get().isIE()) {
-                DOM.setInnerText(errorIndicatorElement, " ");
-            }
-
-        } else if (errorIndicatorElement != null) {
-            DOM.removeChild(getElement(), errorIndicatorElement);
-            errorIndicatorElement = null;
-        }
-
-        if (uidl.hasAttribute("readonly")) {
-            setEnabled(false);
-        }
-
-        if (uidl.hasAttribute("icon")) {
-            if (icon == null) {
-                icon = new Icon(client);
-                DOM.insertChild(getElement(), icon.getElement(), 0);
-            }
-            icon.setUri(uidl.getStringAttribute("icon"));
-        } else {
-            if (icon != null) {
-                DOM.removeChild(getElement(), icon.getElement());
-                icon = null;
-            }
-        }
-        if (BrowserInfo.get().isIE7()) {
-            if (width.equals("")) {
-                setWidth(getOffsetWidth() + "px");
-            }
-        }
-    }
-
-    @Override
-    public void setText(String text) {
-        DOM.setInnerText(captionElement, text);
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-
-        if (DOM.eventGetType(event) == Event.ONLOAD) {
-            Util.notifyParentOfSizeChange(this, true);
-
-        } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN
-                && event.getButton() == Event.BUTTON_LEFT) {
-            clickPending = true;
-            if (BrowserInfo.get().isIE()) {
-               // Only for IE, because it doesn't support :active CSS selector
-               // Simple check is cheaper than DOM manipulation
-                addStyleName(CLASSNAME_DOWN);
-            }
-        } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) {
-            clickPending = false;
-        } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
-            if (clickPending) {
-                click();
-            }
-            if (BrowserInfo.get().isIE()) {
-                removeStyleName(CLASSNAME_DOWN);
-            }
-            clickPending = false;
-        } else if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
-            if (BrowserInfo.get().isIE()) {
-                removeStyleName(CLASSNAME_DOWN);
-            }
-        }
-
-        if (client != null) {
-            client.handleTooltipEvent(event, this);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        /* Workaround for IE7 button size part 1 (#2014) */
-        if (BrowserInfo.get().isIE7() && this.width != null) {
-            if (this.width.equals(width)) {
-                return;
-            }
-
-            if (width == null) {
-                width = "";
-            }
-        }
-
-        this.width = width;
-        super.setWidth(width);
-
-        /* Workaround for IE7 button size part 2 (#2014) */
-        if (BrowserInfo.get().isIE7()) {
-            super.setWidth(width);
-        }
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ICalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/ICalendarPanel.java
deleted file mode 100644 (file)
index 31566a7..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Date;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.Event;\r
-import com.google.gwt.user.client.Timer;\r
-import com.google.gwt.user.client.ui.FlexTable;\r
-import com.google.gwt.user.client.ui.MouseListener;\r
-import com.google.gwt.user.client.ui.MouseListenerCollection;\r
-import com.google.gwt.user.client.ui.SourcesMouseEvents;\r
-import com.google.gwt.user.client.ui.SourcesTableEvents;\r
-import com.google.gwt.user.client.ui.TableListener;\r
-import com.google.gwt.user.client.ui.Widget;\r
-import com.vaadin.terminal.gwt.client.DateTimeService;\r
-import com.vaadin.terminal.gwt.client.LocaleService;\r
-\r
-public class ICalendarPanel extends FlexTable implements MouseListener {\r
-\r
-    private final IDateField datefield;\r
-\r
-    private IEventButton prevYear;\r
-\r
-    private IEventButton nextYear;\r
-\r
-    private IEventButton prevMonth;\r
-\r
-    private IEventButton nextMonth;\r
-\r
-    private ITime time;\r
-\r
-    private Date minDate = null;\r
-\r
-    private Date maxDate = null;\r
-\r
-    private CalendarEntrySource entrySource;\r
-\r
-    /* Needed to identify resolution changes */\r
-    private int resolution = IDateField.RESOLUTION_YEAR;\r
-\r
-    /* Needed to identify locale changes */\r
-    private String locale = LocaleService.getDefaultLocale();\r
-\r
-    public ICalendarPanel(IDateField parent) {\r
-        datefield = parent;\r
-        setStyleName(IDateField.CLASSNAME + "-calendarpanel");\r
-        // buildCalendar(true);\r
-        addTableListener(new DateClickListener(this));\r
-    }\r
-\r
-    public ICalendarPanel(IDateField parent, Date min, Date max) {\r
-        datefield = parent;\r
-        setStyleName(IDateField.CLASSNAME + "-calendarpanel");\r
-        // buildCalendar(true);\r
-        addTableListener(new DateClickListener(this));\r
-\r
-    }\r
-\r
-    private void buildCalendar(boolean forceRedraw) {\r
-        final boolean needsMonth = datefield.getCurrentResolution() > IDateField.RESOLUTION_YEAR;\r
-        boolean needsBody = datefield.getCurrentResolution() >= IDateField.RESOLUTION_DAY;\r
-        final boolean needsTime = datefield.getCurrentResolution() >= IDateField.RESOLUTION_HOUR;\r
-        forceRedraw = prevYear == null ? true : forceRedraw;\r
-        buildCalendarHeader(forceRedraw, needsMonth);\r
-        clearCalendarBody(!needsBody);\r
-        if (needsBody) {\r
-            buildCalendarBody();\r
-        }\r
-        if (needsTime) {\r
-            buildTime(forceRedraw);\r
-        } else if (time != null) {\r
-            remove(time);\r
-            time = null;\r
-        }\r
-    }\r
-\r
-    private void clearCalendarBody(boolean remove) {\r
-        if (!remove) {\r
-            for (int row = 2; row < 8; row++) {\r
-                for (int col = 0; col < 7; col++) {\r
-                    setHTML(row, col, "&nbsp;");\r
-                }\r
-            }\r
-        } else if (getRowCount() > 2) {\r
-            while (getRowCount() > 2) {\r
-                removeRow(2);\r
-            }\r
-        }\r
-    }\r
-\r
-    private void buildCalendarHeader(boolean forceRedraw, boolean needsMonth) {\r
-        if (forceRedraw) {\r
-            if (prevMonth == null) { // Only do once\r
-                prevYear = new IEventButton();\r
-                prevYear.setHTML("&laquo;");\r
-                prevYear.setStyleName("i-button-prevyear");\r
-                nextYear = new IEventButton();\r
-                nextYear.setHTML("&raquo;");\r
-                nextYear.setStyleName("i-button-nextyear");\r
-                prevYear.addMouseListener(this);\r
-                nextYear.addMouseListener(this);\r
-                setWidget(0, 0, prevYear);\r
-                setWidget(0, 4, nextYear);\r
-\r
-                if (needsMonth) {\r
-                    prevMonth = new IEventButton();\r
-                    prevMonth.setHTML("&lsaquo;");\r
-                    prevMonth.setStyleName("i-button-prevmonth");\r
-                    nextMonth = new IEventButton();\r
-                    nextMonth.setHTML("&rsaquo;");\r
-                    nextMonth.setStyleName("i-button-nextmonth");\r
-                    prevMonth.addMouseListener(this);\r
-                    nextMonth.addMouseListener(this);\r
-                    setWidget(0, 3, nextMonth);\r
-                    setWidget(0, 1, prevMonth);\r
-                }\r
-\r
-                getFlexCellFormatter().setColSpan(0, 2, 3);\r
-                getRowFormatter().addStyleName(0,\r
-                        IDateField.CLASSNAME + "-calendarpanel-header");\r
-            } else if (!needsMonth) {\r
-                // Remove month traverse buttons\r
-                prevMonth.removeMouseListener(this);\r
-                nextMonth.removeMouseListener(this);\r
-                remove(prevMonth);\r
-                remove(nextMonth);\r
-                prevMonth = null;\r
-                nextMonth = null;\r
-            }\r
-\r
-            // Print weekday names\r
-            final int firstDay = datefield.getDateTimeService()\r
-                    .getFirstDayOfWeek();\r
-            for (int i = 0; i < 7; i++) {\r
-                int day = i + firstDay;\r
-                if (day > 6) {\r
-                    day = 0;\r
-                }\r
-                if (datefield.getCurrentResolution() > IDateField.RESOLUTION_MONTH) {\r
-                    setHTML(1, i, "<strong>"\r
-                            + datefield.getDateTimeService().getShortDay(day)\r
-                            + "</strong>");\r
-                } else {\r
-                    setHTML(1, i, "");\r
-                }\r
-            }\r
-        }\r
-\r
-        final String monthName = needsMonth ? datefield.getDateTimeService()\r
-                .getMonth(datefield.getShowingDate().getMonth()) : "";\r
-        final int year = datefield.getShowingDate().getYear() + 1900;\r
-        setHTML(0, 2, "<span class=\"" + IDateField.CLASSNAME\r
-                + "-calendarpanel-month\">" + monthName + " " + year\r
-                + "</span>");\r
-    }\r
-\r
-    private void buildCalendarBody() {\r
-        // date actually selected?\r
-        Date currentDate = datefield.getCurrentDate();\r
-        Date showing = datefield.getShowingDate();\r
-        boolean selected = (currentDate != null\r
-                && currentDate.getMonth() == showing.getMonth() && currentDate\r
-                .getYear() == showing.getYear());\r
-\r
-        final int startWeekDay = datefield.getDateTimeService()\r
-                .getStartWeekDay(datefield.getShowingDate());\r
-        final int numDays = DateTimeService.getNumberOfDaysInMonth(datefield\r
-                .getShowingDate());\r
-        int dayCount = 0;\r
-        final Date today = new Date();\r
-        final Date curr = new Date(datefield.getShowingDate().getTime());\r
-        for (int row = 2; row < 8; row++) {\r
-            for (int col = 0; col < 7; col++) {\r
-                if (!(row == 2 && col < startWeekDay)) {\r
-                    if (dayCount < numDays) {\r
-                        final int selectedDate = ++dayCount;\r
-                        String title = "";\r
-                        if (entrySource != null) {\r
-                            curr.setDate(dayCount);\r
-                            final List entries = entrySource.getEntries(curr,\r
-                                    IDateField.RESOLUTION_DAY);\r
-                            if (entries != null) {\r
-                                for (final Iterator it = entries.iterator(); it\r
-                                        .hasNext();) {\r
-                                    final CalendarEntry entry = (CalendarEntry) it\r
-                                            .next();\r
-                                    title += (title.length() > 0 ? ", " : "")\r
-                                            + entry.getStringForDate(curr);\r
-                                }\r
-                            }\r
-                        }\r
-                        final String baseclass = IDateField.CLASSNAME\r
-                                + "-calendarpanel-day";\r
-                        String cssClass = baseclass;\r
-                        if (!isEnabledDate(curr)) {\r
-                            cssClass += " " + baseclass + "-disabled";\r
-                        }\r
-                        if (selected\r
-                                && datefield.getShowingDate().getDate() == dayCount) {\r
-                            cssClass += " " + baseclass + "-selected";\r
-                        }\r
-                        if (today.getDate() == dayCount\r
-                                && today.getMonth() == datefield\r
-                                        .getShowingDate().getMonth()\r
-                                && today.getYear() == datefield\r
-                                        .getShowingDate().getYear()) {\r
-                            cssClass += " " + baseclass + "-today";\r
-                        }\r
-                        if (title.length() > 0) {\r
-                            cssClass += " " + baseclass + "-entry";\r
-                        }\r
-                        setHTML(row, col, "<span title=\"" + title\r
-                                + "\" class=\"" + cssClass + "\">"\r
-                                + selectedDate + "</span>");\r
-                    } else {\r
-                        break;\r
-                    }\r
-\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    private void buildTime(boolean forceRedraw) {\r
-        if (time == null) {\r
-            time = new ITime(datefield);\r
-            setText(8, 0, ""); // Add new row\r
-            getFlexCellFormatter().setColSpan(8, 0, 7);\r
-            setWidget(8, 0, time);\r
-        }\r
-        time.updateTime(forceRedraw);\r
-    }\r
-\r
-    /**\r
-     * \r
-     * @param forceRedraw\r
-     *            Build all from scratch, in case of e.g. locale changes\r
-     */\r
-    public void updateCalendar() {\r
-        // Locale and resolution changes force a complete redraw\r
-        buildCalendar(locale != datefield.getCurrentLocale()\r
-                || resolution != datefield.getCurrentResolution());\r
-        if (datefield instanceof ITextualDate) {\r
-            ((ITextualDate) datefield).buildDate();\r
-        }\r
-        locale = datefield.getCurrentLocale();\r
-        resolution = datefield.getCurrentResolution();\r
-    }\r
-\r
-    private boolean isEnabledDate(Date date) {\r
-        if ((minDate != null && date.before(minDate))\r
-                || (maxDate != null && date.after(maxDate))) {\r
-            return false;\r
-        }\r
-        return true;\r
-    }\r
-\r
-    private void processClickEvent(Widget sender, boolean updateVariable) {\r
-        if (!datefield.isEnabled() || datefield.isReadonly()) {\r
-            return;\r
-        }\r
-        Date showingDate = datefield.getShowingDate();\r
-        if (!updateVariable) {\r
-            if (sender == prevYear) {\r
-                showingDate.setYear(showingDate.getYear() - 1);\r
-                updateCalendar();\r
-            } else if (sender == nextYear) {\r
-                showingDate.setYear(showingDate.getYear() + 1);\r
-                updateCalendar();\r
-            } else if (sender == prevMonth) {\r
-                int currentMonth = showingDate.getMonth();\r
-                showingDate.setMonth(currentMonth - 1);\r
-\r
-                /*\r
-                 * If the selected date was e.g. 31.12 the new date would be\r
-                 * 31.11 but this date is invalid so the new date will be 1.12.\r
-                 * This is taken care of by decreasing the date until we have\r
-                 * the correct month.\r
-                 */\r
-                while (showingDate.getMonth() == currentMonth) {\r
-                    showingDate.setDate(showingDate.getDate() - 1);\r
-                }\r
-\r
-                updateCalendar();\r
-            } else if (sender == nextMonth) {\r
-                int currentMonth = showingDate.getMonth();\r
-                showingDate.setMonth(currentMonth + 1);\r
-                int requestedMonth = (currentMonth + 1) % 12;\r
-\r
-                /*\r
-                 * If the selected date was e.g. 31.3 the new date would be 31.4\r
-                 * but this date is invalid so the new date will be 1.5. This is\r
-                 * taken care of by decreasing the date until we have the\r
-                 * correct month.\r
-                 */\r
-                while (showingDate.getMonth() != requestedMonth) {\r
-                    showingDate.setDate(showingDate.getDate() - 1);\r
-                }\r
-\r
-                updateCalendar();\r
-            }\r
-        } else {\r
-            if (datefield.getCurrentResolution() == IDateField.RESOLUTION_YEAR\r
-                    || datefield.getCurrentResolution() == IDateField.RESOLUTION_MONTH) {\r
-                // Due to current UI, update variable if res=year/month\r
-                datefield.setCurrentDate(new Date(showingDate.getTime()));\r
-                if (datefield.getCurrentResolution() == IDateField.RESOLUTION_MONTH) {\r
-                    datefield.getClient().updateVariable(datefield.getId(),\r
-                            "month", datefield.getCurrentDate().getMonth() + 1,\r
-                            false);\r
-                }\r
-                datefield.getClient().updateVariable(datefield.getId(), "year",\r
-                        datefield.getCurrentDate().getYear() + 1900,\r
-                        datefield.isImmediate());\r
-\r
-                /* Must update the value in the textfield also */\r
-                updateCalendar();\r
-            }\r
-        }\r
-    }\r
-\r
-    private Timer timer;\r
-\r
-    public void onMouseDown(final Widget sender, int x, int y) {\r
-        // Allow user to click-n-hold for fast-forward or fast-rewind.\r
-        // Timer is first used for a 500ms delay after mousedown. After that has\r
-        // elapsed, another timer is triggered to go off every 150ms. Both\r
-        // timers are cancelled on mouseup or mouseout.\r
-        if (sender instanceof IEventButton) {\r
-            processClickEvent(sender, false);\r
-            timer = new Timer() {\r
-                @Override\r
-                public void run() {\r
-                    timer = new Timer() {\r
-                        @Override\r
-                        public void run() {\r
-                            processClickEvent(sender, false);\r
-                        }\r
-                    };\r
-                    timer.scheduleRepeating(150);\r
-                }\r
-            };\r
-            timer.schedule(500);\r
-        }\r
-    }\r
-\r
-    public void onMouseEnter(Widget sender) {\r
-    }\r
-\r
-    public void onMouseLeave(Widget sender) {\r
-        if (timer != null) {\r
-            timer.cancel();\r
-        }\r
-    }\r
-\r
-    public void onMouseMove(Widget sender, int x, int y) {\r
-    }\r
-\r
-    public void onMouseUp(Widget sender, int x, int y) {\r
-        if (timer != null) {\r
-            timer.cancel();\r
-        }\r
-        processClickEvent(sender, true);\r
-    }\r
-\r
-    private class IEventButton extends IButton implements SourcesMouseEvents {\r
-\r
-        private MouseListenerCollection mouseListeners;\r
-\r
-        public IEventButton() {\r
-            super();\r
-            sinkEvents(Event.FOCUSEVENTS | Event.KEYEVENTS | Event.ONCLICK\r
-                    | Event.MOUSEEVENTS);\r
-        }\r
-\r
-        public void addMouseListener(MouseListener listener) {\r
-            if (mouseListeners == null) {\r
-                mouseListeners = new MouseListenerCollection();\r
-            }\r
-            mouseListeners.add(listener);\r
-        }\r
-\r
-        public void removeMouseListener(MouseListener listener) {\r
-            if (mouseListeners != null) {\r
-                mouseListeners.remove(listener);\r
-            }\r
-        }\r
-\r
-        @Override\r
-        public void onBrowserEvent(Event event) {\r
-            super.onBrowserEvent(event);\r
-            switch (DOM.eventGetType(event)) {\r
-            case Event.ONMOUSEDOWN:\r
-            case Event.ONMOUSEUP:\r
-            case Event.ONMOUSEMOVE:\r
-            case Event.ONMOUSEOVER:\r
-            case Event.ONMOUSEOUT:\r
-                if (mouseListeners != null) {\r
-                    mouseListeners.fireMouseEvent(this, event);\r
-                }\r
-                break;\r
-            }\r
-        }\r
-    }\r
-\r
-    private class DateClickListener implements TableListener {\r
-\r
-        private final ICalendarPanel cal;\r
-\r
-        public DateClickListener(ICalendarPanel panel) {\r
-            cal = panel;\r
-        }\r
-\r
-        public void onCellClicked(SourcesTableEvents sender, int row, int col) {\r
-            if (sender != cal || row < 2 || row > 7\r
-                    || !cal.datefield.isEnabled() || cal.datefield.isReadonly()) {\r
-                return;\r
-            }\r
-\r
-            final String text = cal.getText(row, col);\r
-            if (text.equals(" ")) {\r
-                return;\r
-            }\r
-\r
-            try {\r
-                final Integer day = new Integer(text);\r
-                final Date newDate = cal.datefield.getShowingDate();\r
-                newDate.setDate(day.intValue());\r
-                if (!isEnabledDate(newDate)) {\r
-                    return;\r
-                }\r
-                if (cal.datefield.getCurrentDate() == null) {\r
-                    cal.datefield.setCurrentDate(new Date(newDate.getTime()));\r
-\r
-                    // Init variables with current time\r
-                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                            "hour", newDate.getHours(), false);\r
-                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                            "min", newDate.getMinutes(), false);\r
-                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                            "sec", newDate.getSeconds(), false);\r
-                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                            "msec", datefield.getMilliseconds(), false);\r
-                }\r
-\r
-                cal.datefield.getCurrentDate().setTime(newDate.getTime());\r
-                cal.datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                        "day", cal.datefield.getCurrentDate().getDate(), false);\r
-                cal.datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                        "month", cal.datefield.getCurrentDate().getMonth() + 1,\r
-                        false);\r
-                cal.datefield.getClient().updateVariable(cal.datefield.getId(),\r
-                        "year",\r
-                        cal.datefield.getCurrentDate().getYear() + 1900,\r
-                        cal.datefield.isImmediate());\r
-\r
-                if (datefield instanceof ITextualDate\r
-                        && resolution < IDateField.RESOLUTION_HOUR) {\r
-                    ((IToolkitOverlay) getParent()).hide();\r
-                } else {\r
-                    updateCalendar();\r
-                }\r
-\r
-            } catch (final NumberFormatException e) {\r
-                // Not a number, ignore and stop here\r
-                return;\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    public void setLimits(Date min, Date max) {\r
-        if (min != null) {\r
-            final Date d = new Date(min.getTime());\r
-            d.setHours(0);\r
-            d.setMinutes(0);\r
-            d.setSeconds(1);\r
-            minDate = d;\r
-        } else {\r
-            minDate = null;\r
-        }\r
-        if (max != null) {\r
-            final Date d = new Date(max.getTime());\r
-            d.setHours(24);\r
-            d.setMinutes(59);\r
-            d.setSeconds(59);\r
-            maxDate = d;\r
-        } else {\r
-            maxDate = null;\r
-        }\r
-    }\r
-\r
-    public void setCalendarEntrySource(CalendarEntrySource entrySource) {\r
-        this.entrySource = entrySource;\r
-    }\r
-\r
-    public CalendarEntrySource getCalendarEntrySource() {\r
-        return entrySource;\r
-    }\r
-\r
-    public interface CalendarEntrySource {\r
-        public List getEntries(Date date, int resolution);\r
-    }\r
-\r
-    /**\r
-     * Sets focus to Calendar panel.\r
-     * \r
-     * @param focus\r
-     */\r
-    public void setFocus(boolean focus) {\r
-        nextYear.setFocus(focus);\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ICheckBox.java b/src/com/vaadin/terminal/gwt/client/ui/ICheckBox.java
deleted file mode 100644 (file)
index 397dc89..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class ICheckBox extends com.google.gwt.user.client.ui.CheckBox implements
-        Paintable, Field {
-
-    public static final String CLASSNAME = "i-checkbox";
-
-    String id;
-
-    boolean immediate;
-
-    ApplicationConnection client;
-
-    private Element errorIndicatorElement;
-
-    private Icon icon;
-
-    private boolean isBlockMode = false;
-
-    public ICheckBox() {
-        setStyleName(CLASSNAME);
-        addClickListener(new ClickListener() {
-
-            public void onClick(Widget sender) {
-                if (id == null || client == null) {
-                    return;
-                }
-                client.updateVariable(id, "state", isChecked(), immediate);
-            }
-
-        });
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-        Element el = DOM.getFirstChild(getElement());
-        while (el != null) {
-            DOM.sinkEvents(el,
-                    (DOM.getEventsSunk(el) | ITooltip.TOOLTIP_EVENTS));
-            el = DOM.getNextSibling(el);
-        }
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // Save details
-        this.client = client;
-        id = uidl.getId();
-
-        // Ensure correct implementation
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-
-        if (uidl.hasAttribute("error")) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                errorIndicatorElement.setInnerHTML("&nbsp;");
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "i-errorindicator");
-                DOM.appendChild(getElement(), errorIndicatorElement);
-                DOM.sinkEvents(errorIndicatorElement, ITooltip.TOOLTIP_EVENTS
-                        | Event.ONCLICK);
-            }
-        } else if (errorIndicatorElement != null) {
-            DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
-        }
-
-        if (uidl.hasAttribute("readonly")) {
-            setEnabled(false);
-        }
-
-        if (uidl.hasAttribute("icon")) {
-            if (icon == null) {
-                icon = new Icon(client);
-                DOM.insertChild(getElement(), icon.getElement(), 1);
-                icon.sinkEvents(ITooltip.TOOLTIP_EVENTS);
-                icon.sinkEvents(Event.ONCLICK);
-            }
-            icon.setUri(uidl.getStringAttribute("icon"));
-        } else if (icon != null) {
-            // detach icon
-            DOM.removeChild(getElement(), icon.getElement());
-            icon = null;
-        }
-
-        // Set text
-        setText(uidl.getStringAttribute("caption"));
-        setChecked(uidl.getBooleanVariable("state"));
-        immediate = uidl.getBooleanAttribute("immediate");
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        if (icon != null && (event.getTypeInt() == Event.ONCLICK)
-                && (event.getTarget() == icon.getElement())) {
-            setChecked(!isChecked());
-        }
-        super.onBrowserEvent(event);
-        if (event.getTypeInt() == Event.ONLOAD) {
-            Util.notifyParentOfSizeChange(this, true);
-        }
-        if (client != null) {
-            client.handleTooltipEvent(event, this);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        setBlockMode();
-        super.setWidth(width);
-    }
-
-    @Override
-    public void setHeight(String height) {
-        setBlockMode();
-        super.setHeight(height);
-    }
-
-    /**
-     * makes container element (span) to be block element to enable sizing.
-     */
-    private void setBlockMode() {
-        if (!isBlockMode) {
-            DOM.setStyleAttribute(getElement(), "display", "block");
-            isBlockMode = true;
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IContextMenu.java b/src/com/vaadin/terminal/gwt/client/ui/IContextMenu.java
deleted file mode 100644 (file)
index 5dc2e98..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.TableRowElement;
-import com.google.gwt.dom.client.TableSectionElement;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.MenuBar;
-import com.google.gwt.user.client.ui.MenuItem;
-import com.google.gwt.user.client.ui.PopupPanel;
-
-public class IContextMenu extends IToolkitOverlay implements SubPartAware {
-
-    private ActionOwner actionOwner;
-
-    private final CMenuBar menu = new CMenuBar();
-
-    private int left;
-
-    private int top;
-
-    /**
-     * This method should be used only by Client object as only one per client
-     * should exists. Request an instance via client.getContextMenu();
-     * 
-     * @param cli
-     *            to be set as an owner of menu
-     */
-    public IContextMenu() {
-        super(true, false, true);
-        setWidget(menu);
-        setStyleName("i-contextmenu");
-    }
-
-    /**
-     * Sets the element from which to build menu
-     * 
-     * @param ao
-     */
-    public void setActionOwner(ActionOwner ao) {
-        actionOwner = ao;
-    }
-
-    /**
-     * Shows context menu at given location.
-     * 
-     * @param left
-     * @param top
-     */
-    public void showAt(int left, int top) {
-        this.left = left;
-        this.top = top;
-        menu.clearItems();
-        final Action[] actions = actionOwner.getActions();
-        for (int i = 0; i < actions.length; i++) {
-            final Action a = actions[i];
-            menu.addItem(new MenuItem(a.getHTML(), true, a));
-        }
-
-        setPopupPositionAndShow(new PositionCallback() {
-            public void setPosition(int offsetWidth, int offsetHeight) {
-                // mac FF gets bad width due GWT popups overflow hacks,
-                // re-determine width
-                offsetWidth = menu.getOffsetWidth();
-                int left = IContextMenu.this.left;
-                int top = IContextMenu.this.top;
-                if (offsetWidth + left > Window.getClientWidth()) {
-                    left = left - offsetWidth;
-                    if (left < 0) {
-                        left = 0;
-                    }
-                }
-                if (offsetHeight + top > Window.getClientHeight()) {
-                    top = top - offsetHeight;
-                    if (top < 0) {
-                        top = 0;
-                    }
-                }
-                setPopupPosition(left, top);
-            }
-        });
-    }
-
-    public void showAt(ActionOwner ao, int left, int top) {
-        setActionOwner(ao);
-        showAt(left, top);
-    }
-
-    /**
-     * Extend standard Gwt MenuBar to set proper settings and to override
-     * onPopupClosed method so that PopupPanel gets closed.
-     */
-    class CMenuBar extends MenuBar {
-        public CMenuBar() {
-            super(true);
-        }
-
-        @Override
-        public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
-            super.onPopupClosed(sender, autoClosed);
-            hide();
-        }
-
-        /*
-         * public void onBrowserEvent(Event event) { // Remove current selection
-         * when mouse leaves if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
-         * Element to = DOM.eventGetToElement(event); if
-         * (!DOM.isOrHasChild(getElement(), to)) { DOM.setElementProperty(
-         * super.getSelectedItem().getElement(), "className",
-         * super.getSelectedItem().getStylePrimaryName()); } }
-         * 
-         * super.onBrowserEvent(event); }
-         */
-    }
-
-    public Element getSubPartElement(String subPart) {
-        int index = Integer.parseInt(subPart.substring(6));
-        // ApplicationConnection.getConsole().log(
-        // "Searching element for selection index " + index);
-        Element wrapperdiv = menu.getElement();
-        com.google.gwt.dom.client.TableSectionElement tBody = (TableSectionElement) wrapperdiv
-                .getFirstChildElement().getFirstChildElement();
-        TableRowElement item = tBody.getRows().getItem(index);
-        com.google.gwt.dom.client.Element clickableDivElement = item
-                .getFirstChildElement().getFirstChildElement();
-        return clickableDivElement.cast();
-    }
-
-    public String getSubPartName(Element subElement) {
-        if (getElement().isOrHasChild(subElement)) {
-            com.google.gwt.dom.client.Element e = subElement;
-            {
-                while (e != null && !e.getTagName().toLowerCase().equals("tr")) {
-                    e = e.getParentElement();
-                    // ApplicationConnection.getConsole().log("Found row");
-                }
-            }
-            com.google.gwt.dom.client.TableSectionElement parentElement = (TableSectionElement) e
-                    .getParentElement();
-            NodeList<TableRowElement> rows = parentElement.getRows();
-            for (int i = 0; i < rows.getLength(); i++) {
-                if (rows.getItem(i) == e) {
-                    // ApplicationConnection.getConsole().log(
-                    // "Found index for row" + 1);
-                    return "option" + i;
-                }
-            }
-            return null;
-        } else {
-            return null;
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ICustomComponent.java b/src/com/vaadin/terminal/gwt/client/ui/ICustomComponent.java
deleted file mode 100644 (file)
index 1e92111..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Set;
-
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class ICustomComponent extends SimplePanel implements Container {
-
-    private static final String CLASSNAME = "i-customcomponent";
-    private String height;
-    private ApplicationConnection client;
-    private boolean rendering;
-    private String width;
-    private RenderSpace renderSpace = new RenderSpace();
-
-    public ICustomComponent() {
-        super();
-        setStyleName(CLASSNAME);
-    }
-
-    public void updateFromUIDL(UIDL uidl, final ApplicationConnection client) {
-        rendering = true;
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-        this.client = client;
-
-        final UIDL child = uidl.getChildUIDL(0);
-        if (child != null) {
-            final Paintable p = client.getPaintable(child);
-            if (p != getWidget()) {
-                if (getWidget() != null) {
-                    client.unregisterPaintable((Paintable) getWidget());
-                    clear();
-                }
-                setWidget((Widget) p);
-            }
-            p.updateFromUIDL(child, client);
-        }
-
-        boolean updateDynamicSize = updateDynamicSize();
-        if (updateDynamicSize) {
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    // FIXME deferred relative size update needed to fix some
-                    // scrollbar issues in sampler. This must be the wrong way
-                    // to do it. Might be that some other component is broken.
-                    client.handleComponentRelativeSize(ICustomComponent.this);
-
-                }
-            });
-        }
-
-        renderSpace.setWidth(getElement().getOffsetWidth());
-        renderSpace.setHeight(getElement().getOffsetHeight());
-
-        rendering = false;
-    }
-
-    private boolean updateDynamicSize() {
-        boolean updated = false;
-        if (isDynamicWidth()) {
-            int childWidth = Util.getRequiredWidth(getWidget());
-            getElement().getStyle().setPropertyPx("width", childWidth);
-            updated = true;
-        }
-        if (isDynamicHeight()) {
-            int childHeight = Util.getRequiredHeight(getWidget());
-            getElement().getStyle().setPropertyPx("height", childHeight);
-            updated = true;
-        }
-
-        return updated;
-    }
-
-    private boolean isDynamicWidth() {
-        return width == null || width.equals("");
-    }
-
-    private boolean isDynamicHeight() {
-        return height == null || height.equals("");
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (getWidget() == component) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        if (hasChildComponent(oldComponent)) {
-            clear();
-            setWidget(newComponent);
-        } else {
-            throw new IllegalStateException();
-        }
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        // NOP, custom component dont render composition roots caption
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        return !updateDynamicSize();
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        return renderSpace;
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        renderSpace.setHeight(getElement().getOffsetHeight());
-
-        if (!height.equals(this.height)) {
-            this.height = height;
-            if (!rendering) {
-                client.runDescendentsLayout(this);
-            }
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        super.setWidth(width);
-        renderSpace.setWidth(getElement().getOffsetWidth());
-
-        if (!width.equals(this.width)) {
-            this.width = width;
-            if (!rendering) {
-                client.runDescendentsLayout(this);
-            }
-        }
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ICustomLayout.java b/src/com/vaadin/terminal/gwt/client/ui/ICustomLayout.java
deleted file mode 100644 (file)
index ac7827f..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.dom.client.ImageElement;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.ICaption;
-import com.vaadin.terminal.gwt.client.ICaptionWrapper;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
-
-/**
- * Custom Layout implements complex layout defined with HTML template.
- * 
- * @author IT Mill
- * 
- */
-public class ICustomLayout extends ComplexPanel implements Paintable,
-        Container, ContainerResizedListener {
-
-    public static final String CLASSNAME = "i-customlayout";
-
-    /** Location-name to containing element in DOM map */
-    private final HashMap locationToElement = new HashMap();
-
-    /** Location-name to contained widget map */
-    private final HashMap<String, Widget> locationToWidget = new HashMap<String, Widget>();
-
-    /** Widget to captionwrapper map */
-    private final HashMap widgetToCaptionWrapper = new HashMap();
-
-    /** Name of the currently rendered style */
-    String currentTemplateName;
-
-    /** Unexecuted scripts loaded from the template */
-    private String scripts = "";
-
-    /** Paintable ID of this paintable */
-    private String pid;
-
-    private ApplicationConnection client;
-
-    /** Has the template been loaded from contents passed in UIDL **/
-    private boolean hasTemplateContents = false;
-
-    private Element elementWithNativeResizeFunction;
-
-    private String height = "";
-
-    private String width = "";
-
-    private HashMap<String, FloatSize> locationToExtraSize = new HashMap<String, FloatSize>();
-
-    public ICustomLayout() {
-        setElement(DOM.createDiv());
-        // Clear any unwanted styling
-        DOM.setStyleAttribute(getElement(), "border", "none");
-        DOM.setStyleAttribute(getElement(), "margin", "0");
-        DOM.setStyleAttribute(getElement(), "padding", "0");
-
-        if (BrowserInfo.get().isIE()) {
-            DOM.setStyleAttribute(getElement(), "position", "relative");
-        }
-
-        setStyleName(CLASSNAME);
-    }
-
-    /**
-     * Sets widget to given location.
-     * 
-     * If location already contains a widget it will be removed.
-     * 
-     * @param widget
-     *            Widget to be set into location.
-     * @param location
-     *            location name where widget will be added
-     * 
-     * @throws IllegalArgumentException
-     *             if no such location is found in the layout.
-     */
-    public void setWidget(Widget widget, String location) {
-
-        if (widget == null) {
-            return;
-        }
-
-        // If no given location is found in the layout, and exception is throws
-        Element elem = (Element) locationToElement.get(location);
-        if (elem == null && hasTemplate()) {
-            throw new IllegalArgumentException("No location " + location
-                    + " found");
-        }
-
-        // Get previous widget
-        final Widget previous = locationToWidget.get(location);
-        // NOP if given widget already exists in this location
-        if (previous == widget) {
-            return;
-        }
-
-        if (previous != null) {
-            remove(previous);
-        }
-
-        // if template is missing add element in order
-        if (!hasTemplate()) {
-            elem = getElement();
-        }
-
-        // Add widget to location
-        super.add(widget, elem);
-        locationToWidget.put(location, widget);
-    }
-
-    /** Update the layout from UIDL */
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-        // ApplicationConnection manages generic component features
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        pid = uidl.getId();
-        if (!hasTemplate()) {
-            // Update HTML template only once
-            initializeHTML(uidl, client);
-        }
-
-        // Evaluate scripts
-        eval(scripts);
-        scripts = null;
-
-        iLayout();
-        // TODO Check if this is needed
-        client.runDescendentsLayout(this);
-
-        Set oldWidgets = new HashSet();
-        oldWidgets.addAll(locationToWidget.values());
-
-        // For all contained widgets
-        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
-            final UIDL uidlForChild = (UIDL) i.next();
-            if (uidlForChild.getTag().equals("location")) {
-                final String location = uidlForChild.getStringAttribute("name");
-                final Paintable child = client.getPaintable(uidlForChild
-                        .getChildUIDL(0));
-                try {
-                    setWidget((Widget) child, location);
-                    child.updateFromUIDL(uidlForChild.getChildUIDL(0), client);
-                } catch (final IllegalArgumentException e) {
-                    // If no location is found, this component is not visible
-                }
-                oldWidgets.remove(child);
-            }
-        }
-        for (Iterator iterator = oldWidgets.iterator(); iterator.hasNext();) {
-            Widget oldWidget = (Widget) iterator.next();
-            if (oldWidget.isAttached()) {
-                // slot of this widget is emptied, remove it
-                remove(oldWidget);
-            }
-        }
-
-        iLayout();
-        // TODO Check if this is needed
-        client.runDescendentsLayout(this);
-
-    }
-
-    /** Initialize HTML-layout. */
-    private void initializeHTML(UIDL uidl, ApplicationConnection client) {
-
-        final String newTemplateContents = uidl
-                .getStringAttribute("templateContents");
-        final String newTemplate = uidl.getStringAttribute("template");
-
-        currentTemplateName = null;
-        hasTemplateContents = false;
-
-        String template = "";
-        if (newTemplate != null) {
-            // Get the HTML-template from client
-            template = client.getResource("layouts/" + newTemplate + ".html");
-            if (template == null) {
-                template = "<em>Layout file layouts/"
-                        + newTemplate
-                        + ".html is missing. Components will be drawn for debug purposes.</em>";
-            } else {
-                currentTemplateName = newTemplate;
-            }
-        } else {
-            hasTemplateContents = true;
-            template = newTemplateContents;
-        }
-
-        // Connect body of the template to DOM
-        template = extractBodyAndScriptsFromTemplate(template);
-
-        // TODO prefix img src:s here with a regeps, cannot work further with IE
-
-        String themeUri = client.getThemeUri();
-        String relImgPrefix = themeUri + "/layouts/";
-
-        // prefix all relative image elements to point to theme dir with a
-        // regexp search
-        template = template.replaceAll(
-                "<((?:img)|(?:IMG))\\s([^>]*)src=\"((?![a-z]+:)[^/][^\"]+)\"",
-                "<$1 $2src=\"" + relImgPrefix + "$3\"");
-        // also support src attributes without quotes
-        template = template
-                .replaceAll(
-                        "<((?:img)|(?:IMG))\\s([^>]*)src=[^\"]((?![a-z]+:)[^/][^ />]+)[ />]",
-                        "<$1 $2src=\"" + relImgPrefix + "$3\"");
-        // also prefix relative style="...url(...)..."
-        template = template
-                .replaceAll(
-                        "(<[^>]+style=\"[^\"]*url\\()((?![a-z]+:)[^/][^\"]+)(\\)[^>]*>)",
-                        "$1 " + relImgPrefix + "$2 $3");
-
-        getElement().setInnerHTML(template);
-
-        // Remap locations to elements
-        locationToElement.clear();
-        scanForLocations(getElement());
-
-        initImgElements();
-
-        elementWithNativeResizeFunction = DOM.getFirstChild(getElement());
-        if (elementWithNativeResizeFunction == null) {
-            elementWithNativeResizeFunction = getElement();
-        }
-        publishResizedFunction(elementWithNativeResizeFunction);
-
-    }
-
-    private native boolean uriEndsWithSlash()
-    /*-{
-        var path =  $wnd.location.pathname;
-        if(path.charAt(path.length - 1) == "/")
-            return true;
-        return false;
-    }-*/;
-
-    private boolean hasTemplate() {
-        if (currentTemplateName == null && !hasTemplateContents) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    /** Collect locations from template */
-    private void scanForLocations(Element elem) {
-
-        final String location = elem.getAttribute("location");
-        if (!"".equals(location)) {
-            locationToElement.put(location, elem);
-            elem.setInnerHTML("");
-            int x = Util.measureHorizontalPaddingAndBorder(elem, 0);
-            int y = Util.measureVerticalPaddingAndBorder(elem, 0);
-
-            FloatSize fs = new FloatSize(x, y);
-
-            locationToExtraSize.put(location, fs);
-
-        } else {
-            final int len = DOM.getChildCount(elem);
-            for (int i = 0; i < len; i++) {
-                scanForLocations(DOM.getChild(elem, i));
-            }
-        }
-    }
-
-    /** Evaluate given script in browser document */
-    private static native void eval(String script)
-    /*-{
-      try {
-        if (script != null) 
-      eval("{ var document = $doc; var window = $wnd; "+ script + "}");
-      } catch (e) {
-      }
-    }-*/;
-
-    /**
-     * Img elements needs some special handling in custom layout. Img elements
-     * will get their onload events sunk. This way custom layout can notify
-     * parent about possible size change.
-     */
-    private void initImgElements() {
-        NodeList<com.google.gwt.dom.client.Element> nodeList = getElement()
-                .getElementsByTagName("IMG");
-        for (int i = 0; i < nodeList.getLength(); i++) {
-            com.google.gwt.dom.client.ImageElement img = (ImageElement) nodeList
-                    .getItem(i);
-            DOM.sinkEvents((Element) img.cast(), Event.ONLOAD);
-        }
-    }
-
-    /**
-     * Extract body part and script tags from raw html-template.
-     * 
-     * Saves contents of all script-tags to private property: scripts. Returns
-     * contents of the body part for the html without script-tags. Also replaces
-     * all _UID_ tags with an unique id-string.
-     * 
-     * @param html
-     *            Original HTML-template received from server
-     * @return html that is used to create the HTMLPanel.
-     */
-    private String extractBodyAndScriptsFromTemplate(String html) {
-
-        // Replace UID:s
-        html = html.replaceAll("_UID_", pid + "__");
-
-        // Exctract script-tags
-        scripts = "";
-        int endOfPrevScript = 0;
-        int nextPosToCheck = 0;
-        String lc = html.toLowerCase();
-        String res = "";
-        int scriptStart = lc.indexOf("<script", nextPosToCheck);
-        while (scriptStart > 0) {
-            res += html.substring(endOfPrevScript, scriptStart);
-            scriptStart = lc.indexOf(">", scriptStart);
-            final int j = lc.indexOf("</script>", scriptStart);
-            scripts += html.substring(scriptStart + 1, j) + ";";
-            nextPosToCheck = endOfPrevScript = j + "</script>".length();
-            scriptStart = lc.indexOf("<script", nextPosToCheck);
-        }
-        res += html.substring(endOfPrevScript);
-
-        // Extract body
-        html = res;
-        lc = html.toLowerCase();
-        int startOfBody = lc.indexOf("<body");
-        if (startOfBody < 0) {
-            res = html;
-        } else {
-            res = "";
-            startOfBody = lc.indexOf(">", startOfBody) + 1;
-            final int endOfBody = lc.indexOf("</body>", startOfBody);
-            if (endOfBody > startOfBody) {
-                res = html.substring(startOfBody, endOfBody);
-            } else {
-                res = html.substring(startOfBody);
-            }
-        }
-
-        return res;
-    }
-
-    /** Replace child components */
-    public void replaceChildComponent(Widget from, Widget to) {
-        final String location = getLocation(from);
-        if (location == null) {
-            throw new IllegalArgumentException();
-        }
-        setWidget(to, location);
-    }
-
-    /** Does this layout contain given child */
-    public boolean hasChildComponent(Widget component) {
-        return locationToWidget.containsValue(component);
-    }
-
-    /** Update caption for given widget */
-    public void updateCaption(Paintable component, UIDL uidl) {
-        ICaptionWrapper wrapper = (ICaptionWrapper) widgetToCaptionWrapper
-                .get(component);
-        if (ICaption.isNeeded(uidl)) {
-            if (wrapper == null) {
-                final String loc = getLocation((Widget) component);
-                super.remove((Widget) component);
-                wrapper = new ICaptionWrapper(component, client);
-                super.add(wrapper, (Element) locationToElement.get(loc));
-                widgetToCaptionWrapper.put(component, wrapper);
-            }
-            wrapper.updateCaption(uidl);
-        } else {
-            if (wrapper != null) {
-                final String loc = getLocation((Widget) component);
-                super.remove(wrapper);
-                super.add((Widget) wrapper.getPaintable(),
-                        (Element) locationToElement.get(loc));
-                widgetToCaptionWrapper.remove(component);
-            }
-        }
-    }
-
-    /** Get the location of an widget */
-    public String getLocation(Widget w) {
-        for (final Iterator i = locationToWidget.keySet().iterator(); i
-                .hasNext();) {
-            final String location = (String) i.next();
-            if (locationToWidget.get(location) == w) {
-                return location;
-            }
-        }
-        return null;
-    }
-
-    /** Removes given widget from the layout */
-    @Override
-    public boolean remove(Widget w) {
-        client.unregisterPaintable((Paintable) w);
-        final String location = getLocation(w);
-        if (location != null) {
-            locationToWidget.remove(location);
-        }
-        final ICaptionWrapper cw = (ICaptionWrapper) widgetToCaptionWrapper
-                .get(w);
-        if (cw != null) {
-            widgetToCaptionWrapper.remove(w);
-            return super.remove(cw);
-        } else if (w != null) {
-            return super.remove(w);
-        }
-        return false;
-    }
-
-    /** Adding widget without specifying location is not supported */
-    @Override
-    public void add(Widget w) {
-        throw new UnsupportedOperationException();
-    }
-
-    /** Clear all widgets from the layout */
-    @Override
-    public void clear() {
-        super.clear();
-        locationToWidget.clear();
-        widgetToCaptionWrapper.clear();
-    }
-
-    public void iLayout() {
-        iLayoutJS(DOM.getFirstChild(getElement()));
-    }
-
-    /**
-     * This method is published to JS side with the same name into first DOM
-     * node of custom layout. This way if one implements some resizeable
-     * containers in custom layout he/she can notify children after resize.
-     */
-    public void notifyChildrenOfSizeChange() {
-        client.runDescendentsLayout(this);
-    }
-
-    @Override
-    public void onDetach() {
-        super.onDetach();
-        detachResizedFunction(elementWithNativeResizeFunction);
-    }
-
-    private native void detachResizedFunction(Element element)
-    /*-{
-       element.notifyChildrenOfSizeChange = null;
-    }-*/;
-
-    private native void publishResizedFunction(Element element)
-    /*-{
-       var self = this;
-       element.notifyChildrenOfSizeChange = function() {
-               self.@com.vaadin.terminal.gwt.client.ui.ICustomLayout::notifyChildrenOfSizeChange()();
-       };
-    }-*/;
-
-    /**
-     * In custom layout one may want to run layout functions made with
-     * JavaScript. This function tests if one exists (with name "iLayoutJS" in
-     * layouts first DOM node) and runs et. Return value is used to determine if
-     * children needs to be notified of size changes.
-     * 
-     * Note! When implementing a JS layout function you most likely want to call
-     * notifyChildrenOfSizeChange() function on your custom layouts main
-     * element. That method is used to control whether child components layout
-     * functions are to be run.
-     * 
-     * @param el
-     * @return true if layout function exists and was run successfully, else
-     *         false.
-     */
-    private native boolean iLayoutJS(Element el)
-    /*-{
-       if(el && el.iLayoutJS) {
-               try {
-                       el.iLayoutJS();
-                       return true;
-               } catch (e) {
-                       return false;
-               }
-       } else {
-               return false;
-       }
-    }-*/;
-
-    public boolean requestLayout(Set<Paintable> child) {
-        updateRelativeSizedComponents(true, true);
-
-        if (width.equals("") || height.equals("")) {
-            /* Automatically propagated upwards if the size can change */
-            return false;
-        }
-
-        return true;
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        com.google.gwt.dom.client.Element pe = child.getElement()
-                .getParentElement();
-
-        FloatSize extra = locationToExtraSize.get(getLocation(child));
-        return new RenderSpace(pe.getOffsetWidth() - (int) extra.getWidth(), pe
-                .getOffsetHeight()
-                - (int) extra.getHeight(), Util.mayHaveScrollBars(pe));
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        if (event.getTypeInt() == Event.ONLOAD) {
-            Util.notifyParentOfSizeChange(this, true);
-            event.cancelBubble(true);
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        if (this.height.equals(height)) {
-            return;
-        }
-
-        boolean shrinking = true;
-        if (isLarger(height, this.height)) {
-            shrinking = false;
-        }
-
-        this.height = height;
-        super.setHeight(height);
-
-        /*
-         * If the height shrinks we must remove all components with relative
-         * height from the DOM, update their height when they do not affect the
-         * available space and finally restore them to the original state
-         */
-        if (shrinking) {
-            updateRelativeSizedComponents(false, true);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        boolean shrinking = true;
-        if (isLarger(width, this.width)) {
-            shrinking = false;
-        }
-
-        super.setWidth(width);
-        this.width = width;
-
-        /*
-         * If the width shrinks we must remove all components with relative
-         * width from the DOM, update their width when they do not affect the
-         * available space and finally restore them to the original state
-         */
-        if (shrinking) {
-            updateRelativeSizedComponents(true, false);
-        }
-    }
-
-    private void updateRelativeSizedComponents(boolean relativeWidth,
-            boolean relativeHeight) {
-
-        Set<Widget> relativeSizeWidgets = new HashSet<Widget>();
-
-        for (Widget widget : locationToWidget.values()) {
-            FloatSize relativeSize = client.getRelativeSize(widget);
-            if (relativeSize != null) {
-                if ((relativeWidth && (relativeSize.getWidth() >= 0.0f))
-                        || (relativeHeight && (relativeSize.getHeight() >= 0.0f))) {
-
-                    relativeSizeWidgets.add(widget);
-                    widget.getElement().getStyle().setProperty("position",
-                            "absolute");
-                }
-            }
-        }
-
-        for (Widget widget : relativeSizeWidgets) {
-            client.handleComponentRelativeSize(widget);
-            widget.getElement().getStyle().setProperty("position", "");
-        }
-    }
-
-    /**
-     * Compares newSize with currentSize and returns true if it is clear that
-     * newSize is larger than currentSize. Returns false if newSize is smaller
-     * or if it is unclear which one is smaller.
-     * 
-     * @param newSize
-     * @param currentSize
-     * @return
-     */
-    private boolean isLarger(String newSize, String currentSize) {
-        if (newSize.equals("") || currentSize.equals("")) {
-            return false;
-        }
-
-        if (!newSize.endsWith("px") || !currentSize.endsWith("px")) {
-            return false;
-        }
-
-        int newSizePx = Integer.parseInt(newSize.substring(0,
-                newSize.length() - 2));
-        int currentSizePx = Integer.parseInt(currentSize.substring(0,
-                currentSize.length() - 2));
-
-        boolean larger = newSizePx > currentSizePx;
-        return larger;
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IDateField.java b/src/com/vaadin/terminal/gwt/client/ui/IDateField.java
deleted file mode 100644 (file)
index b62def2..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Date;\r
-\r
-import com.google.gwt.user.client.Event;\r
-import com.google.gwt.user.client.ui.FlowPanel;\r
-import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
-import com.vaadin.terminal.gwt.client.ClientExceptionHandler;\r
-import com.vaadin.terminal.gwt.client.DateTimeService;\r
-import com.vaadin.terminal.gwt.client.ITooltip;\r
-import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;\r
-import com.vaadin.terminal.gwt.client.Paintable;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class IDateField extends FlowPanel implements Paintable, Field {\r
-\r
-    public static final String CLASSNAME = "i-datefield";\r
-\r
-    protected String id;\r
-\r
-    protected ApplicationConnection client;\r
-\r
-    protected boolean immediate;\r
-\r
-    public static final int RESOLUTION_YEAR = 0;\r
-    public static final int RESOLUTION_MONTH = 1;\r
-    public static final int RESOLUTION_DAY = 2;\r
-    public static final int RESOLUTION_HOUR = 3;\r
-    public static final int RESOLUTION_MIN = 4;\r
-    public static final int RESOLUTION_SEC = 5;\r
-    public static final int RESOLUTION_MSEC = 6;\r
-\r
-    protected int currentResolution = RESOLUTION_YEAR;\r
-\r
-    protected String currentLocale;\r
-\r
-    protected boolean readonly;\r
-\r
-    protected boolean enabled;\r
-\r
-    protected Date date = null;\r
-    // e.g when paging a calendar, before actually selecting\r
-    protected Date showingDate = new Date();\r
-\r
-    protected DateTimeService dts;\r
-\r
-    public IDateField() {\r
-        setStyleName(CLASSNAME);\r
-        dts = new DateTimeService();\r
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);\r
-    }\r
-\r
-    @Override\r
-    public void onBrowserEvent(Event event) {\r
-        super.onBrowserEvent(event);\r
-        if (client != null) {\r
-            client.handleTooltipEvent(event, this);\r
-        }\r
-    }\r
-\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        // Ensure correct implementation and let layout manage caption\r
-        if (client.updateComponent(this, uidl, true)) {\r
-            return;\r
-        }\r
-\r
-        // Save details\r
-        this.client = client;\r
-        id = uidl.getId();\r
-        immediate = uidl.getBooleanAttribute("immediate");\r
-\r
-        readonly = uidl.getBooleanAttribute("readonly");\r
-        enabled = !uidl.getBooleanAttribute("disabled");\r
-\r
-        if (uidl.hasAttribute("locale")) {\r
-            final String locale = uidl.getStringAttribute("locale");\r
-            try {\r
-                dts.setLocale(locale);\r
-                currentLocale = locale;\r
-            } catch (final LocaleNotLoadedException e) {\r
-                currentLocale = dts.getLocale();\r
-                ClientExceptionHandler.displayError(\r
-                        "Tried to use an unloaded locale \"" + locale\r
-                                + "\". Using default locale (" + currentLocale\r
-                                + ").", e);\r
-            }\r
-        }\r
-\r
-        int newResolution;\r
-        if (uidl.hasVariable("msec")) {\r
-            newResolution = RESOLUTION_MSEC;\r
-        } else if (uidl.hasVariable("sec")) {\r
-            newResolution = RESOLUTION_SEC;\r
-        } else if (uidl.hasVariable("min")) {\r
-            newResolution = RESOLUTION_MIN;\r
-        } else if (uidl.hasVariable("hour")) {\r
-            newResolution = RESOLUTION_HOUR;\r
-        } else if (uidl.hasVariable("day")) {\r
-            newResolution = RESOLUTION_DAY;\r
-        } else if (uidl.hasVariable("month")) {\r
-            newResolution = RESOLUTION_MONTH;\r
-        } else {\r
-            newResolution = RESOLUTION_YEAR;\r
-        }\r
-\r
-        currentResolution = newResolution;\r
-\r
-        final int year = uidl.getIntVariable("year");\r
-        final int month = (currentResolution >= RESOLUTION_MONTH) ? uidl\r
-                .getIntVariable("month") : -1;\r
-        final int day = (currentResolution >= RESOLUTION_DAY) ? uidl\r
-                .getIntVariable("day") : -1;\r
-        final int hour = (currentResolution >= RESOLUTION_HOUR) ? uidl\r
-                .getIntVariable("hour") : 0;\r
-        final int min = (currentResolution >= RESOLUTION_MIN) ? uidl\r
-                .getIntVariable("min") : 0;\r
-        final int sec = (currentResolution >= RESOLUTION_SEC) ? uidl\r
-                .getIntVariable("sec") : 0;\r
-        final int msec = (currentResolution >= RESOLUTION_MSEC) ? uidl\r
-                .getIntVariable("msec") : 0;\r
-\r
-        // Construct new date for this datefield (only if not null)\r
-        if (year > -1) {\r
-            date = new Date((long) getTime(year, month, day, hour, min, sec,\r
-                    msec));\r
-            showingDate.setTime(date.getTime());\r
-        } else {\r
-            date = null;\r
-            showingDate = new Date();\r
-        }\r
-\r
-    }\r
-\r
-    /*\r
-     * We need this redundant native function because Java's Date object doesn't\r
-     * have a setMilliseconds method.\r
-     */\r
-    private static native double getTime(int y, int m, int d, int h, int mi,\r
-            int s, int ms)\r
-    /*-{\r
-       try {\r
-               var date = new Date(2000,1,1,1); // don't use current date here\r
-               if(y && y >= 0) date.setFullYear(y);\r
-               if(m && m >= 1) date.setMonth(m-1);\r
-               if(d && d >= 0) date.setDate(d);\r
-               if(h >= 0) date.setHours(h);\r
-               if(mi >= 0) date.setMinutes(mi);\r
-               if(s >= 0) date.setSeconds(s);\r
-               if(ms >= 0) date.setMilliseconds(ms);\r
-               return date.getTime();\r
-       } catch (e) {\r
-               // TODO print some error message on the console\r
-               //console.log(e);\r
-               return (new Date()).getTime();\r
-       }\r
-    }-*/;\r
-\r
-    public int getMilliseconds() {\r
-        return (int) (date.getTime() - date.getTime() / 1000 * 1000);\r
-    }\r
-\r
-    public void setMilliseconds(int ms) {\r
-        date.setTime(date.getTime() / 1000 * 1000 + ms);\r
-    }\r
-\r
-    public int getShowingMilliseconds() {\r
-        return (int) (showingDate.getTime() - showingDate.getTime() / 1000 * 1000);\r
-    }\r
-\r
-    public void setShowingMilliseconds(int ms) {\r
-        showingDate.setTime(showingDate.getTime() / 1000 * 1000 + ms);\r
-    }\r
-\r
-    public int getCurrentResolution() {\r
-        return currentResolution;\r
-    }\r
-\r
-    public void setCurrentResolution(int currentResolution) {\r
-        this.currentResolution = currentResolution;\r
-    }\r
-\r
-    public String getCurrentLocale() {\r
-        return currentLocale;\r
-    }\r
-\r
-    public void setCurrentLocale(String currentLocale) {\r
-        this.currentLocale = currentLocale;\r
-    }\r
-\r
-    public Date getCurrentDate() {\r
-        return date;\r
-    }\r
-\r
-    public void setCurrentDate(Date date) {\r
-        this.date = date;\r
-    }\r
-\r
-    public Date getShowingDate() {\r
-        return showingDate;\r
-    }\r
-\r
-    public void setShowingDate(Date date) {\r
-        showingDate = date;\r
-    }\r
-\r
-    public boolean isImmediate() {\r
-        return immediate;\r
-    }\r
-\r
-    public boolean isReadonly() {\r
-        return readonly;\r
-    }\r
-\r
-    public boolean isEnabled() {\r
-        return enabled;\r
-    }\r
-\r
-    public DateTimeService getDateTimeService() {\r
-        return dts;\r
-    }\r
-\r
-    public String getId() {\r
-        return id;\r
-    }\r
-\r
-    public ApplicationConnection getClient() {\r
-        return client;\r
-    }\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/IDateFieldCalendar.java
deleted file mode 100644 (file)
index 24f6147..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class IDateFieldCalendar extends IDateField {\r
-\r
-    private final ICalendarPanel date;\r
-\r
-    public IDateFieldCalendar() {\r
-        super();\r
-        date = new ICalendarPanel(this);\r
-        add(date);\r
-    }\r
-\r
-    @Override\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        super.updateFromUIDL(uidl, client);\r
-        date.updateCalendar();\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/IEmbedded.java
deleted file mode 100644 (file)
index 8c8340b..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Iterator;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Node;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.ObjectElement;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.HTML;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class IEmbedded extends HTML implements Paintable {
-    private static String CLASSNAME = "i-embedded";
-
-    private String height;
-    private String width;
-    private Element browserElement;
-
-    private ApplicationConnection client;
-
-    public IEmbedded() {
-        setStyleName(CLASSNAME);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-        this.client = client;
-
-        boolean clearBrowserElement = true;
-
-        if (uidl.hasAttribute("type")) {
-            final String type = uidl.getStringAttribute("type");
-            if (type.equals("image")) {
-                Element el = null;
-                boolean created = false;
-                NodeList nodes = getElement().getChildNodes();
-                if (nodes != null && nodes.getLength() == 1) {
-                    Node n = nodes.getItem(0);
-                    if (n.getNodeType() == Node.ELEMENT_NODE) {
-                        Element e = (Element) n;
-                        if (e.getTagName().equals("IMG")) {
-                            el = e;
-                        }
-                    }
-                }
-                if (el == null) {
-                    setHTML("");
-                    el = DOM.createImg();
-                    created = true;
-                    client.addPngFix(el);
-                    DOM.sinkEvents(el, Event.ONLOAD);
-                }
-
-                // Set attributes
-                Style style = el.getStyle();
-                String w = uidl.getStringAttribute("width");
-                if (w != null) {
-                    style.setProperty("width", w);
-                } else {
-                    style.setProperty("width", "");
-                }
-                String h = uidl.getStringAttribute("height");
-                if (h != null) {
-                    style.setProperty("height", h);
-                } else {
-                    style.setProperty("height", "");
-                }
-                DOM.setElementProperty(el, "src", getSrc(uidl, client));
-
-                if (created) {
-                    // insert in dom late
-                    getElement().appendChild(el);
-                }
-
-            } else if (type.equals("browser")) {
-                if (browserElement == null) {
-                    setHTML("<iframe width=\"100%\" height=\"100%\" frameborder=\"0\" src=\""
-                            + getSrc(uidl, client)
-                            + "\" name=\""
-                            + uidl.getId() + "\"></iframe>");
-                    browserElement = DOM.getFirstChild(getElement());
-                } else {
-                    DOM.setElementAttribute(browserElement, "src", getSrc(uidl,
-                            client));
-                }
-                clearBrowserElement = false;
-            } else {
-                ApplicationConnection.getConsole().log(
-                        "Unknown Embedded type '" + type + "'");
-            }
-        } else if (uidl.hasAttribute("mimetype")) {
-            final String mime = uidl.getStringAttribute("mimetype");
-            if (mime.equals("application/x-shockwave-flash")) {
-                setHTML("<object width=\"" + width + "\" height=\"" + height
-                        + "\"><param name=\"movie\" value=\""
-                        + getSrc(uidl, client) + "\"><embed src=\""
-                        + getSrc(uidl, client) + "\" width=\"" + width
-                        + "\" height=\"" + height + "\"></embed></object>");
-            } else if (mime.equals("image/svg+xml")) {
-                String data;
-                if (getParameter("data", uidl) == null) {
-                    data = getSrc(uidl, client);
-                } else {
-                    data = "data:image/svg+xml," + getParameter("data", uidl);
-                }
-                setHTML("");
-                ObjectElement obj = Document.get().createObjectElement();
-                obj.setType(mime);
-                obj.setData(data);
-                if (width != null) {
-                    obj.getStyle().setProperty("width", "100%");
-                }
-                if (height != null) {
-                    obj.getStyle().setProperty("height", "100%");
-                }
-                getElement().appendChild(obj);
-
-            } else {
-                ApplicationConnection.getConsole().log(
-                        "Unknown Embedded mimetype '" + mime + "'");
-            }
-        } else {
-            ApplicationConnection.getConsole().log(
-                    "Unknown Embedded; no type or mimetype attribute");
-        }
-
-        if (clearBrowserElement) {
-            browserElement = null;
-        }
-
-    }
-
-    private static String getParameter(String paramName, UIDL uidl) {
-        Iterator childIterator = uidl.getChildIterator();
-        while (childIterator.hasNext()) {
-            Object child = childIterator.next();
-            if (child instanceof UIDL) {
-                UIDL childUIDL = (UIDL) child;
-                if (childUIDL.getTag().equals("embeddedparam")
-                        && childUIDL.getStringAttribute("name").equals(
-                                paramName)) {
-                    return childUIDL.getStringAttribute("value");
-                }
-
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Helper to return translated src-attribute from embedded's UIDL
-     * 
-     * @param uidl
-     * @param client
-     * @return
-     */
-    private String getSrc(UIDL uidl, ApplicationConnection client) {
-        String url = client.translateToolkitUri(uidl.getStringAttribute("src"));
-        if (url == null) {
-            return "";
-        }
-        return url;
-    }
-
-    @Override
-    public void setWidth(String width) {
-        this.width = width;
-        if (isDynamicHeight()) {
-            int oldHeight = getOffsetHeight();
-            super.setWidth(width);
-            int newHeight = getOffsetHeight();
-            /*
-             * Must notify parent if the height changes as a result of a width
-             * change
-             */
-            if (oldHeight != newHeight) {
-                Util.notifyParentOfSizeChange(this, false);
-            }
-        } else {
-            super.setWidth(width);
-        }
-
-    }
-
-    private boolean isDynamicHeight() {
-        return height == null || height.equals("");
-    }
-
-    @Override
-    public void setHeight(String height) {
-        this.height = height;
-        super.setHeight(height);
-    }
-
-    @Override
-    protected void onDetach() {
-        // Force browser to fire unload event when component is detached from
-        // the view (IE doesn't do this automatically)
-        if (browserElement != null) {
-            DOM.setElementAttribute(browserElement, "src", "javascript:false");
-        }
-        super.onDetach();
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        if (DOM.eventGetType(event) == Event.ONLOAD) {
-            Util.notifyParentOfSizeChange(this, true);
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/IFilterSelect.java
deleted file mode 100644 (file)
index ec9ecf1..0000000
+++ /dev/null
@@ -1,1059 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-
-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.ClickListener;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.FocusListener;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.KeyboardListener;
-import com.google.gwt.user.client.ui.LoadListener;
-import com.google.gwt.user.client.ui.PopupListener;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.TextBox;
-import com.google.gwt.user.client.ui.Widget;
-import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
-import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-/**
- * 
- * TODO needs major refactoring (to be extensible etc)
- */
-public class IFilterSelect extends Composite implements Paintable, Field,
-        KeyboardListener, ClickListener, FocusListener, Focusable {
-
-    public class FilterSelectSuggestion implements Suggestion, Command {
-
-        private final String key;
-        private final String caption;
-        private String iconUri;
-
-        public FilterSelectSuggestion(UIDL uidl) {
-            key = uidl.getStringAttribute("key");
-            caption = uidl.getStringAttribute("caption");
-            if (uidl.hasAttribute("icon")) {
-                iconUri = client.translateToolkitUri(uidl
-                        .getStringAttribute("icon"));
-            }
-        }
-
-        public String getDisplayString() {
-            final StringBuffer sb = new StringBuffer();
-            if (iconUri != null) {
-                sb.append("<img src=\"");
-                sb.append(iconUri);
-                sb.append("\" alt=\"\" class=\"i-icon\" />");
-            }
-            sb.append("<span>" + Util.escapeHTML(caption) + "</span>");
-            return sb.toString();
-        }
-
-        public String getReplacementString() {
-            return caption;
-        }
-
-        public int getOptionKey() {
-            return Integer.parseInt(key);
-        }
-
-        public String getIconUri() {
-            return iconUri;
-        }
-
-        public void execute() {
-            onSuggestionSelected(this);
-        }
-    }
-
-    public class SuggestionPopup extends IToolkitOverlay implements
-            PositionCallback, PopupListener {
-
-        private static final String Z_INDEX = "30000";
-
-        private final SuggestionMenu menu;
-
-        private final Element up = DOM.createDiv();
-        private final Element down = DOM.createDiv();
-        private final Element status = DOM.createDiv();
-
-        private boolean isPagingEnabled = true;
-
-        private long lastAutoClosed;
-
-        private int popupOuterPadding = -1;
-
-        private int topPosition;
-
-        SuggestionPopup() {
-            super(true, false, true);
-            menu = new SuggestionMenu();
-            setWidget(menu);
-            setStyleName(CLASSNAME + "-suggestpopup");
-            DOM.setStyleAttribute(getElement(), "zIndex", Z_INDEX);
-
-            final Element root = getContainerElement();
-
-            DOM.setInnerHTML(up, "<span>Prev</span>");
-            DOM.sinkEvents(up, Event.ONCLICK);
-            DOM.setInnerHTML(down, "<span>Next</span>");
-            DOM.sinkEvents(down, Event.ONCLICK);
-            DOM.insertChild(root, up, 0);
-            DOM.appendChild(root, down);
-            DOM.appendChild(root, status);
-            DOM.setElementProperty(status, "className", CLASSNAME + "-status");
-
-            addPopupListener(this);
-        }
-
-        public void showSuggestions(
-                Collection<FilterSelectSuggestion> currentSuggestions,
-                int currentPage, int totalSuggestions) {
-
-            // Add TT anchor point
-            DOM.setElementProperty(getElement(), "id",
-                    "TOOLKIT_COMBOBOX_OPTIONLIST");
-
-            menu.setSuggestions(currentSuggestions);
-            final int x = IFilterSelect.this.getAbsoluteLeft();
-            topPosition = tb.getAbsoluteTop();
-            topPosition += tb.getOffsetHeight();
-            setPopupPosition(x, topPosition);
-
-            final int first = currentPage * PAGELENTH
-                    + (nullSelectionAllowed && currentPage > 0 ? 0 : 1);
-            final int last = first + currentSuggestions.size() - 1;
-            final int matches = totalSuggestions
-                    - (nullSelectionAllowed ? 1 : 0);
-            if (last > 0) {
-                // nullsel not counted, as requested by user
-                DOM.setInnerText(status, (matches == 0 ? 0 : first)
-                        + "-"
-                        + ("".equals(lastFilter) && nullSelectionAllowed
-                                && currentPage == 0 ? last - 1 : last) + "/"
-                        + matches);
-            } else {
-                DOM.setInnerText(status, "");
-            }
-            // We don't need to show arrows or statusbar if there is only one
-            // page
-            if (matches <= PAGELENTH) {
-                setPagingEnabled(false);
-            } else {
-                setPagingEnabled(true);
-            }
-            setPrevButtonActive(first > 1);
-            setNextButtonActive(last < matches);
-
-            // clear previously fixed width
-            menu.setWidth("");
-            DOM.setStyleAttribute(DOM.getFirstChild(menu.getElement()),
-                    "width", "");
-
-            setPopupPositionAndShow(this);
-        }
-
-        private void setNextButtonActive(boolean b) {
-            if (b) {
-                DOM.sinkEvents(down, Event.ONCLICK);
-                DOM.setElementProperty(down, "className", CLASSNAME
-                        + "-nextpage");
-            } else {
-                DOM.sinkEvents(down, 0);
-                DOM.setElementProperty(down, "className", CLASSNAME
-                        + "-nextpage-off");
-            }
-        }
-
-        private void setPrevButtonActive(boolean b) {
-            if (b) {
-                DOM.sinkEvents(up, Event.ONCLICK);
-                DOM
-                        .setElementProperty(up, "className", CLASSNAME
-                                + "-prevpage");
-            } else {
-                DOM.sinkEvents(up, 0);
-                DOM.setElementProperty(up, "className", CLASSNAME
-                        + "-prevpage-off");
-            }
-
-        }
-
-        public void selectNextItem() {
-            final MenuItem cur = menu.getSelectedItem();
-            final int index = 1 + menu.getItems().indexOf(cur);
-            if (menu.getItems().size() > index) {
-                final MenuItem newSelectedItem = (MenuItem) menu.getItems()
-                        .get(index);
-                menu.selectItem(newSelectedItem);
-                tb.setText(newSelectedItem.getText());
-                tb.setSelectionRange(lastFilter.length(), newSelectedItem
-                        .getText().length()
-                        - lastFilter.length());
-
-            } else if (hasNextPage()) {
-                lastIndex = index - 1; // save for paging
-                filterOptions(currentPage + 1, lastFilter);
-            }
-        }
-
-        public void selectPrevItem() {
-            final MenuItem cur = menu.getSelectedItem();
-            final int index = -1 + menu.getItems().indexOf(cur);
-            if (index > -1) {
-                final MenuItem newSelectedItem = (MenuItem) menu.getItems()
-                        .get(index);
-                menu.selectItem(newSelectedItem);
-                tb.setText(newSelectedItem.getText());
-                tb.setSelectionRange(lastFilter.length(), newSelectedItem
-                        .getText().length()
-                        - lastFilter.length());
-            } else if (index == -1) {
-                if (currentPage > 0) {
-                    lastIndex = index + 1; // save for paging
-                    filterOptions(currentPage - 1, lastFilter);
-                }
-            } else {
-                final MenuItem newSelectedItem = (MenuItem) menu.getItems()
-                        .get(menu.getItems().size() - 1);
-                menu.selectItem(newSelectedItem);
-                tb.setText(newSelectedItem.getText());
-                tb.setSelectionRange(lastFilter.length(), newSelectedItem
-                        .getText().length()
-                        - lastFilter.length());
-            }
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            final Element target = DOM.eventGetTarget(event);
-            if (DOM.compare(target, up)
-                    || DOM.compare(target, DOM.getChild(up, 0))) {
-                filterOptions(currentPage - 1, lastFilter);
-            } else if (DOM.compare(target, down)
-                    || DOM.compare(target, DOM.getChild(down, 0))) {
-                filterOptions(currentPage + 1, lastFilter);
-            }
-            tb.setFocus(true);
-        }
-
-        public void setPagingEnabled(boolean paging) {
-            if (isPagingEnabled == paging) {
-                return;
-            }
-            if (paging) {
-                DOM.setStyleAttribute(down, "display", "");
-                DOM.setStyleAttribute(up, "display", "");
-                DOM.setStyleAttribute(status, "display", "");
-            } else {
-                DOM.setStyleAttribute(down, "display", "none");
-                DOM.setStyleAttribute(up, "display", "none");
-                DOM.setStyleAttribute(status, "display", "none");
-            }
-            isPagingEnabled = paging;
-        }
-
-        /*
-         * (non-Javadoc)
-         * 
-         * @see
-         * com.google.gwt.user.client.ui.PopupPanel$PositionCallback#setPosition
-         * (int, int)
-         */
-        public void setPosition(int offsetWidth, int offsetHeight) {
-
-            int top = -1;
-            int left = -1;
-
-            // reset menu size and retrieve its "natural" size
-            menu.setHeight("");
-            if (currentPage > 0) {
-                // fix height to avoid height change when getting to last page
-                menu.fixHeightTo(PAGELENTH);
-            }
-            offsetHeight = getOffsetHeight();
-
-            final int desiredWidth = getMainWidth();
-            int naturalMenuWidth = DOM.getElementPropertyInt(DOM
-                    .getFirstChild(menu.getElement()), "offsetWidth");
-
-            if (popupOuterPadding == -1) {
-                popupOuterPadding = Util.measureHorizontalPaddingAndBorder(
-                        getElement(), 2);
-            }
-
-            if (naturalMenuWidth < desiredWidth) {
-                menu.setWidth((desiredWidth - popupOuterPadding) + "px");
-                DOM.setStyleAttribute(DOM.getFirstChild(menu.getElement()),
-                        "width", "100%");
-                naturalMenuWidth = desiredWidth;
-            }
-
-            if (BrowserInfo.get().isIE()) {
-                /*
-                 * IE requires us to specify the width for the container
-                 * element. Otherwise it will be 100% wide
-                 */
-                int rootWidth = naturalMenuWidth - popupOuterPadding;
-                DOM.setStyleAttribute(getContainerElement(), "width", rootWidth
-                        + "px");
-            }
-
-            if (offsetHeight + getPopupTop() > Window.getClientHeight()
-                    + Window.getScrollTop()) {
-                // popup on top of input instead
-                top = getPopupTop() - offsetHeight
-                        - IFilterSelect.this.getOffsetHeight();
-                if (top < 0) {
-                    top = 0;
-                }
-            } else {
-                top = getPopupTop();
-                /*
-                 * Take popup top margin into account. getPopupTop() returns the
-                 * top value including the margin but the value we give must not
-                 * include the margin.
-                 */
-                int topMargin = (top - topPosition);
-                top -= topMargin;
-            }
-
-            // fetch real width (mac FF bugs here due GWT popups overflow:auto )
-            offsetWidth = DOM.getElementPropertyInt(DOM.getFirstChild(menu
-                    .getElement()), "offsetWidth");
-            if (offsetWidth + getPopupLeft() > Window.getClientWidth()
-                    + Window.getScrollLeft()) {
-                left = IFilterSelect.this.getAbsoluteLeft()
-                        + IFilterSelect.this.getOffsetWidth()
-                        + Window.getScrollLeft() - offsetWidth;
-                if (left < 0) {
-                    left = 0;
-                }
-            } else {
-                left = getPopupLeft();
-            }
-            setPopupPosition(left, top);
-
-        }
-
-        /**
-         * @return true if popup was just closed
-         */
-        public boolean isJustClosed() {
-            final long now = (new Date()).getTime();
-            return (lastAutoClosed > 0 && (now - lastAutoClosed) < 200);
-        }
-
-        public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
-            if (autoClosed) {
-                lastAutoClosed = (new Date()).getTime();
-            }
-        }
-
-        /**
-         * Updates style names in suggestion popup to help theme building.
-         */
-        public void updateStyleNames(UIDL uidl) {
-            if (uidl.hasAttribute("style")) {
-                setStyleName(CLASSNAME + "-suggestpopup");
-                final String[] styles = uidl.getStringAttribute("style").split(
-                        " ");
-                for (int i = 0; i < styles.length; i++) {
-                    addStyleDependentName(styles[i]);
-                }
-            }
-        }
-
-    }
-
-    public class SuggestionMenu extends MenuBar {
-
-        SuggestionMenu() {
-            super(true);
-            setStyleName(CLASSNAME + "-suggestmenu");
-        }
-
-        /**
-         * Fixes menus height to use same space as full page would use. Needed
-         * to avoid height changes when quickly "scrolling" to last page
-         */
-        public void fixHeightTo(int pagelenth) {
-            if (currentSuggestions.size() > 0) {
-                final int pixels = pagelenth * (getOffsetHeight() - 2)
-                        / currentSuggestions.size();
-                setHeight((pixels + 2) + "px");
-            }
-        }
-
-        public void setSuggestions(
-                Collection<FilterSelectSuggestion> suggestions) {
-            clearItems();
-            final Iterator<FilterSelectSuggestion> it = suggestions.iterator();
-            while (it.hasNext()) {
-                final FilterSelectSuggestion s = it.next();
-                final MenuItem mi = new MenuItem(s.getDisplayString(), true, s);
-
-                com.google.gwt.dom.client.Element child = mi.getElement()
-                        .getFirstChildElement();
-                while (child != null) {
-                    if (child.getNodeName().toLowerCase().equals("img")) {
-                        DOM
-                                .sinkEvents((Element) child.cast(),
-                                        (DOM.getEventsSunk((Element) child
-                                                .cast()) | Event.ONLOAD));
-                    }
-                    child = child.getNextSiblingElement();
-                }
-
-                this.addItem(mi);
-                if (s == currentSuggestion) {
-                    selectItem(mi);
-                }
-            }
-        }
-
-        public void doSelectedItemAction() {
-            final MenuItem item = getSelectedItem();
-            final String enteredItemValue = tb.getText();
-            // check for exact match in menu
-            int p = getItems().size();
-            if (p > 0) {
-                for (int i = 0; i < p; i++) {
-                    final MenuItem potentialExactMatch = (MenuItem) getItems()
-                            .get(i);
-                    if (potentialExactMatch.getText().equals(enteredItemValue)) {
-                        selectItem(potentialExactMatch);
-                        doItemAction(potentialExactMatch, true);
-                        suggestionPopup.hide();
-                        return;
-                    }
-                }
-            }
-            if (allowNewItem) {
-
-                if (!prompting && !enteredItemValue.equals(lastNewItemString)) {
-                    /*
-                     * Store last sent new item string to avoid double sends
-                     */
-                    lastNewItemString = enteredItemValue;
-                    client.updateVariable(paintableId, "newitem",
-                            enteredItemValue, immediate);
-                }
-            } else if (item != null
-                    && !"".equals(lastFilter)
-                    && item.getText().toLowerCase().startsWith(
-                            lastFilter.toLowerCase())) {
-                doItemAction(item, true);
-            } else {
-                if (currentSuggestion != null) {
-                    String text = currentSuggestion.getReplacementString();
-                    /* TODO?
-                    if (text.equals("")) {
-                        addStyleDependentName(CLASSNAME_PROMPT);
-                        tb.setText(inputPrompt);
-                        prompting = true;
-                    } else {
-                        tb.setText(text);
-                        prompting = false;
-                        removeStyleDependentName(CLASSNAME_PROMPT);
-                    }
-                    */
-                    selectedOptionKey = currentSuggestion.key;
-                }
-            }
-            suggestionPopup.hide();
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            if (event.getTypeInt() == Event.ONLOAD) {
-                if (suggestionPopup.isVisible()) {
-                    setWidth("");
-                    DOM.setStyleAttribute(DOM.getFirstChild(getElement()),
-                            "width", "");
-                    suggestionPopup.setPopupPositionAndShow(suggestionPopup);
-                }
-            }
-            super.onBrowserEvent(event);
-        }
-    }
-
-    public static final int FILTERINGMODE_OFF = 0;
-    public static final int FILTERINGMODE_STARTSWITH = 1;
-    public static final int FILTERINGMODE_CONTAINS = 2;
-
-    private static final String CLASSNAME = "i-filterselect";
-
-    public static final int PAGELENTH = 10;
-
-    private final FlowPanel panel = new FlowPanel();
-
-    private final TextBox tb = new TextBox() {
-        @Override
-        public void onBrowserEvent(Event event) {
-            super.onBrowserEvent(event);
-            if (client != null) {
-                client.handleTooltipEvent(event, IFilterSelect.this);
-            }
-        }
-    };
-
-    private final SuggestionPopup suggestionPopup = new SuggestionPopup();
-
-    private final HTML popupOpener = new HTML("");
-
-    private final Image selectedItemIcon = new Image();
-
-    private ApplicationConnection client;
-
-    private String paintableId;
-
-    private int currentPage;
-
-    private final Collection<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>();
-
-    private boolean immediate;
-
-    private String selectedOptionKey;
-
-    private boolean filtering = false;
-
-    private String lastFilter = "";
-    private int lastIndex = -1; // last selected index when using arrows
-
-    private FilterSelectSuggestion currentSuggestion;
-
-    private int totalMatches;
-    private boolean allowNewItem;
-    private boolean nullSelectionAllowed;
-    private boolean enabled;
-
-    // shown in unfocused empty field, disappears on focus (e.g "Search here")
-    private static final String CLASSNAME_PROMPT = "prompt";
-    private static final String ATTR_INPUTPROMPT = "prompt";
-    private String inputPrompt = "";
-    private boolean prompting = false;
-
-    // Set true when popupopened has been clicked. Cleared on each UIDL-update.
-    // This handles the special case where are not filtering yet and the
-    // selected value has changed on the server-side. See #2119
-    private boolean popupOpenerClicked;
-    private String width = null;
-    private int textboxPadding = -1;
-    private int componentPadding = -1;
-    private int suggestionPopupMinWidth = 0;
-    /*
-     * Stores the last new item string to avoid double submissions. Cleared on
-     * uidl updates
-     */
-    private String lastNewItemString;
-    private boolean focused = false;
-
-    public IFilterSelect() {
-        selectedItemIcon.setVisible(false);
-        selectedItemIcon.setStyleName("i-icon");
-        selectedItemIcon.addLoadListener(new LoadListener() {
-            public void onError(Widget sender) {
-            }
-
-            public void onLoad(Widget sender) {
-                updateRootWidth();
-                updateSelectedIconPosition();
-            }
-        });
-
-        panel.add(selectedItemIcon);
-        tb.sinkEvents(ITooltip.TOOLTIP_EVENTS);
-        panel.add(tb);
-        panel.add(popupOpener);
-        initWidget(panel);
-        setStyleName(CLASSNAME);
-        tb.addKeyboardListener(this);
-        tb.setStyleName(CLASSNAME + "-input");
-        tb.addFocusListener(this);
-        popupOpener.setStyleName(CLASSNAME + "-button");
-        popupOpener.addClickListener(this);
-    }
-
-    public boolean hasNextPage() {
-        if (totalMatches > (currentPage + 1) * PAGELENTH) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public void filterOptions(int page) {
-        filterOptions(page, tb.getText());
-    }
-
-    public void filterOptions(int page, String filter) {
-        if (filter.equals(lastFilter) && currentPage == page) {
-            if (!suggestionPopup.isAttached()) {
-                suggestionPopup.showSuggestions(currentSuggestions,
-                        currentPage, totalMatches);
-            }
-            return;
-        }
-        if (!filter.equals(lastFilter)) {
-            // we are on subsequent page and text has changed -> reset page
-            if ("".equals(filter)) {
-                // let server decide
-                page = -1;
-            } else {
-                page = 0;
-            }
-        }
-
-        filtering = true;
-        client.updateVariable(paintableId, "filter", filter, false);
-        client.updateVariable(paintableId, "page", page, true);
-        lastFilter = filter;
-        currentPage = page;
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        paintableId = uidl.getId();
-        this.client = client;
-
-        boolean readonly = uidl.hasAttribute("readonly");
-        boolean disabled = uidl.hasAttribute("disabled");
-
-        if (disabled || readonly) {
-            tb.setEnabled(false);
-            enabled = false;
-        } else {
-            tb.setEnabled(true);
-            enabled = true;
-        }
-
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        // not a FocusWidget -> needs own tabindex handling
-        if (uidl.hasAttribute("tabindex")) {
-            tb.setTabIndex(uidl.getIntAttribute("tabindex"));
-        }
-
-        immediate = uidl.hasAttribute("immediate");
-
-        nullSelectionAllowed = uidl.hasAttribute("nullselect");
-
-        currentPage = uidl.getIntVariable("page");
-
-        if (uidl.hasAttribute(ATTR_INPUTPROMPT)) {
-            // input prompt changed from server
-            inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
-        } else {
-            inputPrompt = "";
-        }
-
-        suggestionPopup.setPagingEnabled(true);
-        suggestionPopup.updateStyleNames(uidl);
-
-        allowNewItem = uidl.hasAttribute("allownewitem");
-        lastNewItemString = null;
-
-        currentSuggestions.clear();
-        final UIDL options = uidl.getChildUIDL(0);
-        totalMatches = uidl.getIntAttribute("totalMatches");
-
-        String captions = inputPrompt;
-
-        for (final Iterator i = options.getChildIterator(); i.hasNext();) {
-            final UIDL optionUidl = (UIDL) i.next();
-            final FilterSelectSuggestion suggestion = new FilterSelectSuggestion(
-                    optionUidl);
-            currentSuggestions.add(suggestion);
-            if (optionUidl.hasAttribute("selected")) {
-                if (!filtering || popupOpenerClicked) {
-                    tb.setText(suggestion.getReplacementString());
-                    selectedOptionKey = "" + suggestion.getOptionKey();
-                }
-                currentSuggestion = suggestion;
-                setSelectedItemIcon(suggestion.getIconUri());
-            }
-
-            // Collect captions so we can calculate minimum width for textarea
-            if (captions.length() > 0) {
-                captions += "|";
-            }
-            captions += suggestion.getReplacementString();
-        }
-
-        if ((!filtering || popupOpenerClicked) && uidl.hasVariable("selected")
-                && uidl.getStringArrayVariable("selected").length == 0) {
-            // select nulled
-            if (!filtering || !popupOpenerClicked) {
-                setPromptingOn();
-            }
-            selectedOptionKey = null;
-        }
-
-        if (filtering
-                && lastFilter.toLowerCase().equals(
-                        uidl.getStringVariable("filter"))) {
-            suggestionPopup.showSuggestions(currentSuggestions, currentPage,
-                    totalMatches);
-            filtering = false;
-            if (!popupOpenerClicked && lastIndex != -1) {
-                // we're paging w/ arrows
-                if (lastIndex == 0) {
-                    // going up, select last item
-                    int lastItem = PAGELENTH - 1;
-                    List items = suggestionPopup.menu.getItems();
-                    /*
-                     * The first page can contain less than 10 items if the null
-                     * selection item is filtered away
-                     */
-                    if (lastItem >= items.size()) {
-                        lastItem = items.size() - 1;
-                    }
-                    suggestionPopup.menu.selectItem((MenuItem) items
-                            .get(lastItem));
-                } else {
-                    // going down, select first item
-                    suggestionPopup.menu
-                            .selectItem((MenuItem) suggestionPopup.menu
-                                    .getItems().get(0));
-                }
-                lastIndex = -1; // reset
-            }
-        }
-
-        // Calculate minumum textarea width
-        suggestionPopupMinWidth = minWidth(captions);
-
-        popupOpenerClicked = false;
-
-        updateRootWidth();
-    }
-
-    private void setPromptingOn() {
-        prompting = true;
-        addStyleDependentName(CLASSNAME_PROMPT);
-        tb.setText(inputPrompt);
-    }
-
-    private void setPromptingOff(String text) {
-        tb.setText(text);
-        prompting = false;
-        removeStyleDependentName(CLASSNAME_PROMPT);
-    }
-
-    public void onSuggestionSelected(FilterSelectSuggestion suggestion) {
-        currentSuggestion = suggestion;
-        String newKey;
-        if (suggestion.key.equals("")) {
-            // "nullselection"
-            newKey = "";
-        } else {
-            // normal selection
-            newKey = String.valueOf(suggestion.getOptionKey());
-        }
-
-        String text = suggestion.getReplacementString();
-        if ("".equals(newKey) && !focused) {
-            setPromptingOn();
-        } else {
-            setPromptingOff(text);
-        }
-        setSelectedItemIcon(suggestion.getIconUri());
-        if (!newKey.equals(selectedOptionKey)) {
-            selectedOptionKey = newKey;
-            client.updateVariable(paintableId, "selected",
-                    new String[] { selectedOptionKey }, immediate);
-            // currentPage = -1; // forget the page
-        }
-        suggestionPopup.hide();
-    }
-
-    private void setSelectedItemIcon(String iconUri) {
-        if (iconUri == null) {
-            selectedItemIcon.setVisible(false);
-            updateRootWidth();
-        } else {
-            selectedItemIcon.setUrl(iconUri);
-            selectedItemIcon.setVisible(true);
-            updateRootWidth();
-            updateSelectedIconPosition();
-        }
-    }
-
-    private void updateSelectedIconPosition() {
-        // Position icon vertically to middle
-        int availableHeight = getOffsetHeight();
-        int iconHeight = Util.getRequiredHeight(selectedItemIcon);
-        int marginTop = (availableHeight - iconHeight) / 2;
-        DOM.setStyleAttribute(selectedItemIcon.getElement(), "marginTop",
-                marginTop + "px");
-    }
-
-    public void onKeyDown(Widget sender, char keyCode, int modifiers) {
-        if (enabled && suggestionPopup.isAttached()) {
-            switch (keyCode) {
-            case KeyboardListener.KEY_DOWN:
-                suggestionPopup.selectNextItem();
-                DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
-                break;
-            case KeyboardListener.KEY_UP:
-                suggestionPopup.selectPrevItem();
-                DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
-                break;
-            case KeyboardListener.KEY_PAGEDOWN:
-                if (hasNextPage()) {
-                    filterOptions(currentPage + 1, lastFilter);
-                }
-                break;
-            case KeyboardListener.KEY_PAGEUP:
-                if (currentPage > 0) {
-                    filterOptions(currentPage - 1, lastFilter);
-                }
-                break;
-            case KeyboardListener.KEY_ENTER:
-            case KeyboardListener.KEY_TAB:
-                suggestionPopup.menu.doSelectedItemAction();
-                break;
-            }
-        }
-    }
-
-    public void onKeyPress(Widget sender, char keyCode, int modifiers) {
-
-    }
-
-    public void onKeyUp(Widget sender, char keyCode, int modifiers) {
-        if (enabled) {
-            switch (keyCode) {
-            case KeyboardListener.KEY_ENTER:
-            case KeyboardListener.KEY_TAB:
-            case KeyboardListener.KEY_SHIFT:
-            case KeyboardListener.KEY_CTRL:
-            case KeyboardListener.KEY_ALT:
-                ; // NOP
-                break;
-            case KeyboardListener.KEY_DOWN:
-            case KeyboardListener.KEY_UP:
-            case KeyboardListener.KEY_PAGEDOWN:
-            case KeyboardListener.KEY_PAGEUP:
-                if (suggestionPopup.isAttached()) {
-                    break;
-                } else {
-                    // open popup as from gadget
-                    filterOptions(-1, "");
-                    lastFilter = "";
-                    tb.selectAll();
-                    break;
-                }
-            case KeyboardListener.KEY_ESCAPE:
-                if (currentSuggestion != null) {
-                    String text = currentSuggestion.getReplacementString();
-                    setPromptingOff(text);
-                    selectedOptionKey = currentSuggestion.key;
-                } else {
-                    setPromptingOn();
-                    selectedOptionKey = null;
-                }
-                lastFilter = "";
-                suggestionPopup.hide();
-                break;
-            default:
-                filterOptions(currentPage);
-                break;
-            }
-        }
-    }
-
-    /**
-     * Listener for popupopener
-     */
-    public void onClick(Widget sender) {
-        if (enabled) {
-            // ask suggestionPopup if it was just closed, we are using GWT
-            // Popup's auto close feature
-            if (!suggestionPopup.isJustClosed()) {
-                filterOptions(-1, "");
-                popupOpenerClicked = true;
-                lastFilter = "";
-            } else if (selectedOptionKey == null) {
-                tb.setText(inputPrompt);
-                prompting = true;
-            }
-            DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
-            tb.setFocus(true);
-            tb.selectAll();
-
-        }
-    }
-
-    /*
-     * Calculate minumum width for FilterSelect textarea
-     */
-    private native int minWidth(String captions)
-    /*-{
-        if(!captions || captions.length <= 0)
-                return 0;
-        captions = captions.split("|");
-        var d = $wnd.document.createElement("div");
-        var html = "";
-        for(var i=0; i < captions.length; i++) {
-                html += "<div>" + captions[i] + "</div>";
-                // TODO apply same CSS classname as in suggestionmenu
-        }
-        d.style.position = "absolute";
-        d.style.top = "0";
-        d.style.left = "0";
-        d.style.visibility = "hidden";
-        d.innerHTML = html;
-        $wnd.document.body.appendChild(d);
-        var w = d.offsetWidth;
-        $wnd.document.body.removeChild(d);
-        return w;
-    }-*/;
-
-    public void onFocus(Widget sender) {
-        focused = true;
-        if (prompting) {
-            setPromptingOff("");
-        }
-        addStyleDependentName("focus");
-    }
-
-    public void onLostFocus(Widget sender) {
-        focused = false;
-        if (!suggestionPopup.isAttached() || suggestionPopup.isJustClosed()) {
-            // typing so fast the popup was never opened, or it's just closed
-            suggestionPopup.menu.doSelectedItemAction();
-        }
-        if (selectedOptionKey == null) {
-            setPromptingOn();
-        }
-        removeStyleDependentName("focus");
-    }
-
-    public void focus() {
-        focused = true;
-        if (prompting) {
-            setPromptingOff("");
-        }
-        tb.setFocus(true);
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (width == null || width.equals("")) {
-            this.width = null;
-        } else {
-            this.width = width;
-        }
-        Util.setWidthExcludingPaddingAndBorder(this, width, 4);
-        updateRootWidth();
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        Util.setHeightExcludingPaddingAndBorder(tb, height, 3);
-    }
-
-    private void updateRootWidth() {
-        if (width == null) {
-            /*
-             * When the width is not specified we must specify width for root
-             * div so the popupopener won't wrap to the next line and also so
-             * the size of the combobox won't change over time.
-             */
-            int tbWidth = Util.getRequiredWidth(tb);
-            int openerWidth = Util.getRequiredWidth(popupOpener);
-            int iconWidth = Util.getRequiredWidth(selectedItemIcon);
-
-            int w = tbWidth + openerWidth + iconWidth;
-            if (suggestionPopupMinWidth > w) {
-                setTextboxWidth(suggestionPopupMinWidth);
-                w = suggestionPopupMinWidth;
-            } else {
-                /*
-                 * Firefox3 has its own way of doing rendering so we need to
-                 * specify the width for the TextField to make sure it actually
-                 * is rendered as wide as FF3 says it is
-                 */
-                tb.setWidth((tbWidth - getTextboxPadding()) + "px");
-            }
-            super.setWidth((w) + "px");
-            // Freeze the initial width, so that it won't change even if the
-            // icon size changes
-            width = w + "px";
-
-        } else {
-            /*
-             * When the width is specified we also want to explicitly specify
-             * widths for textbox and popupopener
-             */
-            setTextboxWidth(getMainWidth() - getComponentPadding());
-
-        }
-    }
-
-    private int getMainWidth() {
-        int componentWidth;
-        if (BrowserInfo.get().isIE6()) {
-            // Required in IE when textfield is wider than this.width
-            DOM.setStyleAttribute(getElement(), "overflow", "hidden");
-            componentWidth = getOffsetWidth();
-            DOM.setStyleAttribute(getElement(), "overflow", "");
-        } else {
-            componentWidth = getOffsetWidth();
-        }
-        return componentWidth;
-    }
-
-    private void setTextboxWidth(int componentWidth) {
-        int padding = getTextboxPadding();
-        int popupOpenerWidth = Util.getRequiredWidth(popupOpener);
-        int iconWidth = Util.getRequiredWidth(selectedItemIcon);
-        int textboxWidth = componentWidth - padding - popupOpenerWidth
-                - iconWidth;
-        if (textboxWidth < 0) {
-            textboxWidth = 0;
-        }
-        tb.setWidth(textboxWidth + "px");
-    }
-
-    private int getTextboxPadding() {
-        if (textboxPadding < 0) {
-            textboxPadding = Util.measureHorizontalPaddingAndBorder(tb
-                    .getElement(), 4);
-        }
-        return textboxPadding;
-    }
-
-    private int getComponentPadding() {
-        if (componentPadding < 0) {
-            componentPadding = Util.measureHorizontalPaddingAndBorder(
-                    getElement(), 3);
-        }
-        return componentPadding;
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IForm.java b/src/com/vaadin/terminal/gwt/client/ui/IForm.java
deleted file mode 100644 (file)
index 9e6c0f5..0000000
+++ /dev/null
@@ -1,288 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Set;\r
-\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.Element;\r
-import com.google.gwt.user.client.ui.ComplexPanel;\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.Container;\r
-import com.vaadin.terminal.gwt.client.IErrorMessage;\r
-import com.vaadin.terminal.gwt.client.Paintable;\r
-import com.vaadin.terminal.gwt.client.RenderInformation;\r
-import com.vaadin.terminal.gwt.client.RenderSpace;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-import com.vaadin.terminal.gwt.client.Util;\r
-\r
-public class IForm extends ComplexPanel implements Container {\r
-\r
-    private String height = "";\r
-\r
-    private String width = "";\r
-\r
-    public static final String CLASSNAME = "i-form";\r
-\r
-    private Container lo;\r
-    private Element legend = DOM.createLegend();\r
-    private Element caption = DOM.createSpan();\r
-    private Element errorIndicatorElement = DOM.createDiv();\r
-    private Element desc = DOM.createDiv();\r
-    private Icon icon;\r
-    private IErrorMessage errorMessage = new IErrorMessage();\r
-\r
-    private Element fieldContainer = DOM.createDiv();\r
-\r
-    private Element footerContainer = DOM.createDiv();\r
-\r
-    private Element fieldSet = DOM.createFieldSet();\r
-\r
-    private Container footer;\r
-\r
-    private ApplicationConnection client;\r
-\r
-    private RenderInformation renderInformation = new RenderInformation();\r
-\r
-    private int borderPaddingHorizontal;\r
-\r
-    private int borderPaddingVertical;\r
-\r
-    private boolean rendering = false;\r
-\r
-    public IForm() {\r
-        setElement(DOM.createDiv());\r
-        DOM.appendChild(getElement(), fieldSet);\r
-        setStyleName(CLASSNAME);\r
-        DOM.appendChild(fieldSet, legend);\r
-        DOM.appendChild(legend, caption);\r
-        DOM.setElementProperty(errorIndicatorElement, "className",\r
-                "i-errorindicator");\r
-        DOM.setStyleAttribute(errorIndicatorElement, "display", "none");\r
-        DOM.setInnerText(errorIndicatorElement, " "); // needed for IE\r
-        DOM.setElementProperty(desc, "className", "i-form-description");\r
-        DOM.appendChild(fieldSet, desc);\r
-        DOM.appendChild(fieldSet, fieldContainer);\r
-        errorMessage.setVisible(false);\r
-        errorMessage.setStyleName(CLASSNAME + "-errormessage");\r
-        DOM.appendChild(fieldSet, errorMessage.getElement());\r
-        DOM.appendChild(fieldSet, footerContainer);\r
-    }\r
-\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        rendering = true;\r
-        boolean measure = false;\r
-        if (this.client == null) {\r
-            this.client = client;\r
-            measure = true;\r
-        }\r
-\r
-        if (client.updateComponent(this, uidl, false)) {\r
-            rendering = false;\r
-            return;\r
-        }\r
-\r
-        if (measure) {\r
-            // Measure the border when the style names have been set\r
-            borderPaddingVertical = getOffsetHeight();\r
-            int ow = getOffsetWidth();\r
-            int dow = desc.getOffsetWidth();\r
-            borderPaddingHorizontal = ow - dow;\r
-        }\r
-\r
-        boolean legendEmpty = true;\r
-        if (uidl.hasAttribute("caption")) {\r
-            DOM.setInnerText(caption, uidl.getStringAttribute("caption"));\r
-            legendEmpty = false;\r
-        } else {\r
-            DOM.setInnerText(caption, "");\r
-        }\r
-        if (uidl.hasAttribute("icon")) {\r
-            if (icon == null) {\r
-                icon = new Icon(client);\r
-                DOM.insertChild(legend, icon.getElement(), 0);\r
-            }\r
-            icon.setUri(uidl.getStringAttribute("icon"));\r
-            legendEmpty = false;\r
-        } else {\r
-            if (icon != null) {\r
-                DOM.removeChild(legend, icon.getElement());\r
-            }\r
-        }\r
-        if (legendEmpty) {\r
-            DOM.setStyleAttribute(legend, "display", "none");\r
-        } else {\r
-            DOM.setStyleAttribute(legend, "display", "");\r
-        }\r
-\r
-        if (uidl.hasAttribute("error")) {\r
-            final UIDL errorUidl = uidl.getErrors();\r
-            errorMessage.updateFromUIDL(errorUidl);\r
-            errorMessage.setVisible(true);\r
-\r
-        } else {\r
-            errorMessage.setVisible(false);\r
-        }\r
-\r
-        if (uidl.hasAttribute("description")) {\r
-            DOM.setInnerHTML(desc, uidl.getStringAttribute("description"));\r
-        } else {\r
-            DOM.setInnerHTML(desc, "");\r
-        }\r
-\r
-        updateSize();\r
-        // TODO Check if this is needed\r
-        client.runDescendentsLayout(this);\r
-\r
-        final UIDL layoutUidl = uidl.getChildUIDL(0);\r
-        Container newLo = (Container) client.getPaintable(layoutUidl);\r
-        if (lo == null) {\r
-            lo = newLo;\r
-            add((Widget) lo, fieldContainer);\r
-        } else if (lo != newLo) {\r
-            client.unregisterPaintable(lo);\r
-            remove((Widget) lo);\r
-            lo = newLo;\r
-            add((Widget) lo, fieldContainer);\r
-        }\r
-        lo.updateFromUIDL(layoutUidl, client);\r
-\r
-        if (uidl.getChildCount() > 1) {\r
-            // render footer\r
-            Container newFooter = (Container) client.getPaintable(uidl\r
-                    .getChildUIDL(1));\r
-            if (footer == null) {\r
-                add((Widget) newFooter, footerContainer);\r
-                footer = newFooter;\r
-            } else if (newFooter != footer) {\r
-                remove((Widget) footer);\r
-                client.unregisterPaintable(footer);\r
-                add((Widget) newFooter, footerContainer);\r
-            }\r
-            footer = newFooter;\r
-            footer.updateFromUIDL(uidl.getChildUIDL(1), client);\r
-        } else {\r
-            if (footer != null) {\r
-                remove((Widget) footer);\r
-                client.unregisterPaintable(footer);\r
-            }\r
-        }\r
-\r
-        rendering = false;\r
-    }\r
-\r
-    public void updateSize() {\r
-\r
-        renderInformation.updateSize(getElement());\r
-\r
-        renderInformation.setContentAreaHeight(renderInformation\r
-                .getRenderedSize().getHeight()\r
-                - borderPaddingVertical);\r
-        if (BrowserInfo.get().isIE6()) {\r
-            getElement().getStyle().setProperty("overflow", "hidden");\r
-        }\r
-        renderInformation.setContentAreaWidth(renderInformation\r
-                .getRenderedSize().getWidth()\r
-                - borderPaddingHorizontal);\r
-    }\r
-\r
-    public RenderSpace getAllocatedSpace(Widget child) {\r
-        if (child == lo) {\r
-            int hPixels = 0;\r
-            if (!"".equals(height)) {\r
-                hPixels = getOffsetHeight();\r
-                hPixels -= borderPaddingVertical;\r
-                hPixels -= footerContainer.getOffsetHeight();\r
-                hPixels -= errorMessage.getOffsetHeight();\r
-                hPixels -= desc.getOffsetHeight();\r
-\r
-            }\r
-\r
-            return new RenderSpace(renderInformation.getContentAreaSize()\r
-                    .getWidth(), hPixels);\r
-        } else if (child == footer) {\r
-            return new RenderSpace(footerContainer.getOffsetWidth(), 0);\r
-        } else {\r
-            ApplicationConnection.getConsole().error(\r
-                    "Invalid child requested RenderSpace information");\r
-            return null;\r
-        }\r
-    }\r
-\r
-    public boolean hasChildComponent(Widget component) {\r
-        return component != null && (component == lo || component == footer);\r
-    }\r
-\r
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {\r
-        if (!hasChildComponent(oldComponent)) {\r
-            throw new IllegalArgumentException(\r
-                    "Old component is not inside this Container");\r
-        }\r
-        remove(oldComponent);\r
-        if (oldComponent == lo) {\r
-            lo = (Container) newComponent;\r
-            add((Widget) lo, fieldContainer);\r
-        } else {\r
-            footer = (Container) newComponent;\r
-            add((Widget) footer, footerContainer);\r
-        }\r
-\r
-    }\r
-\r
-    public boolean requestLayout(Set<Paintable> child) {\r
-\r
-        if (height != null && width != null) {\r
-            /*\r
-             * If the height and width has been specified the child components\r
-             * cannot make the size of the layout change\r
-             */\r
-\r
-            return true;\r
-        }\r
-\r
-        if (renderInformation.updateSize(getElement())) {\r
-            return false;\r
-        } else {\r
-            return true;\r
-        }\r
-\r
-    }\r
-\r
-    public void updateCaption(Paintable component, UIDL uidl) {\r
-        // NOP form don't render caption for neither field layout nor footer\r
-        // layout\r
-    }\r
-\r
-    @Override\r
-    public void setHeight(String height) {\r
-        if (this.height.equals(height)) {\r
-            return;\r
-        }\r
-\r
-        this.height = height;\r
-        super.setHeight(height);\r
-\r
-        updateSize();\r
-    }\r
-\r
-    @Override\r
-    public void setWidth(String width) {\r
-        if (Util.equals(this.width, width)) {\r
-            return;\r
-        }\r
-\r
-        this.width = width;\r
-        super.setWidth(width);\r
-\r
-        updateSize();\r
-\r
-        if (!rendering && height.equals("")) {\r
-            // Width might affect height\r
-            Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);\r
-        }\r
-    }\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/IFormLayout.java
deleted file mode 100644 (file)
index 6d4e62b..0000000
+++ /dev/null
@@ -1,464 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.FlexTable;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.StyleConstants;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-/**
- * Two col Layout that places caption on left col and field on right col
- */
-public class IFormLayout extends SimplePanel implements Container {
-
-    private final static String CLASSNAME = "i-formlayout";
-
-    private ApplicationConnection client;
-    private IFormLayoutTable table;
-
-    private String width = "";
-    private String height = "";
-
-    private boolean rendering = false;
-
-    public IFormLayout() {
-        super();
-        setStylePrimaryName(CLASSNAME);
-        table = new IFormLayoutTable();
-        setWidget(table);
-    }
-
-    public class IFormLayoutTable extends FlexTable {
-
-        private static final int COLUMN_CAPTION = 0;
-        private static final int COLUMN_ERRORFLAG = 1;
-        private static final int COLUMN_WIDGET = 2;
-
-        private HashMap<Paintable, Caption> componentToCaption = new HashMap<Paintable, Caption>();
-        private HashMap<Paintable, ErrorFlag> componentToError = new HashMap<Paintable, ErrorFlag>();
-
-        public IFormLayoutTable() {
-            DOM.setElementProperty(getElement(), "cellPadding", "0");
-            DOM.setElementProperty(getElement(), "cellSpacing", "0");
-        }
-
-        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-            final IMarginInfo margins = new IMarginInfo(uidl
-                    .getIntAttribute("margins"));
-
-            Element margin = getElement();
-            setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP,
-                    margins.hasTop());
-            setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT,
-                    margins.hasRight());
-            setStyleName(margin,
-                    CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM, margins
-                            .hasBottom());
-            setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT,
-                    margins.hasLeft());
-
-            setStyleName(margin, CLASSNAME + "-" + "spacing", uidl
-                    .hasAttribute("spacing"));
-
-            int i = 0;
-            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);
-                if (caption == null) {
-                    caption = new Caption(p, client);
-                    componentToCaption.put(p, caption);
-                }
-                ErrorFlag error = componentToError.get(p);
-                if (error == null) {
-                    error = new ErrorFlag();
-                    componentToError.put(p, 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);
-                }
-                getCellFormatter().setStyleName(i, COLUMN_WIDGET,
-                        CLASSNAME + "-contentcell");
-                getCellFormatter().setStyleName(i, COLUMN_CAPTION,
-                        CLASSNAME + "-captioncell");
-                setWidget(i, COLUMN_CAPTION, caption);
-
-                setContentWidth(i);
-
-                getCellFormatter().setStyleName(i, COLUMN_ERRORFLAG,
-                        CLASSNAME + "-errorcell");
-                setWidget(i, COLUMN_ERRORFLAG, error);
-
-                p.updateFromUIDL(childUidl, client);
-
-                String rowstyles = CLASSNAME + "-row";
-                if (i == 0) {
-                    rowstyles += " " + CLASSNAME + "-firstrow";
-                }
-                if (!it.hasNext()) {
-                    rowstyles += " " + CLASSNAME + "-lastrow";
-                }
-
-                getRowFormatter().setStyleName(i, rowstyles);
-
-            }
-
-            while (getRowCount() > i) {
-                final Paintable p = (Paintable) getWidget(i, COLUMN_WIDGET);
-                client.unregisterPaintable(p);
-                componentToCaption.remove(p);
-                removeRow(i);
-            }
-
-            /*
-             * Must update relative sized fields last when it is clear how much
-             * space they are allowed to use
-             */
-            for (Paintable p : componentToCaption.keySet()) {
-                client.handleComponentRelativeSize((Widget) p);
-            }
-        }
-
-        public void setContentWidths() {
-            for (int row = 0; row < getRowCount(); row++) {
-                setContentWidth(row);
-            }
-        }
-
-        private void setContentWidth(int row) {
-            String width = "";
-            if (!isDynamicWidth()) {
-                width = "100%";
-            }
-            getCellFormatter().setWidth(row, COLUMN_WIDGET, width);
-        }
-
-        public void replaceChildComponent(Widget oldComponent,
-                Widget newComponent) {
-            int i;
-            for (i = 0; i < getRowCount(); i++) {
-                Widget candidate = getWidget(i, COLUMN_WIDGET);
-                if (oldComponent == candidate) {
-                    final Caption newCap = new Caption(
-                            (Paintable) newComponent, client);
-                    componentToCaption.put((Paintable) newComponent, newCap);
-                    ErrorFlag error = componentToError.get(newComponent);
-                    if (error == null) {
-                        error = new ErrorFlag();
-                        componentToError.put((Paintable) newComponent, error);
-                    }
-
-                    setWidget(i, COLUMN_CAPTION, newCap);
-                    setWidget(i, COLUMN_ERRORFLAG, error);
-                    setWidget(i, COLUMN_WIDGET, newComponent);
-                    break;
-                }
-            }
-
-        }
-
-        public boolean hasChildComponent(Widget component) {
-            return componentToCaption.containsKey(component);
-        }
-
-        public void updateCaption(Paintable component, UIDL uidl) {
-            final Caption c = componentToCaption.get(component);
-            if (c != null) {
-                c.updateCaption(uidl);
-            }
-            final ErrorFlag e = componentToError.get(component);
-            if (e != null) {
-                e.updateFromUIDL(uidl, component);
-            }
-
-        }
-
-        public int getAllocatedWidth(Widget child, int availableWidth) {
-            Caption caption = componentToCaption.get(child);
-            ErrorFlag error = componentToError.get(child);
-            int width = availableWidth;
-
-            if (caption != null) {
-                width -= DOM.getParent(caption.getElement()).getOffsetWidth();
-            }
-            if (error != null) {
-                width -= DOM.getParent(error.getElement()).getOffsetWidth();
-            }
-
-            return width;
-        }
-
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-
-        this.client = client;
-
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-
-        table.updateFromUIDL(uidl, client);
-
-        rendering = false;
-    }
-
-    public boolean isDynamicWidth() {
-        return width.equals("");
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        return table.hasChildComponent(component);
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        table.replaceChildComponent(oldComponent, newComponent);
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        table.updateCaption(component, uidl);
-    }
-
-    public class Caption extends HTML {
-
-        public static final String CLASSNAME = "i-caption";
-
-        private final Paintable owner;
-
-        private Element requiredFieldIndicator;
-
-        private Icon icon;
-
-        private Element captionText;
-
-        private final ApplicationConnection client;
-
-        /**
-         * 
-         * @param component
-         *            optional owner of caption. If not set, getOwner will
-         *            return null
-         * @param client
-         */
-        public Caption(Paintable component, ApplicationConnection client) {
-            super();
-            this.client = client;
-            owner = component;
-            setStyleName(CLASSNAME);
-            sinkEvents(ITooltip.TOOLTIP_EVENTS);
-        }
-
-        public void updateCaption(UIDL uidl) {
-            setVisible(!uidl.getBooleanAttribute("invisible"));
-
-            setStyleName(getElement(), "i-disabled", uidl
-                    .hasAttribute("disabled"));
-
-            boolean isEmpty = true;
-
-            if (uidl.hasAttribute("icon")) {
-                if (icon == null) {
-                    icon = new Icon(client);
-
-                    DOM.insertChild(getElement(), icon.getElement(), 0);
-                }
-                icon.setUri(uidl.getStringAttribute("icon"));
-                isEmpty = false;
-            } else {
-                if (icon != null) {
-                    DOM.removeChild(getElement(), icon.getElement());
-                    icon = null;
-                }
-
-            }
-
-            if (uidl.hasAttribute("caption")) {
-                if (captionText == null) {
-                    captionText = DOM.createSpan();
-                    DOM.insertChild(getElement(), captionText, icon == null ? 0
-                            : 1);
-                }
-                String c = uidl.getStringAttribute("caption");
-                if (c == null) {
-                    c = "";
-                } else {
-                    isEmpty = false;
-                }
-                DOM.setInnerText(captionText, c);
-            } else {
-                // TODO should span also be removed
-            }
-
-            if (uidl.hasAttribute("description")) {
-                if (captionText != null) {
-                    addStyleDependentName("hasdescription");
-                } else {
-                    removeStyleDependentName("hasdescription");
-                }
-            }
-
-            if (uidl.getBooleanAttribute("required")) {
-                if (requiredFieldIndicator == null) {
-                    requiredFieldIndicator = DOM.createSpan();
-                    DOM.setInnerText(requiredFieldIndicator, "*");
-                    DOM.setElementProperty(requiredFieldIndicator, "className",
-                            "i-required-field-indicator");
-                    DOM.appendChild(getElement(), requiredFieldIndicator);
-                }
-            } else {
-                if (requiredFieldIndicator != null) {
-                    DOM.removeChild(getElement(), requiredFieldIndicator);
-                    requiredFieldIndicator = null;
-                }
-            }
-
-            // Workaround for IE weirdness, sometimes returns bad height in some
-            // circumstances when Caption is empty. See #1444
-            // IE7 bugs more often. I wonder what happens when IE8 arrives...
-            if (Util.isIE()) {
-                if (isEmpty) {
-                    setHeight("0px");
-                    DOM.setStyleAttribute(getElement(), "overflow", "hidden");
-                } else {
-                    setHeight("");
-                    DOM.setStyleAttribute(getElement(), "overflow", "");
-                }
-
-            }
-
-        }
-
-        /**
-         * Returns Paintable for which this Caption belongs to.
-         * 
-         * @return owner Widget
-         */
-        public Paintable getOwner() {
-            return owner;
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            super.onBrowserEvent(event);
-            if (client != null) {
-                client.handleTooltipEvent(event, owner);
-            }
-        }
-    }
-
-    private class ErrorFlag extends HTML {
-        private static final String CLASSNAME = IFormLayout.CLASSNAME
-                + "-error-indicator";
-        Element errorIndicatorElement;
-        private Paintable owner;
-
-        public ErrorFlag() {
-            setStyleName(CLASSNAME);
-            sinkEvents(ITooltip.TOOLTIP_EVENTS);
-        }
-
-        public void updateFromUIDL(UIDL uidl, Paintable component) {
-            owner = component;
-            if (uidl.hasAttribute("error")
-                    && !uidl.getBooleanAttribute("hideErrors")) {
-                if (errorIndicatorElement == null) {
-                    errorIndicatorElement = DOM.createDiv();
-                    DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
-                    DOM.setElementProperty(errorIndicatorElement, "className",
-                            "i-errorindicator");
-                    DOM.appendChild(getElement(), errorIndicatorElement);
-                }
-
-            } else if (errorIndicatorElement != null) {
-                DOM.removeChild(getElement(), errorIndicatorElement);
-                errorIndicatorElement = null;
-            }
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            super.onBrowserEvent(event);
-            if (owner != null) {
-                client.handleTooltipEvent(event, owner);
-            }
-        }
-
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        if (height.equals("") || width.equals("")) {
-            // A dynamic size might change due to children changes
-            return false;
-        }
-
-        return true;
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        int width = 0;
-        int height = 0;
-
-        if (!this.width.equals("")) {
-            int availableWidth = getOffsetWidth();
-            width = table.getAllocatedWidth(child, availableWidth);
-        }
-
-        return new RenderSpace(width, height, false);
-    }
-
-    @Override
-    public void setHeight(String height) {
-        if (this.height.equals(height)) {
-            return;
-        }
-
-        this.height = height;
-        super.setHeight(height);
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        this.width = width;
-        super.setWidth(width);
-
-        if (!rendering) {
-            table.setContentWidths();
-            if (height.equals("")) {
-                // Width might affect height
-                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
-            }
-        }
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/IGridLayout.java
deleted file mode 100644 (file)
index 07bb758..0000000
+++ /dev/null
@@ -1,1018 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.AbsolutePanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.StyleConstants;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
-import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
-
-public class IGridLayout extends SimplePanel implements Paintable, Container {
-
-    public static final String CLASSNAME = "i-gridlayout";
-
-    private DivElement margin = Document.get().createDivElement();
-
-    private final AbsolutePanel canvas = new AbsolutePanel();
-
-    private ApplicationConnection client;
-
-    protected HashMap<Widget, ChildComponentContainer> widgetToComponentContainer = new HashMap<Widget, ChildComponentContainer>();
-
-    private HashMap<Paintable, Cell> paintableToCell = new HashMap<Paintable, Cell>();
-
-    private int spacingPixelsHorizontal;
-    private int spacingPixelsVertical;
-
-    private int[] columnWidths;
-    private int[] rowHeights;
-
-    private String height;
-
-    private String width;
-
-    private int[] colExpandRatioArray;
-
-    private int[] rowExpandRatioArray;
-
-    private int[] minColumnWidths;
-
-    private int[] minRowHeights;
-
-    private boolean rendering;
-
-    private HashMap<Widget, ChildComponentContainer> nonRenderedWidgets;
-
-    private boolean sizeChangedDuringRendering = false;
-
-    public IGridLayout() {
-        super();
-        getElement().appendChild(margin);
-        setStyleName(CLASSNAME);
-        setWidget(canvas);
-    }
-
-    @Override
-    protected Element getContainerElement() {
-        return margin.cast();
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-        this.client = client;
-
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-
-        boolean mightToggleVScrollBar = "".equals(height) && !"".equals(width);
-        boolean mightToggleHScrollBar = "".equals(width) && !"".equals(height);
-        int wBeforeRender = 0;
-        int hBeforeRender = 0;
-        if (mightToggleHScrollBar || mightToggleVScrollBar) {
-            wBeforeRender = canvas.getOffsetWidth();
-            hBeforeRender = getOffsetHeight();
-        }
-        canvas.setWidth("0px");
-
-        handleMargins(uidl);
-        detectSpacing(uidl);
-
-        int cols = uidl.getIntAttribute("w");
-        int rows = uidl.getIntAttribute("h");
-
-        columnWidths = new int[cols];
-        rowHeights = new int[rows];
-
-        if (cells == null) {
-            cells = new Cell[cols][rows];
-        } else if (cells.length != cols || cells[0].length != rows) {
-            Cell[][] newCells = new Cell[cols][rows];
-            for (int i = 0; i < cells.length; i++) {
-                for (int j = 0; j < cells[i].length; j++) {
-                    if (i < cols && j < rows) {
-                        newCells[i][j] = cells[i][j];
-                    }
-                }
-            }
-            cells = newCells;
-        }
-
-        nonRenderedWidgets = (HashMap<Widget, ChildComponentContainer>) widgetToComponentContainer
-                .clone();
-
-        final int[] alignments = uidl.getIntArrayAttribute("alignments");
-        int alignmentIndex = 0;
-
-        LinkedList<Cell> pendingCells = new LinkedList<Cell>();
-
-        LinkedList<Cell> relativeHeighted = new LinkedList<Cell>();
-
-        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
-            final UIDL r = (UIDL) i.next();
-            if ("gr".equals(r.getTag())) {
-                for (final Iterator j = r.getChildIterator(); j.hasNext();) {
-                    final UIDL c = (UIDL) j.next();
-                    if ("gc".equals(c.getTag())) {
-                        Cell cell = getCell(c);
-                        if (cell.hasContent()) {
-                            boolean rendered = cell.renderIfNoRelativeWidth();
-                            cell.alignment = alignments[alignmentIndex++];
-                            if (!rendered) {
-                                pendingCells.add(cell);
-                            }
-
-                            if (cell.colspan > 1) {
-                                storeColSpannedCell(cell);
-                            } else if (rendered) {
-                                // strore non-colspanned widths to columnWidth
-                                // array
-                                if (columnWidths[cell.col] < cell.getWidth()) {
-                                    columnWidths[cell.col] = cell.getWidth();
-                                }
-                            }
-                            if (cell.hasRelativeHeight()) {
-                                relativeHeighted.add(cell);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        distributeColSpanWidths();
-        colExpandRatioArray = uidl.getIntArrayAttribute("colExpand");
-        rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand");
-
-        minColumnWidths = cloneArray(columnWidths);
-        expandColumns();
-
-        renderRemainingComponentsWithNoRelativeHeight(pendingCells);
-
-        detectRowHeights();
-
-        expandRows();
-
-        renderRemainingComponents(pendingCells);
-
-        for (Cell cell : relativeHeighted) {
-            Widget widget2 = cell.cc.getWidget();
-            client.handleComponentRelativeSize(widget2);
-            cell.cc.updateWidgetSize();
-        }
-
-        layoutCells();
-
-        // clean non rendered components
-        for (Widget w : nonRenderedWidgets.keySet()) {
-            ChildComponentContainer childComponentContainer = widgetToComponentContainer
-                    .get(w);
-            paintableToCell.remove(w);
-            widgetToComponentContainer.remove(w);
-            childComponentContainer.removeFromParent();
-            client.unregisterPaintable((Paintable) w);
-        }
-        nonRenderedWidgets = null;
-
-        rendering = false;
-        sizeChangedDuringRendering = false;
-
-        boolean needsRelativeSizeCheck = false;
-
-        if (mightToggleHScrollBar && wBeforeRender != canvas.getOffsetWidth()) {
-            needsRelativeSizeCheck = true;
-        }
-        if (mightToggleVScrollBar && hBeforeRender != getOffsetHeight()) {
-            needsRelativeSizeCheck = true;
-        }
-        if (needsRelativeSizeCheck) {
-            client.handleComponentRelativeSize(this);
-        }
-    }
-
-    private static int[] cloneArray(int[] toBeCloned) {
-        int[] clone = new int[toBeCloned.length];
-        for (int i = 0; i < clone.length; i++) {
-            clone[i] = toBeCloned[i] * 1;
-        }
-        return clone;
-    }
-
-    private void expandRows() {
-        if (!"".equals(height)) {
-            int usedSpace = minRowHeights[0];
-            for (int i = 1; i < minRowHeights.length; i++) {
-                usedSpace += spacingPixelsVertical + minRowHeights[i];
-            }
-            int availableSpace = getOffsetHeight() - marginTopAndBottom;
-            int excessSpace = availableSpace - usedSpace;
-            int distributed = 0;
-            if (excessSpace > 0) {
-                for (int i = 0; i < rowHeights.length; i++) {
-                    int ew = excessSpace * rowExpandRatioArray[i] / 1000;
-                    rowHeights[i] = minRowHeights[i] + ew;
-                    distributed += ew;
-                }
-                excessSpace -= distributed;
-                int c = 0;
-                while (excessSpace > 0) {
-                    rowHeights[c % rowHeights.length]++;
-                    excessSpace--;
-                    c++;
-                }
-            }
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        if (!height.equals(this.height)) {
-            this.height = height;
-            if (rendering) {
-                sizeChangedDuringRendering = true;
-            } else {
-                expandRows();
-                layoutCells();
-                for (Paintable c : paintableToCell.keySet()) {
-                    client.handleComponentRelativeSize((Widget) c);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        super.setWidth(width);
-        if (!width.equals(this.width)) {
-            this.width = width;
-            if (rendering) {
-                sizeChangedDuringRendering = true;
-            } else {
-                int[] oldWidths = cloneArray(columnWidths);
-                expandColumns();
-                boolean heightChanged = false;
-                HashSet<Integer> dirtyRows = null;
-                for (int i = 0; i < oldWidths.length; i++) {
-                    if (columnWidths[i] != oldWidths[i]) {
-                        Cell[] column = cells[i];
-                        for (int j = 0; j < column.length; j++) {
-                            Cell c = column[j];
-                            if (c != null && c.cc != null
-                                    && c.widthCanAffectHeight()) {
-                                c.cc.setContainerSize(c.getAvailableWidth(), c
-                                        .getAvailableHeight());
-                                client.handleComponentRelativeSize(c.cc
-                                        .getWidget());
-                                c.cc.updateWidgetSize();
-                                int newHeight = c.getHeight();
-                                if (columnWidths[i] < oldWidths[i]
-                                        && newHeight > minRowHeights[j]) {
-                                    minRowHeights[j] = newHeight;
-                                    if (newHeight > rowHeights[j]) {
-                                        rowHeights[j] = newHeight;
-                                        heightChanged = true;
-                                    }
-                                } else if (newHeight < minRowHeights[j]) {
-                                    // need to recalculate new minimum height
-                                    // for this row
-                                    if (dirtyRows == null) {
-                                        dirtyRows = new HashSet<Integer>();
-                                    }
-                                    dirtyRows.add(j);
-                                }
-                            }
-                        }
-                    }
-                }
-                if (dirtyRows != null) {
-                    /* flag indicating that there is a potential row shrinking */
-                    boolean rowMayShrink = false;
-                    for (Integer rowIndex : dirtyRows) {
-                        int oldMinimum = minRowHeights[rowIndex];
-                        int newMinimum = 0;
-                        for (int colIndex = 0; colIndex < columnWidths.length; colIndex++) {
-                            Cell cell = cells[colIndex][rowIndex];
-                            if (cell != null && !cell.hasRelativeHeight()
-                                    && cell.getHeight() > newMinimum) {
-                                newMinimum = cell.getHeight();
-                            }
-                        }
-                        if (newMinimum < oldMinimum) {
-                            minRowHeights[rowIndex] = rowHeights[rowIndex] = newMinimum;
-                            rowMayShrink = true;
-                        }
-                    }
-                    if (rowMayShrink) {
-                        distributeRowSpanHeights();
-                        minRowHeights = cloneArray(rowHeights);
-                        heightChanged = true;
-                    }
-
-                }
-                layoutCells();
-                for (Paintable c : paintableToCell.keySet()) {
-                    client.handleComponentRelativeSize((Widget) c);
-                }
-                if (heightChanged && "".equals(height)) {
-                    Util.notifyParentOfSizeChange(this, false);
-                }
-            }
-        }
-    }
-
-    private void expandColumns() {
-        if (!"".equals(width)) {
-            int usedSpace = minColumnWidths[0];
-            for (int i = 1; i < minColumnWidths.length; i++) {
-                usedSpace += spacingPixelsHorizontal + minColumnWidths[i];
-            }
-            canvas.setWidth("");
-            int availableSpace = canvas.getOffsetWidth();
-            int excessSpace = availableSpace - usedSpace;
-            int distributed = 0;
-            if (excessSpace > 0) {
-                for (int i = 0; i < columnWidths.length; i++) {
-                    int ew = excessSpace * colExpandRatioArray[i] / 1000;
-                    columnWidths[i] = minColumnWidths[i] + ew;
-                    distributed += ew;
-                }
-                excessSpace -= distributed;
-                int c = 0;
-                while (excessSpace > 0) {
-                    columnWidths[c % columnWidths.length]++;
-                    excessSpace--;
-                    c++;
-                }
-            }
-        }
-    }
-
-    private void layoutCells() {
-        int x = 0;
-        int y = 0;
-        for (int i = 0; i < cells.length; i++) {
-            y = 0;
-            for (int j = 0; j < cells[i].length; j++) {
-                Cell cell = cells[i][j];
-                if (cell != null) {
-                    cell.layout(x, y);
-                }
-                y += rowHeights[j] + spacingPixelsVertical;
-            }
-            x += columnWidths[i] + spacingPixelsHorizontal;
-        }
-
-        if ("".equals(width)) {
-            canvas.setWidth((x - spacingPixelsHorizontal) + "px");
-        } else {
-            // main element defines width
-            canvas.setWidth("");
-        }
-        int canvasHeight;
-        if ("".equals(height)) {
-            canvasHeight = y - spacingPixelsVertical;
-        } else {
-            canvasHeight = getOffsetHeight() - marginTopAndBottom;
-        }
-        canvas.setHeight(canvasHeight + "px");
-    }
-
-    private void renderRemainingComponents(LinkedList<Cell> pendingCells) {
-        for (Cell cell : pendingCells) {
-            cell.render();
-        }
-    }
-
-    private void detectRowHeights() {
-
-        // collect min rowheight from non-rowspanned cells
-        for (int i = 0; i < cells.length; i++) {
-            for (int j = 0; j < cells[i].length; j++) {
-                Cell cell = cells[i][j];
-                if (cell != null) {
-                    /*
-                     * Setting fixing container width may in some situations
-                     * affect height. Example: Label with wrapping text without
-                     * or with relative width.
-                     */
-                    if (cell.cc != null && cell.widthCanAffectHeight()) {
-                        cell.cc.setWidth(cell.getAvailableWidth() + "px");
-                        cell.cc.updateWidgetSize();
-                    }
-                    if (cell.rowspan == 1) {
-                        if (!cell.hasRelativeHeight()
-                                && rowHeights[j] < cell.getHeight()) {
-                            rowHeights[j] = cell.getHeight();
-                        }
-                    } else {
-                        storeRowSpannedCell(cell);
-                    }
-                }
-            }
-        }
-
-        distributeRowSpanHeights();
-
-        minRowHeights = cloneArray(rowHeights);
-    }
-
-    private void storeRowSpannedCell(Cell cell) {
-        SpanList l = null;
-        for (SpanList list : rowSpans) {
-            if (list.span < cell.rowspan) {
-                continue;
-            } else {
-                // insert before this
-                l = list;
-                break;
-            }
-        }
-        if (l == null) {
-            l = new SpanList(cell.rowspan);
-            rowSpans.add(l);
-        } else if (l.span != cell.rowspan) {
-            SpanList newL = new SpanList(cell.rowspan);
-            rowSpans.add(rowSpans.indexOf(l), newL);
-            l = newL;
-        }
-        l.cells.add(cell);
-    }
-
-    private void renderRemainingComponentsWithNoRelativeHeight(
-            LinkedList<Cell> pendingCells) {
-
-        for (Iterator iterator = pendingCells.iterator(); iterator.hasNext();) {
-            Cell cell = (Cell) iterator.next();
-            if (!cell.hasRelativeHeight()) {
-                cell.render();
-                iterator.remove();
-            }
-        }
-
-    }
-
-    /**
-     * Iterates colspanned cells, ensures cols have enough space to accommodate
-     * them
-     */
-    private void distributeColSpanWidths() {
-        for (SpanList list : colSpans) {
-            for (Cell cell : list.cells) {
-                int width = cell.getWidth();
-                int allocated = columnWidths[cell.col];
-                for (int i = 1; i < cell.colspan; i++) {
-                    allocated += spacingPixelsHorizontal
-                            + columnWidths[cell.col + i];
-                }
-                if (allocated < width) {
-                    // columnWidths needs to be expanded due colspanned cell
-                    int neededExtraSpace = width - allocated;
-                    int spaceForColunms = neededExtraSpace / cell.colspan;
-                    for (int i = 0; i < cell.colspan; i++) {
-                        int col = cell.col + i;
-                        columnWidths[col] += spaceForColunms;
-                        neededExtraSpace -= spaceForColunms;
-                    }
-                    if (neededExtraSpace > 0) {
-                        for (int i = 0; i < cell.colspan; i++) {
-                            int col = cell.col + i;
-                            columnWidths[col] += 1;
-                            neededExtraSpace -= 1;
-                            if (neededExtraSpace == 0) {
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Iterates rowspanned cells, ensures rows have enough space to accommodate
-     * them
-     */
-    private void distributeRowSpanHeights() {
-        for (SpanList list : rowSpans) {
-            for (Cell cell : list.cells) {
-                int height = cell.getHeight();
-                int allocated = rowHeights[cell.row];
-                for (int i = 1; i < cell.rowspan; i++) {
-                    allocated += spacingPixelsVertical
-                            + rowHeights[cell.row + i];
-                }
-                if (allocated < height) {
-                    // columnWidths needs to be expanded due colspanned cell
-                    int neededExtraSpace = height - allocated;
-                    int spaceForColunms = neededExtraSpace / cell.rowspan;
-                    for (int i = 0; i < cell.rowspan; i++) {
-                        int row = cell.row + i;
-                        rowHeights[row] += spaceForColunms;
-                        neededExtraSpace -= spaceForColunms;
-                    }
-                    if (neededExtraSpace > 0) {
-                        for (int i = 0; i < cell.rowspan; i++) {
-                            int row = cell.row + i;
-                            rowHeights[row] += 1;
-                            neededExtraSpace -= 1;
-                            if (neededExtraSpace == 0) {
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private LinkedList<SpanList> colSpans = new LinkedList<SpanList>();
-    private LinkedList<SpanList> rowSpans = new LinkedList<SpanList>();
-
-    private int marginTopAndBottom;
-
-    private class SpanList {
-        final int span;
-        List<Cell> cells = new LinkedList<Cell>();
-
-        public SpanList(int span) {
-            this.span = span;
-        }
-    }
-
-    private void storeColSpannedCell(Cell cell) {
-        SpanList l = null;
-        for (SpanList list : colSpans) {
-            if (list.span < cell.colspan) {
-                continue;
-            } else {
-                // insert before this
-                l = list;
-                break;
-            }
-        }
-        if (l == null) {
-            l = new SpanList(cell.colspan);
-            colSpans.add(l);
-        } else if (l.span != cell.colspan) {
-
-            SpanList newL = new SpanList(cell.colspan);
-            colSpans.add(colSpans.indexOf(l), newL);
-            l = newL;
-        }
-        l.cells.add(cell);
-    }
-
-    private void detectSpacing(UIDL uidl) {
-        DivElement spacingmeter = Document.get().createDivElement();
-        spacingmeter.setClassName(CLASSNAME + "-" + "spacing-"
-                + (uidl.getBooleanAttribute("spacing") ? "on" : "off"));
-        spacingmeter.getStyle().setProperty("width", "0");
-        spacingmeter.getStyle().setProperty("height", "0");
-        canvas.getElement().appendChild(spacingmeter);
-        spacingPixelsHorizontal = spacingmeter.getOffsetWidth();
-        spacingPixelsVertical = spacingmeter.getOffsetHeight();
-        canvas.getElement().removeChild(spacingmeter);
-    }
-
-    private void handleMargins(UIDL uidl) {
-        final IMarginInfo margins = new IMarginInfo(uidl
-                .getIntAttribute("margins"));
-
-        String styles = CLASSNAME + "-margin";
-        if (margins.hasTop()) {
-            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_TOP;
-        }
-        if (margins.hasRight()) {
-            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT;
-        }
-        if (margins.hasBottom()) {
-            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM;
-        }
-        if (margins.hasLeft()) {
-            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_LEFT;
-        }
-        margin.setClassName(styles);
-
-        marginTopAndBottom = margin.getOffsetHeight()
-                - canvas.getOffsetHeight();
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        return paintableToCell.containsKey(component);
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        ChildComponentContainer componentContainer = widgetToComponentContainer
-                .remove(oldComponent);
-        if (componentContainer == null) {
-            return;
-        }
-
-        componentContainer.setWidget(newComponent);
-        widgetToComponentContainer.put(newComponent, componentContainer);
-
-        paintableToCell.put((Paintable) newComponent, paintableToCell
-                .get(oldComponent));
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        ChildComponentContainer cc = widgetToComponentContainer.get(component);
-        if (cc != null) {
-            cc.updateCaption(uidl, client);
-        }
-        if (!rendering) {
-            // ensure rel size details are updated
-            paintableToCell.get(component).updateRelSizeStatus(uidl);
-        }
-    }
-
-    public boolean requestLayout(final Set<Paintable> changedChildren) {
-        boolean needsLayout = false;
-        boolean reDistributeColSpanWidths = false;
-        boolean reDistributeRowSpanHeights = false;
-        int offsetHeight = canvas.getOffsetHeight();
-        int offsetWidth = canvas.getOffsetWidth();
-        if ("".equals(width) || "".equals(height)) {
-            needsLayout = true;
-        }
-        ArrayList<Integer> dirtyColumns = new ArrayList<Integer>();
-        ArrayList<Integer> dirtyRows = new ArrayList<Integer>();
-        for (Paintable paintable : changedChildren) {
-
-            Cell cell = paintableToCell.get(paintable);
-            if (!cell.hasRelativeHeight() || !cell.hasRelativeWidth()) {
-                // cell sizes will only stay still if only relatively
-                // sized
-                // components
-                // check if changed child affects min col widths
-                cell.cc.setWidth("");
-                cell.cc.setHeight("");
-
-                cell.cc.updateWidgetSize();
-                int width = cell.getWidth();
-                int allocated = columnWidths[cell.col];
-                for (int i = 1; i < cell.colspan; i++) {
-                    allocated += spacingPixelsHorizontal
-                            + columnWidths[cell.col + i];
-                }
-                if (allocated < width) {
-                    needsLayout = true;
-                    if (cell.colspan == 1) {
-                        // do simple column width expansion
-                        columnWidths[cell.col] = minColumnWidths[cell.col] = width;
-                    } else {
-                        // mark that col span expansion is needed
-                        reDistributeColSpanWidths = true;
-                    }
-                } else if (allocated != width) {
-                    // size is smaller thant allocated, column might
-                    // shrink
-                    dirtyColumns.add(cell.col);
-                }
-
-                int height = cell.getHeight();
-
-                allocated = rowHeights[cell.row];
-                for (int i = 1; i < cell.rowspan; i++) {
-                    allocated += spacingPixelsVertical
-                            + rowHeights[cell.row + i];
-                }
-                if (allocated < height) {
-                    needsLayout = true;
-                    if (cell.rowspan == 1) {
-                        // do simple row expansion
-                        rowHeights[cell.row] = minRowHeights[cell.row] = height;
-                    } else {
-                        // mark that row span expansion is needed
-                        reDistributeRowSpanHeights = true;
-                    }
-                } else if (allocated != height) {
-                    // size is smaller than allocated, row might shrink
-                    dirtyRows.add(cell.row);
-                }
-            }
-        }
-
-        if (dirtyColumns.size() > 0) {
-            for (Integer colIndex : dirtyColumns) {
-                int colW = 0;
-                for (int i = 0; i < rowHeights.length; i++) {
-                    Cell cell = cells[colIndex][i];
-                    if (cell != null && cell.getChildUIDL() != null
-                            && !cell.hasRelativeWidth() && cell.colspan == 1) {
-                        int width = cell.getWidth();
-                        if (width > colW) {
-                            colW = width;
-                        }
-                    }
-                }
-                minColumnWidths[colIndex] = colW;
-            }
-            needsLayout = true;
-            // ensure colspanned columns have enough space
-            columnWidths = cloneArray(minColumnWidths);
-            distributeColSpanWidths();
-            reDistributeColSpanWidths = false;
-        }
-
-        if (reDistributeColSpanWidths) {
-            distributeColSpanWidths();
-        }
-
-        if (dirtyRows.size() > 0) {
-            needsLayout = true;
-            for (Integer rowIndex : dirtyRows) {
-                // recalculate min row height
-                int rowH = minRowHeights[rowIndex] = 0;
-                // loop all columns on row rowIndex
-                for (int i = 0; i < columnWidths.length; i++) {
-                    Cell cell = cells[i][rowIndex];
-                    if (cell != null && cell.getChildUIDL() != null
-                            && !cell.hasRelativeHeight() && cell.rowspan == 1) {
-                        int h = cell.getHeight();
-                        if (h > rowH) {
-                            rowH = h;
-                        }
-                    }
-                }
-                minRowHeights[rowIndex] = rowH;
-            }
-            // TODO could check only some row spans
-            rowHeights = cloneArray(minRowHeights);
-            distributeRowSpanHeights();
-            reDistributeRowSpanHeights = false;
-        }
-
-        if (reDistributeRowSpanHeights) {
-            distributeRowSpanHeights();
-        }
-
-        if (needsLayout) {
-            expandColumns();
-            expandRows();
-            layoutCells();
-            // loop all relative sized components and update their size
-            for (int i = 0; i < cells.length; i++) {
-                for (int j = 0; j < cells[i].length; j++) {
-                    Cell cell = cells[i][j];
-                    if (cell != null
-                            && cell.cc != null
-                            && (cell.hasRelativeHeight() || cell
-                                    .hasRelativeWidth())) {
-                        client.handleComponentRelativeSize(cell.cc.getWidget());
-                    }
-                }
-            }
-        }
-        if (canvas.getOffsetHeight() != offsetHeight
-                || canvas.getOffsetWidth() != offsetWidth) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        Cell cell = paintableToCell.get(child);
-        assert cell != null;
-        return cell.getAllocatedSpace();
-    }
-
-    private Cell[][] cells;
-
-    /**
-     * Private helper class.
-     */
-    private class Cell {
-        private boolean relHeight = false;
-        private boolean relWidth = false;
-        private boolean widthCanAffectHeight = false;
-
-        public Cell(UIDL c) {
-            row = c.getIntAttribute("y");
-            col = c.getIntAttribute("x");
-            setUidl(c);
-        }
-
-        public boolean widthCanAffectHeight() {
-            return widthCanAffectHeight;
-        }
-
-        public boolean hasRelativeHeight() {
-            return relHeight;
-        }
-
-        public RenderSpace getAllocatedSpace() {
-            return new RenderSpace(getAvailableWidth()
-                    - cc.getCaptionWidthAfterComponent(), getAvailableHeight()
-                    - cc.getCaptionHeightAboveComponent());
-        }
-
-        public boolean hasContent() {
-            return childUidl != null;
-        }
-
-        /**
-         * @return total of spanned cols
-         */
-        private int getAvailableWidth() {
-            int width = columnWidths[col];
-            for (int i = 1; i < colspan; i++) {
-                width += spacingPixelsHorizontal + columnWidths[col + i];
-            }
-            return width;
-        }
-
-        /**
-         * @return total of spanned rows
-         */
-        private int getAvailableHeight() {
-            int height = rowHeights[row];
-            for (int i = 1; i < rowspan; i++) {
-                height += spacingPixelsVertical + rowHeights[row + i];
-            }
-            return height;
-        }
-
-        public void layout(int x, int y) {
-            if (cc != null && cc.isAttached()) {
-                canvas.setWidgetPosition(cc, x, y);
-                cc.setContainerSize(getAvailableWidth(), getAvailableHeight());
-                cc.setAlignment(new AlignmentInfo(alignment));
-                cc.updateAlignments(getAvailableWidth(), getAvailableHeight());
-            }
-        }
-
-        public int getWidth() {
-            if (cc != null) {
-                int w = cc.getWidgetSize().getWidth()
-                        + cc.getCaptionWidthAfterComponent();
-                return w;
-            } else {
-                return 0;
-            }
-        }
-
-        public int getHeight() {
-            if (cc != null) {
-                return cc.getWidgetSize().getHeight()
-                        + cc.getCaptionHeightAboveComponent();
-            } else {
-                return 0;
-            }
-        }
-
-        public boolean renderIfNoRelativeWidth() {
-            if (childUidl == null) {
-                return false;
-            }
-            if (!hasRelativeWidth()) {
-                render();
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        protected boolean hasRelativeWidth() {
-            return relWidth;
-        }
-
-        protected void render() {
-            assert childUidl != null;
-
-            Paintable paintable = client.getPaintable(childUidl);
-            assert paintable != null;
-            if (cc == null || cc.getWidget() != paintable) {
-                if (widgetToComponentContainer.containsKey(paintable)) {
-                    cc = widgetToComponentContainer.get(paintable);
-                    cc.setWidth("");
-                    cc.setHeight("");
-                } else {
-                    cc = new ChildComponentContainer((Widget) paintable,
-                            CellBasedLayout.ORIENTATION_VERTICAL);
-                    widgetToComponentContainer.put((Widget) paintable, cc);
-                    paintableToCell.put(paintable, this);
-                    cc.setWidth("");
-                    canvas.add(cc, 0, 0);
-                }
-            }
-            cc.renderChild(childUidl, client, -1);
-            if (sizeChangedDuringRendering && Util.isCached(childUidl)) {
-                client.handleComponentRelativeSize(cc.getWidget());
-            }
-            cc.updateWidgetSize();
-            nonRenderedWidgets.remove(paintable);
-        }
-
-        public UIDL getChildUIDL() {
-            return childUidl;
-        }
-
-        final int row;
-        final int col;
-        int colspan = 1;
-        int rowspan = 1;
-        UIDL childUidl;
-        int alignment;
-        ChildComponentContainer cc;
-
-        public void setUidl(UIDL c) {
-            // Set cell width
-            colspan = c.hasAttribute("w") ? c.getIntAttribute("w") : 1;
-            // Set cell height
-            rowspan = c.hasAttribute("h") ? c.getIntAttribute("h") : 1;
-            // ensure we will lose reference to old cells, now overlapped by
-            // this cell
-            for (int i = 0; i < colspan; i++) {
-                for (int j = 0; j < rowspan; j++) {
-                    if (i > 0 || j > 0) {
-                        cells[col + i][row + j] = null;
-                    }
-                }
-            }
-
-            c = c.getChildUIDL(0); // we are interested about childUidl
-            if (childUidl != null) {
-                if (c == null) {
-                    // content has vanished, old content will be removed from
-                    // canvas
-                    // later durin render phase
-                    cc = null;
-                } else if (cc != null
-                        && cc.getWidget() != client.getPaintable(c)) {
-                    // content has changed
-                    cc = null;
-                    if (widgetToComponentContainer.containsKey(client
-                            .getPaintable(c))) {
-                        // cc exist for this component (moved) use that for this
-                        // cell
-                        cc = widgetToComponentContainer.get(client
-                                .getPaintable(c));
-                        cc.setWidth("");
-                        cc.setHeight("");
-                    }
-                }
-            }
-            childUidl = c;
-            updateRelSizeStatus(c);
-        }
-
-        protected void updateRelSizeStatus(UIDL uidl) {
-            if (uidl != null && !uidl.getBooleanAttribute("cached")) {
-                if (uidl.hasAttribute("height")
-                        && uidl.getStringAttribute("height").contains("%")) {
-                    relHeight = true;
-                } else {
-                    relHeight = false;
-                }
-                if (uidl.hasAttribute("width")) {
-                    widthCanAffectHeight = relWidth = uidl.getStringAttribute(
-                            "width").contains("%");
-                    if (uidl.hasAttribute("height")) {
-                        widthCanAffectHeight = false;
-                    }
-                } else {
-                    widthCanAffectHeight = !uidl.hasAttribute("height");
-                    relWidth = false;
-                }
-            }
-        }
-    }
-
-    private Cell getCell(UIDL c) {
-        int row = c.getIntAttribute("y");
-        int col = c.getIntAttribute("x");
-        Cell cell = cells[col][row];
-        if (cell == null) {
-            cell = new Cell(c);
-            cells[col][row] = cell;
-        } else {
-            cell.setUidl(c);
-        }
-        return cell;
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IHorizontalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/IHorizontalLayout.java
deleted file mode 100644 (file)
index eeb2c1d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-public class IHorizontalLayout extends IOrderedLayout {\r
-\r
-    public static final String CLASSNAME = "i-horizontallayout";\r
-\r
-    public IHorizontalLayout() {\r
-        super(CLASSNAME, ORIENTATION_HORIZONTAL);\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ILabel.java b/src/com/vaadin/terminal/gwt/client/ui/ILabel.java
deleted file mode 100644 (file)
index c1ef09d..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.PreElement;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.HTML;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class ILabel extends HTML implements Paintable {
-
-    public static final String CLASSNAME = "i-label";
-    private static final String CLASSNAME_UNDEFINED_WIDTH = "i-label-undef-w";
-
-    private ApplicationConnection client;
-    private int verticalPaddingBorder = 0;
-    private int horizontalPaddingBorder = 0;
-
-    public ILabel() {
-        super();
-        setStyleName(CLASSNAME);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-    }
-
-    public ILabel(String text) {
-        super(text);
-        setStyleName(CLASSNAME);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        if (event.getTypeInt() == Event.ONLOAD) {
-            Util.notifyParentOfSizeChange(this, true);
-            event.cancelBubble(true);
-            return;
-        }
-        if (client != null) {
-            client.handleTooltipEvent(event, this);
-        }
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        this.client = client;
-
-        boolean sinkOnloads = false;
-
-        final String mode = uidl.getStringAttribute("mode");
-        if (mode == null || "text".equals(mode)) {
-            setText(uidl.getChildString(0));
-        } else if ("pre".equals(mode)) {
-            PreElement preElement = Document.get().createPreElement();
-            preElement.setInnerText(uidl.getChildUIDL(0).getChildString(0));
-            // clear existing content
-            setHTML("");
-            // add preformatted text to dom
-            getElement().appendChild(preElement);
-        } else if ("uidl".equals(mode)) {
-            setHTML(uidl.getChildrenAsXML());
-        } else if ("xhtml".equals(mode)) {
-            UIDL content = uidl.getChildUIDL(0).getChildUIDL(0);
-            if (content.getChildCount() > 0) {
-                setHTML(content.getChildString(0));
-            } else {
-                setHTML("");
-            }
-            sinkOnloads = true;
-        } else if ("xml".equals(mode)) {
-            setHTML(uidl.getChildUIDL(0).getChildString(0));
-        } else if ("raw".equals(mode)) {
-            setHTML(uidl.getChildUIDL(0).getChildString(0));
-            sinkOnloads = true;
-        } else {
-            setText("");
-        }
-        if (sinkOnloads) {
-            sinkOnloadsForContainedImgs();
-        }
-    }
-
-    private void sinkOnloadsForContainedImgs() {
-        NodeList<Element> images = getElement().getElementsByTagName("img");
-        for (int i = 0; i < images.getLength(); i++) {
-            Element img = images.getItem(i);
-            DOM.sinkEvents((com.google.gwt.user.client.Element) img,
-                    Event.ONLOAD);
-        }
-
-    }
-
-    @Override
-    public void setHeight(String height) {
-        verticalPaddingBorder = Util.setHeightExcludingPaddingAndBorder(this,
-                height, verticalPaddingBorder);
-    }
-
-    @Override
-    public void setWidth(String width) {
-        horizontalPaddingBorder = Util.setWidthExcludingPaddingAndBorder(this,
-                width, horizontalPaddingBorder);
-        if (width == null || width.equals("")) {
-            setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true);
-        } else {
-            setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false);
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ILink.java b/src/com/vaadin/terminal/gwt/client/ui/ILink.java
deleted file mode 100644 (file)
index 2d09c21..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-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.ClickListener;
-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.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class ILink extends HTML implements Paintable, ClickListener {
-
-    public static final String CLASSNAME = "i-link";
-
-    private static final int BORDER_STYLE_DEFAULT = 0;
-    private static final int BORDER_STYLE_MINIMAL = 1;
-    private static final int BORDER_STYLE_NONE = 2;
-
-    private String src;
-
-    private String target;
-
-    private int borderStyle = BORDER_STYLE_DEFAULT;
-
-    private boolean enabled;
-
-    private boolean readonly;
-
-    private int targetWidth;
-
-    private int targetHeight;
-
-    private Element errorIndicatorElement;
-
-    private final Element anchor = DOM.createAnchor();
-
-    private final Element captionElement = DOM.createSpan();
-
-    private Icon icon;
-
-    private ApplicationConnection client;
-
-    public ILink() {
-        super();
-        getElement().appendChild(anchor);
-        anchor.appendChild(captionElement);
-        addClickListener(this);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-        setStyleName(CLASSNAME);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
-        // Ensure correct implementation,
-        // but don't let container manage caption etc.
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-
-        this.client = client;
-
-        enabled = uidl.hasAttribute("disabled") ? false : true;
-        readonly = uidl.hasAttribute("readonly") ? true : false;
-
-        if (uidl.hasAttribute("name")) {
-            target = uidl.getStringAttribute("name");
-            anchor.setAttribute("target", target);
-        }
-        if (uidl.hasAttribute("src")) {
-            src = client.translateToolkitUri(uidl.getStringAttribute("src"));
-            anchor.setAttribute("href", src);
-        }
-
-        if (uidl.hasAttribute("border")) {
-            if ("none".equals(uidl.getStringAttribute("border"))) {
-                borderStyle = BORDER_STYLE_NONE;
-            } else {
-                borderStyle = BORDER_STYLE_MINIMAL;
-            }
-        } else {
-            borderStyle = BORDER_STYLE_DEFAULT;
-        }
-
-        targetHeight = uidl.hasAttribute("targetHeight") ? uidl
-                .getIntAttribute("targetHeight") : -1;
-        targetWidth = uidl.hasAttribute("targetWidth") ? uidl
-                .getIntAttribute("targetWidth") : -1;
-
-        // Set link caption
-        captionElement.setInnerText(uidl.getStringAttribute("caption"));
-
-        // handle error
-        if (uidl.hasAttribute("error")) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "i-errorindicator");
-            }
-            DOM.insertChild(getElement(), errorIndicatorElement, 0);
-        } else if (errorIndicatorElement != null) {
-            DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
-        }
-
-        if (uidl.hasAttribute("icon")) {
-            if (icon == null) {
-                icon = new Icon(client);
-                anchor.insertBefore(icon.getElement(), captionElement);
-            }
-            icon.setUri(uidl.getStringAttribute("icon"));
-        }
-
-    }
-
-    public void onClick(Widget sender) {
-        if (enabled && !readonly) {
-            if (target == null) {
-                target = "_self";
-            }
-            String features;
-            switch (borderStyle) {
-            case BORDER_STYLE_NONE:
-                features = "menubar=no,location=no,status=no";
-                break;
-            case BORDER_STYLE_MINIMAL:
-                features = "menubar=yes,location=no,status=no";
-                break;
-            default:
-                features = "";
-                break;
-            }
-
-            if (targetWidth > 0) {
-                features += (features.length() > 0 ? "," : "") + "width="
-                        + targetWidth;
-            }
-            if (targetHeight > 0) {
-                features += (features.length() > 0 ? "," : "") + "height="
-                        + targetHeight;
-            }
-
-            if (features.length() > 0) {
-                // if 'special features' are set, use window.open(), unless
-                // a modifier key is held (ctrl to open in new tab etc)
-                Event e = DOM.eventGetCurrentEvent();
-                if (!e.getCtrlKey() && !e.getAltKey() && !e.getShiftKey()
-                        && !e.getMetaKey()) {
-                    Window.open(src, target, features);
-                    e.preventDefault();
-                }
-            }
-        }
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        final Element target = DOM.eventGetTarget(event);
-        if (event.getTypeInt() == Event.ONLOAD) {
-            Util.notifyParentOfSizeChange(this, true);
-        }
-        if (client != null) {
-            client.handleTooltipEvent(event, this);
-        }
-        if (target == captionElement || target == anchor
-                || (icon != null && target == icon.getElement())) {
-            super.onBrowserEvent(event);
-        }
-        if (!enabled) {
-            event.preventDefault();
-        }
-
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IListSelect.java b/src/com/vaadin/terminal/gwt/client/ui/IListSelect.java
deleted file mode 100644 (file)
index 301c7aa..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Iterator;
-import java.util.Vector;
-
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IListSelect extends IOptionGroupBase {
-
-    public static final String CLASSNAME = "i-select";
-
-    private static final int VISIBLE_COUNT = 10;
-
-    protected TooltipListBox select;
-
-    private int lastSelectedIndex = -1;
-
-    public IListSelect() {
-        super(new TooltipListBox(true), CLASSNAME);
-        select = (TooltipListBox) optionsContainer;
-        select.setSelect(this);
-        select.addChangeListener(this);
-        select.addClickListener(this);
-        select.setStyleName(CLASSNAME + "-select");
-        select.setVisibleItemCount(VISIBLE_COUNT);
-    }
-
-    @Override
-    protected void buildOptions(UIDL uidl) {
-        select.setClient(client);
-        select.setMultipleSelect(isMultiselect());
-        select.setEnabled(!isDisabled() && !isReadonly());
-        select.clear();
-        if (!isMultiselect() && isNullSelectionAllowed()
-                && !isNullSelectionItemAvailable()) {
-            // can't unselect last item in singleselect mode
-            select.addItem("", null);
-        }
-        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
-            final UIDL optionUidl = (UIDL) i.next();
-            select.addItem(optionUidl.getStringAttribute("caption"), optionUidl
-                    .getStringAttribute("key"));
-            if (optionUidl.hasAttribute("selected")) {
-                select.setItemSelected(select.getItemCount() - 1, true);
-            }
-        }
-        if (getRows() > 0) {
-            select.setVisibleItemCount(getRows());
-        }
-    }
-
-    @Override
-    protected Object[] getSelectedItems() {
-        final Vector selectedItemKeys = new Vector();
-        for (int i = 0; i < select.getItemCount(); i++) {
-            if (select.isItemSelected(i)) {
-                selectedItemKeys.add(select.getValue(i));
-            }
-        }
-        return selectedItemKeys.toArray();
-    }
-
-    @Override
-    public void onChange(Widget sender) {
-        final int si = select.getSelectedIndex();
-        if (si == -1 && !isNullSelectionAllowed()) {
-            select.setSelectedIndex(lastSelectedIndex);
-        } else {
-            lastSelectedIndex = si;
-            if (isMultiselect()) {
-                client.updateVariable(id, "selected", getSelectedItems(),
-                        isImmediate());
-            } else {
-                client.updateVariable(id, "selected", new String[] { ""
-                        + getSelectedItem() }, isImmediate());
-            }
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        select.setHeight(height);
-        super.setHeight(height);
-    }
-
-    @Override
-    public void setWidth(String width) {
-        select.setWidth(width);
-        super.setWidth(width);
-    }
-
-    @Override
-    protected void setTabIndex(int tabIndex) {
-        ((TooltipListBox) optionsContainer).setTabIndex(tabIndex);
-    }
-
-    public void focus() {
-        select.setFocus(true);
-    }
-
-}
-
-/**
- * Extended ListBox to listen tooltip events and forward them to generic
- * handler.
- */
-class TooltipListBox extends ListBox {
-    private ApplicationConnection client;
-    private Paintable pntbl;
-
-    TooltipListBox(boolean isMultiselect) {
-        super(isMultiselect);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-    }
-
-    public void setClient(ApplicationConnection client) {
-        this.client = client;
-    }
-
-    public void setSelect(Paintable s) {
-        pntbl = s;
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        if (client != null) {
-            client.handleTooltipEvent(event, pntbl);
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IMarginInfo.java b/src/com/vaadin/terminal/gwt/client/ui/IMarginInfo.java
deleted file mode 100644 (file)
index 9366393..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.io.Serializable;
-
-@SuppressWarnings("serial")
-public class IMarginInfo implements Serializable {
-
-    private static final int TOP = 1;
-    private static final int RIGHT = 2;
-    private static final int BOTTOM = 4;
-    private static final int LEFT = 8;
-
-    private int bitMask;
-
-    public IMarginInfo(int bitMask) {
-        this.bitMask = bitMask;
-    }
-
-    public IMarginInfo(boolean top, boolean right, boolean bottom, boolean left) {
-        setMargins(top, right, bottom, left);
-    }
-
-    public void setMargins(boolean top, boolean right, boolean bottom,
-            boolean left) {
-        bitMask = top ? TOP : 0;
-        bitMask += right ? RIGHT : 0;
-        bitMask += bottom ? BOTTOM : 0;
-        bitMask += left ? LEFT : 0;
-    }
-
-    public void setMargins(IMarginInfo marginInfo) {
-        bitMask = marginInfo.bitMask;
-    }
-
-    public boolean hasLeft() {
-        return (bitMask & LEFT) == LEFT;
-    }
-
-    public boolean hasRight() {
-        return (bitMask & RIGHT) == RIGHT;
-    }
-
-    public boolean hasTop() {
-        return (bitMask & TOP) == TOP;
-    }
-
-    public boolean hasBottom() {
-        return (bitMask & BOTTOM) == BOTTOM;
-    }
-
-    public int getBitMask() {
-        return bitMask;
-    }
-
-    public void setMargins(boolean enabled) {
-        if (enabled) {
-            bitMask = TOP + RIGHT + BOTTOM + LEFT;
-        } else {
-            bitMask = 0;
-        }
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (!(obj instanceof IMarginInfo)) {
-            return false;
-        }
-
-        return ((IMarginInfo) obj).bitMask == bitMask;
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/IMenuBar.java
deleted file mode 100644 (file)
index bb9a3d5..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Stack;
-
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.HasHTML;
-import com.google.gwt.user.client.ui.PopupListener;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.UIObject;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IMenuBar extends Widget implements Paintable, PopupListener {
-
-    /** Set the CSS class name to allow styling. */
-    public static final String CLASSNAME = "i-menubar";
-
-    /** For server connections **/
-    protected String uidlId;
-    protected ApplicationConnection client;
-
-    protected final IMenuBar hostReference = this;
-    protected String submenuIcon = null;
-    protected boolean collapseItems = true;
-    protected CustomMenuItem moreItem = null;
-
-    // Construct an empty command to be used when the item has no command
-    // associated
-    protected static final Command emptyCommand = null;
-
-    /** Widget fields **/
-    protected boolean subMenu;
-    protected ArrayList<CustomMenuItem> items;
-    protected Element containerElement;
-    protected IToolkitOverlay popup;
-    protected IMenuBar visibleChildMenu;
-    protected IMenuBar parentMenu;
-    protected CustomMenuItem selected;
-
-    public IMenuBar() {
-        // Create an empty horizontal menubar
-        this(false);
-    }
-
-    public IMenuBar(boolean subMenu) {
-        super();
-        setElement(DOM.createDiv());
-
-        items = new ArrayList<CustomMenuItem>();
-        popup = null;
-        visibleChildMenu = null;
-
-        Element table = DOM.createTable();
-        Element tbody = DOM.createTBody();
-        DOM.appendChild(getElement(), table);
-        DOM.appendChild(table, tbody);
-
-        if (!subMenu) {
-            setStyleName(CLASSNAME);
-            Element tr = DOM.createTR();
-            DOM.appendChild(tbody, tr);
-            containerElement = tr;
-        } else {
-            setStyleName(CLASSNAME + "-submenu");
-            containerElement = tbody;
-        }
-        this.subMenu = subMenu;
-
-        sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT);
-    }
-
-    /**
-     * This method must be implemented to update the client-side component from
-     * UIDL data received from server.
-     * 
-     * This method is called when the page is loaded for the first time, and
-     * every time UI changes in the component are received from the server.
-     */
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // This call should be made first. Ensure correct implementation,
-        // and let the containing layout manage caption, etc.
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        // For future connections
-        this.client = client;
-        uidlId = uidl.getId();
-
-        // Empty the menu every time it receives new information
-        if (!getItems().isEmpty()) {
-            clearItems();
-        }
-
-        UIDL options = uidl.getChildUIDL(0);
-
-        if (options.hasAttribute("submenuIcon")) {
-            submenuIcon = client.translateToolkitUri(uidl.getChildUIDL(0)
-                    .getStringAttribute("submenuIcon"));
-        } else {
-            submenuIcon = null;
-        }
-
-        collapseItems = options.getBooleanAttribute("collapseItems");
-
-        if (collapseItems) {
-            UIDL moreItemUIDL = options.getChildUIDL(0);
-            StringBuffer itemHTML = new StringBuffer();
-
-            if (moreItemUIDL.hasAttribute("icon")) {
-                itemHTML.append("<img src=\""
-                        + client.translateToolkitUri(moreItemUIDL
-                                .getStringAttribute("icon"))
-                        + "\" align=\"left\" />");
-            }
-            itemHTML.append(moreItemUIDL.getStringAttribute("text"));
-
-            moreItem = new CustomMenuItem(itemHTML.toString(), emptyCommand);
-        }
-
-        UIDL uidlItems = uidl.getChildUIDL(1);
-        Iterator<UIDL> itr = uidlItems.getChildIterator();
-        Stack<Iterator<UIDL>> iteratorStack = new Stack<Iterator<UIDL>>();
-        Stack<IMenuBar> menuStack = new Stack<IMenuBar>();
-        IMenuBar currentMenu = this;
-
-        while (itr.hasNext()) {
-            UIDL item = (UIDL) itr.next();
-            CustomMenuItem currentItem = null;
-
-            String itemText = item.getStringAttribute("text");
-            final int itemId = item.getIntAttribute("id");
-
-            boolean itemHasCommand = item.getBooleanAttribute("command");
-
-            // Construct html from the text and the optional icon
-            StringBuffer itemHTML = new StringBuffer();
-
-            if (item.hasAttribute("icon")) {
-                itemHTML.append("<img src=\""
-                        + client.translateToolkitUri(item
-                                .getStringAttribute("icon"))
-                        + "\" align=\"left\" />");
-            }
-
-            itemHTML.append(itemText);
-
-            if (currentMenu != this && item.getChildCount() > 0
-                    && submenuIcon != null) {
-                itemHTML.append("<img src=\"" + submenuIcon
-                        + "\" align=\"right\" />");
-            }
-
-            Command cmd = null;
-
-            if (itemHasCommand) {
-                // Construct a command that fires onMenuClick(int) with the
-                // item's id-number
-                cmd = new Command() {
-                    public void execute() {
-                        hostReference.onMenuClick(itemId);
-                    }
-                };
-            }
-
-            currentItem = currentMenu.addItem(itemHTML.toString(), cmd);
-
-            if (item.getChildCount() > 0) {
-                menuStack.push(currentMenu);
-                iteratorStack.push(itr);
-                itr = item.getChildIterator();
-                currentMenu = new IMenuBar(true);
-                currentItem.setSubMenu(currentMenu);
-            }
-
-            while (!itr.hasNext() && !iteratorStack.empty()) {
-                itr = iteratorStack.pop();
-                currentMenu = (IMenuBar) menuStack.pop();
-            }
-        }// while
-
-        // we might need to collapse the top-level menu
-        if (collapseItems) {
-            int topLevelWidth = 0;
-
-            int ourWidth = getOffsetWidth();
-
-            int i = 0;
-            for (; i < getItems().size() && topLevelWidth < ourWidth; i++) {
-                CustomMenuItem item = (CustomMenuItem) getItems().get(i);
-                topLevelWidth += item.getOffsetWidth();
-            }
-
-            if (topLevelWidth > getOffsetWidth()) {
-                ArrayList<CustomMenuItem> toBeCollapsed = new ArrayList<CustomMenuItem>();
-                IMenuBar collapsed = new IMenuBar(true);
-                for (int j = i - 2; j < getItems().size(); j++) {
-                    toBeCollapsed.add(getItems().get(j));
-                }
-
-                for (int j = 0; j < toBeCollapsed.size(); j++) {
-                    CustomMenuItem item = (CustomMenuItem) toBeCollapsed.get(j);
-                    removeItem(item);
-
-                    // it's ugly, but we have to insert the submenu icon
-                    if (item.getSubMenu() != null && submenuIcon != null) {
-                        StringBuffer itemText = new StringBuffer(item.getHTML());
-                        itemText.append("<img src=\"");
-                        itemText.append(submenuIcon);
-                        itemText.append("\" align=\"right\" />");
-                        item.setHTML(itemText.toString());
-                    }
-
-                    collapsed.addItem(item);
-                }
-
-                moreItem.setSubMenu(collapsed);
-                addItem(moreItem);
-            }
-        }
-    }// updateFromUIDL
-
-    /**
-     * This is called by the items in the menu and it communicates the
-     * information to the server
-     * 
-     * @param clickedItemId
-     *            id of the item that was clicked
-     */
-    public void onMenuClick(int clickedItemId) {
-        // Updating the state to the server can not be done before
-        // the server connection is known, i.e., before updateFromUIDL()
-        // has been called.
-        if (uidlId != null && client != null) {
-            // Communicate the user interaction parameters to server. This call
-            // will initiate an AJAX request to the server.
-            client.updateVariable(uidlId, "clickedId", clickedItemId, true);
-        }
-    }
-
-    /** Widget methods **/
-
-    /**
-     * Returns a list of items in this menu
-     */
-    public List<CustomMenuItem> getItems() {
-        return items;
-    }
-
-    /**
-     * Remove all the items in this menu
-     */
-    public void clearItems() {
-        Element e = getContainingElement();
-        while (DOM.getChildCount(e) > 0) {
-            DOM.removeChild(e, DOM.getChild(e, 0));
-        }
-        items.clear();
-    }
-
-    /**
-     * Returns the containing element of the menu
-     * 
-     * @return
-     */
-    public Element getContainingElement() {
-        return containerElement;
-    }
-
-    /**
-     * Returns a new child element to add an item to
-     * 
-     * @return
-     */
-    public Element getNewChildElement() {
-        if (subMenu) {
-            Element tr = DOM.createTR();
-            DOM.appendChild(getContainingElement(), tr);
-            return tr;
-        } else {
-            return getContainingElement();
-        }
-
-    }
-
-    /**
-     * Add a new item to this menu
-     * 
-     * @param html
-     *            items text
-     * @param cmd
-     *            items command
-     * @return the item created
-     */
-    public CustomMenuItem addItem(String html, Command cmd) {
-        CustomMenuItem item = new CustomMenuItem(html, cmd);
-        addItem(item);
-        return item;
-    }
-
-    /**
-     * Add a new item to this menu
-     * 
-     * @param item
-     */
-    public void addItem(CustomMenuItem item) {
-        DOM.appendChild(getNewChildElement(), item.getElement());
-        item.setParentMenu(this);
-        item.setSelected(false);
-        items.add(item);
-    }
-
-    /**
-     * Remove the given item from this menu
-     * 
-     * @param item
-     */
-    public void removeItem(CustomMenuItem item) {
-        if (items.contains(item)) {
-            int index = items.indexOf(item);
-            Element container = getContainingElement();
-
-            DOM.removeChild(container, DOM.getChild(container, index));
-            items.remove(index);
-        }
-    }
-
-    /*
-     * @see
-     * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt.user
-     * .client.Event)
-     */
-    @Override
-    public void onBrowserEvent(Event e) {
-        super.onBrowserEvent(e);
-
-        Element targetElement = DOM.eventGetTarget(e);
-        CustomMenuItem targetItem = null;
-        for (int i = 0; i < items.size(); i++) {
-            CustomMenuItem item = (CustomMenuItem) items.get(i);
-            if (DOM.isOrHasChild(item.getElement(), targetElement)) {
-                targetItem = item;
-            }
-        }
-
-        if (targetItem != null) {
-            switch (DOM.eventGetType(e)) {
-
-            case Event.ONCLICK:
-                itemClick(targetItem);
-                break;
-
-            case Event.ONMOUSEOVER:
-                itemOver(targetItem);
-                break;
-
-            case Event.ONMOUSEOUT:
-                itemOut(targetItem);
-                break;
-            }
-        }
-    }
-
-    /**
-     * When an item is clicked
-     * 
-     * @param item
-     */
-    public void itemClick(CustomMenuItem item) {
-        if (item.getCommand() != null) {
-            setSelected(null);
-
-            if (visibleChildMenu != null) {
-                visibleChildMenu.hideChildren();
-            }
-
-            hideParents();
-            DeferredCommand.addCommand(item.getCommand());
-
-        } else {
-            if (item.getSubMenu() != null
-                    && item.getSubMenu() != visibleChildMenu) {
-                setSelected(item);
-                showChildMenu(item);
-            }
-        }
-    }
-
-    /**
-     * When the user hovers the mouse over the item
-     * 
-     * @param item
-     */
-    public void itemOver(CustomMenuItem item) {
-        setSelected(item);
-
-        boolean menuWasVisible = visibleChildMenu != null;
-
-        if (menuWasVisible && visibleChildMenu != item.getSubMenu()) {
-            popup.hide();
-            visibleChildMenu = null;
-        }
-
-        if (item.getSubMenu() != null && (parentMenu != null || menuWasVisible)
-                && visibleChildMenu != item.getSubMenu()) {
-            showChildMenu(item);
-        }
-    }
-
-    /**
-     * When the mouse is moved away from an item
-     * 
-     * @param item
-     */
-    public void itemOut(CustomMenuItem item) {
-        if (visibleChildMenu != item.getSubMenu() || visibleChildMenu == null) {
-            hideChildMenu(item);
-            setSelected(null);
-        }
-    }
-
-    /**
-     * Shows the child menu of an item. The caller must ensure that the item has
-     * a submenu.
-     * 
-     * @param item
-     */
-    public void showChildMenu(CustomMenuItem item) {
-        popup = new IToolkitOverlay(true, false, true);
-        popup.setWidget(item.getSubMenu());
-        popup.addPopupListener(this);
-
-        if (subMenu) {
-            popup.setPopupPosition(item.getParentMenu().getAbsoluteLeft()
-                    + item.getParentMenu().getOffsetWidth(), item
-                    .getAbsoluteTop());
-        } else {
-            popup.setPopupPosition(item.getAbsoluteLeft(), item.getParentMenu()
-                    .getAbsoluteTop()
-                    + item.getParentMenu().getOffsetHeight());
-        }
-
-        item.getSubMenu().onShow();
-        visibleChildMenu = item.getSubMenu();
-        item.getSubMenu().setParentMenu(this);
-
-        popup.show();
-    }
-
-    /**
-     * Hides the submenu of an item
-     * 
-     * @param item
-     */
-    public void hideChildMenu(CustomMenuItem item) {
-        if (visibleChildMenu != null
-                && !(visibleChildMenu == item.getSubMenu())) {
-            popup.hide();
-
-        }
-    }
-
-    /**
-     * When the menu is shown.
-     */
-    public void onShow() {
-        if (!items.isEmpty()) {
-            ((CustomMenuItem) items.get(0)).setSelected(true);
-        }
-    }
-
-    /**
-     * Recursively hide all child menus
-     */
-    public void hideChildren() {
-        if (visibleChildMenu != null) {
-            visibleChildMenu.hideChildren();
-            popup.hide();
-        }
-    }
-
-    /**
-     * Recursively hide all parent menus
-     */
-    public void hideParents() {
-
-        if (visibleChildMenu != null) {
-            popup.hide();
-            setSelected(null);
-        }
-
-        if (getParentMenu() != null) {
-            getParentMenu().hideParents();
-        }
-    }
-
-    /**
-     * Returns the parent menu of this menu, or null if this is the top-level
-     * menu
-     * 
-     * @return
-     */
-    public IMenuBar getParentMenu() {
-        return parentMenu;
-    }
-
-    /**
-     * Set the parent menu of this menu
-     * 
-     * @param parent
-     */
-    public void setParentMenu(IMenuBar parent) {
-        parentMenu = parent;
-    }
-
-    /**
-     * Returns the currently selected item of this menu, or null if nothing is
-     * selected
-     * 
-     * @return
-     */
-    public CustomMenuItem getSelected() {
-        return selected;
-    }
-
-    /**
-     * Set the currently selected item of this menu
-     * 
-     * @param item
-     */
-    public void setSelected(CustomMenuItem item) {
-        // If we had something selected, unselect
-        if (item != selected && selected != null) {
-            selected.setSelected(false);
-        }
-        // If we have a valid selection, select it
-        if (item != null) {
-            item.setSelected(true);
-        }
-
-        selected = item;
-    }
-
-    /**
-     * Listener method, fired when this menu is closed
-     */
-    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
-        hideChildren();
-        if (autoClosed) {
-            hideParents();
-        }
-        // setSelected(null);
-        visibleChildMenu = null;
-        popup = null;
-
-    }
-
-    /**
-     * 
-     * A class to hold information on menu items
-     * 
-     */
-    private class CustomMenuItem extends UIObject implements HasHTML {
-
-        protected String html = null;
-        protected Command command = null;
-        protected IMenuBar subMenu = null;
-        protected IMenuBar parentMenu = null;
-
-        public CustomMenuItem(String html, Command cmd) {
-            setElement(DOM.createTD());
-
-            setHTML(html);
-            setCommand(cmd);
-            setSelected(false);
-
-            addStyleName("menuitem");
-        }
-
-        public void setSelected(boolean selected) {
-            if (selected) {
-                addStyleDependentName("selected");
-            } else {
-                removeStyleDependentName("selected");
-            }
-        }
-
-        /*
-         * setters and getters for the fields
-         */
-
-        public void setSubMenu(IMenuBar subMenu) {
-            this.subMenu = subMenu;
-        }
-
-        public IMenuBar getSubMenu() {
-            return subMenu;
-        }
-
-        public void setParentMenu(IMenuBar parentMenu) {
-            this.parentMenu = parentMenu;
-        }
-
-        public IMenuBar getParentMenu() {
-            return parentMenu;
-        }
-
-        public void setCommand(Command command) {
-            this.command = command;
-        }
-
-        public Command getCommand() {
-            return command;
-        }
-
-        public String getHTML() {
-            return html;
-        }
-
-        public void setHTML(String html) {
-            this.html = html;
-            DOM.setInnerHTML(getElement(), html);
-        }
-
-        public String getText() {
-            return html;
-        }
-
-        public void setText(String text) {
-            setHTML(text);
-
-        }
-    }
-
-}// class IMenuBar
diff --git a/src/com/vaadin/terminal/gwt/client/ui/INativeSelect.java b/src/com/vaadin/terminal/gwt/client/ui/INativeSelect.java
deleted file mode 100644 (file)
index 3b063bb..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Iterator;
-import java.util.Vector;
-
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class INativeSelect extends IOptionGroupBase implements Field {
-
-    public static final String CLASSNAME = "i-select";
-
-    protected TooltipListBox select;
-
-    public INativeSelect() {
-        super(new TooltipListBox(false), CLASSNAME);
-        select = (TooltipListBox) optionsContainer;
-        select.setSelect(this);
-        select.setVisibleItemCount(1);
-        select.addChangeListener(this);
-        select.setStyleName(CLASSNAME + "-select");
-
-    }
-
-    @Override
-    protected void buildOptions(UIDL uidl) {
-        select.setClient(client);
-        select.setEnabled(!isDisabled() && !isReadonly());
-        select.clear();
-        if (isNullSelectionAllowed() && !isNullSelectionItemAvailable()) {
-            // can't unselect last item in singleselect mode
-            select.addItem("", null);
-        }
-        boolean selected = false;
-        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
-            final UIDL optionUidl = (UIDL) i.next();
-            select.addItem(optionUidl.getStringAttribute("caption"), optionUidl
-                    .getStringAttribute("key"));
-            if (optionUidl.hasAttribute("selected")) {
-                select.setItemSelected(select.getItemCount() - 1, true);
-                selected = true;
-            }
-        }
-        if (!selected && !isNullSelectionAllowed()) {
-            // null-select not allowed, but value not selected yet; add null and
-            // remove when something is selected
-            select.insertItem("", null, 0);
-            select.setItemSelected(0, true);
-        }
-        if (BrowserInfo.get().isIE6()) {
-            // lazy size change - IE6 uses naive dropdown that does not have a
-            // proper size yet
-            Util.notifyParentOfSizeChange(this, true);
-        }
-    }
-
-    @Override
-    protected Object[] getSelectedItems() {
-        final Vector selectedItemKeys = new Vector();
-        for (int i = 0; i < select.getItemCount(); i++) {
-            if (select.isItemSelected(i)) {
-                selectedItemKeys.add(select.getValue(i));
-            }
-        }
-        return selectedItemKeys.toArray();
-    }
-
-    @Override
-    public void onChange(Widget sender) {
-
-        if (select.isMultipleSelect()) {
-            client.updateVariable(id, "selected", getSelectedItems(),
-                    isImmediate());
-        } else {
-            client.updateVariable(id, "selected", new String[] { ""
-                    + getSelectedItem() }, isImmediate());
-        }
-        if (!isNullSelectionAllowed() && "null".equals(select.getValue(0))) {
-            // remove temporary empty item
-            select.removeItem(0);
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        select.setHeight(height);
-        super.setHeight(height);
-    }
-
-    @Override
-    public void setWidth(String width) {
-        select.setWidth(width);
-        super.setWidth(width);
-    }
-
-    @Override
-    protected void setTabIndex(int tabIndex) {
-        ((TooltipListBox) optionsContainer).setTabIndex(tabIndex);
-    }
-
-    public void focus() {
-        select.setFocus(true);
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/INotification.java b/src/com/vaadin/terminal/gwt/client/ui/INotification.java
deleted file mode 100644 (file)
index 5ebb6c7..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Date;\r
-import java.util.EventObject;\r
-import java.util.Iterator;\r
-\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.ui.HTML;\r
-import com.google.gwt.user.client.ui.Widget;\r
-import com.vaadin.terminal.gwt.client.BrowserInfo;\r
-\r
-public class INotification extends IToolkitOverlay {\r
-\r
-    public static final int CENTERED = 1;\r
-    public static final int CENTERED_TOP = 2;\r
-    public static final int CENTERED_BOTTOM = 3;\r
-    public static final int TOP_LEFT = 4;\r
-    public static final int TOP_RIGHT = 5;\r
-    public static final int BOTTOM_LEFT = 6;\r
-    public static final int BOTTOM_RIGHT = 7;\r
-\r
-    public static final int DELAY_FOREVER = -1;\r
-    public static final int DELAY_NONE = 0;\r
-\r
-    private static final String STYLENAME = "i-Notification";\r
-    private static final int mouseMoveThreshold = 7;\r
-    private static final int Z_INDEX_BASE = 20000;\r
-    public static final String STYLE_SYSTEM = "system";\r
-    private static final int FADE_ANIMATION_INTERVAL = 50; // == 20 fps\r
-\r
-    private int startOpacity = 90;\r
-    private int fadeMsec = 400;\r
-    private int delayMsec = 1000;\r
-\r
-    private Timer fader;\r
-    private Timer delay;\r
-\r
-    private int x = -1;\r
-    private int y = -1;\r
-\r
-    private String temporaryStyle;\r
-\r
-    private ArrayList<EventListener> listeners;\r
-\r
-    public INotification() {\r
-        setStylePrimaryName(STYLENAME);\r
-        sinkEvents(Event.ONCLICK);\r
-        DOM.setStyleAttribute(getElement(), "zIndex", "" + Z_INDEX_BASE);\r
-    }\r
-\r
-    public INotification(int delayMsec) {\r
-        this();\r
-        this.delayMsec = delayMsec;\r
-    }\r
-\r
-    public INotification(int delayMsec, int fadeMsec, int startOpacity) {\r
-        this(delayMsec);\r
-        this.fadeMsec = fadeMsec;\r
-        this.startOpacity = startOpacity;\r
-    }\r
-\r
-    public void startDelay() {\r
-        DOM.removeEventPreview(this);\r
-        if (delayMsec > 0) {\r
-            if (delay == null) {\r
-                delay = new Timer() {\r
-                    @Override\r
-                    public void run() {\r
-                        fade();\r
-                    }\r
-                };\r
-                delay.schedule(delayMsec);\r
-            }\r
-        } else if (delayMsec == 0) {\r
-            fade();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void show() {\r
-        show(CENTERED);\r
-    }\r
-\r
-    public void show(String style) {\r
-        show(CENTERED, style);\r
-    }\r
-\r
-    public void show(int position) {\r
-        show(position, null);\r
-    }\r
-\r
-    public void show(Widget widget, int position, String style) {\r
-        setWidget(widget);\r
-        show(position, style);\r
-    }\r
-\r
-    public void show(String html, int position, String style) {\r
-        setWidget(new HTML(html));\r
-        show(position, style);\r
-    }\r
-\r
-    public void show(int position, String style) {\r
-        setOpacity(getElement(), startOpacity);\r
-        if (style != null) {\r
-            temporaryStyle = style;\r
-            addStyleName(style);\r
-        }\r
-        super.show();\r
-        setPosition(position);\r
-    }\r
-\r
-    @Override\r
-    public void hide() {\r
-        DOM.removeEventPreview(this);\r
-        cancelDelay();\r
-        cancelFade();\r
-        if (temporaryStyle != null) {\r
-            removeStyleName(temporaryStyle);\r
-            temporaryStyle = null;\r
-        }\r
-        super.hide();\r
-        fireEvent(new HideEvent(this));\r
-    }\r
-\r
-    public void fade() {\r
-        DOM.removeEventPreview(this);\r
-        cancelDelay();\r
-        fader = new Timer() {\r
-            private final long start = new Date().getTime();\r
-\r
-            @Override\r
-            public void run() {\r
-                /*\r
-                 * To make animation smooth, don't count that event happens on\r
-                 * time. Reduce opacity according to the actual time spent\r
-                 * instead of fixed decrement.\r
-                 */\r
-                long now = new Date().getTime();\r
-                long timeEplaced = now - start;\r
-                float remainingFraction = 1 - timeEplaced / (float) fadeMsec;\r
-                int opacity = (int) (startOpacity * remainingFraction);\r
-                if (opacity <= 0) {\r
-                    cancel();\r
-                    hide();\r
-                    if (BrowserInfo.get().isOpera()) {\r
-                        // tray notification on opera needs to explicitly define\r
-                        // size, reset it\r
-                        DOM.setStyleAttribute(getElement(), "width", "");\r
-                        DOM.setStyleAttribute(getElement(), "height", "");\r
-                    }\r
-                } else {\r
-                    setOpacity(getElement(), opacity);\r
-                }\r
-            }\r
-        };\r
-        fader.scheduleRepeating(FADE_ANIMATION_INTERVAL);\r
-    }\r
-\r
-    public void setPosition(int position) {\r
-        final Element el = getElement();\r
-        DOM.setStyleAttribute(el, "top", "");\r
-        DOM.setStyleAttribute(el, "left", "");\r
-        DOM.setStyleAttribute(el, "bottom", "");\r
-        DOM.setStyleAttribute(el, "right", "");\r
-        switch (position) {\r
-        case TOP_LEFT:\r
-            DOM.setStyleAttribute(el, "top", "0px");\r
-            DOM.setStyleAttribute(el, "left", "0px");\r
-            break;\r
-        case TOP_RIGHT:\r
-            DOM.setStyleAttribute(el, "top", "0px");\r
-            DOM.setStyleAttribute(el, "right", "0px");\r
-            break;\r
-        case BOTTOM_RIGHT:\r
-            DOM.setStyleAttribute(el, "position", "absolute");\r
-            if (BrowserInfo.get().isOpera()) {\r
-                // tray notification on opera needs explicitly defined size\r
-                DOM.setStyleAttribute(el, "width", getOffsetWidth() + "px");\r
-                DOM.setStyleAttribute(el, "height", getOffsetHeight() + "px");\r
-            }\r
-            DOM.setStyleAttribute(el, "bottom", "0px");\r
-            DOM.setStyleAttribute(el, "right", "0px");\r
-            break;\r
-        case BOTTOM_LEFT:\r
-            DOM.setStyleAttribute(el, "bottom", "0px");\r
-            DOM.setStyleAttribute(el, "left", "0px");\r
-            break;\r
-        case CENTERED_TOP:\r
-            center();\r
-            DOM.setStyleAttribute(el, "top", "0px");\r
-            break;\r
-        case CENTERED_BOTTOM:\r
-            center();\r
-            DOM.setStyleAttribute(el, "top", "");\r
-            DOM.setStyleAttribute(el, "bottom", "0px");\r
-            break;\r
-        default:\r
-        case CENTERED:\r
-            center();\r
-            break;\r
-        }\r
-    }\r
-\r
-    private void cancelFade() {\r
-        if (fader != null) {\r
-            fader.cancel();\r
-            fader = null;\r
-        }\r
-    }\r
-\r
-    private void cancelDelay() {\r
-        if (delay != null) {\r
-            delay.cancel();\r
-            delay = null;\r
-        }\r
-    }\r
-\r
-    private void setOpacity(Element el, int opacity) {\r
-        DOM.setStyleAttribute(el, "opacity", "" + (opacity / 100.0));\r
-        if (BrowserInfo.get().isIE()) {\r
-            DOM.setStyleAttribute(el, "filter", "Alpha(opacity=" + opacity\r
-                    + ")");\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void onBrowserEvent(Event event) {\r
-        DOM.removeEventPreview(this);\r
-        if (fader == null) {\r
-            fade();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public boolean onEventPreview(Event event) {\r
-        int type = DOM.eventGetType(event);\r
-        // "modal"\r
-        if (delayMsec == -1 || temporaryStyle == STYLE_SYSTEM) {\r
-            if (type == Event.ONCLICK) {\r
-                if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) {\r
-                    fade();\r
-                    return false;\r
-                }\r
-            }\r
-            if (temporaryStyle == STYLE_SYSTEM) {\r
-                return true;\r
-            } else {\r
-                return false;\r
-            }\r
-        }\r
-        // default\r
-        switch (type) {\r
-        case Event.ONMOUSEMOVE:\r
-\r
-            if (x < 0) {\r
-                x = DOM.eventGetClientX(event);\r
-                y = DOM.eventGetClientY(event);\r
-            } else if (Math.abs(DOM.eventGetClientX(event) - x) > mouseMoveThreshold\r
-                    || Math.abs(DOM.eventGetClientY(event) - y) > mouseMoveThreshold) {\r
-                startDelay();\r
-            }\r
-            break;\r
-        case Event.ONMOUSEDOWN:\r
-        case Event.ONMOUSEWHEEL:\r
-        case Event.ONSCROLL:\r
-            startDelay();\r
-            break;\r
-        case Event.ONKEYDOWN:\r
-            if (event.getRepeat()) {\r
-                return true;\r
-            }\r
-            startDelay();\r
-            break;\r
-        default:\r
-            break;\r
-        }\r
-        return true;\r
-    }\r
-\r
-    public void addEventListener(EventListener listener) {\r
-        if (listeners == null) {\r
-            listeners = new ArrayList<EventListener>();\r
-        }\r
-        listeners.add(listener);\r
-    }\r
-\r
-    public void removeEventListener(EventListener listener) {\r
-        if (listeners == null) {\r
-            return;\r
-        }\r
-        listeners.remove(listener);\r
-    }\r
-\r
-    private void fireEvent(HideEvent event) {\r
-        if (listeners != null) {\r
-            for (Iterator<EventListener> it = listeners.iterator(); it\r
-                    .hasNext();) {\r
-                EventListener l = it.next();\r
-                l.notificationHidden(event);\r
-            }\r
-        }\r
-    }\r
-\r
-    public class HideEvent extends EventObject {\r
-        private static final long serialVersionUID = 4428671753988459560L;\r
-\r
-        public HideEvent(Object source) {\r
-            super(source);\r
-        }\r
-    }\r
-\r
-    public interface EventListener extends java.util.EventListener {\r
-        public void notificationHidden(HideEvent event);\r
-    }\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IOptionGroup.java b/src/com/vaadin/terminal/gwt/client/ui/IOptionGroup.java
deleted file mode 100644 (file)
index cec3d07..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.Map;\r
-\r
-import com.google.gwt.user.client.ui.CheckBox;\r
-import com.google.gwt.user.client.ui.HasFocus;\r
-import com.google.gwt.user.client.ui.Panel;\r
-import com.google.gwt.user.client.ui.RadioButton;\r
-import com.google.gwt.user.client.ui.Widget;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class IOptionGroup extends IOptionGroupBase {\r
-\r
-    public static final String CLASSNAME = "i-select-optiongroup";\r
-\r
-    private final Panel panel;\r
-\r
-    private final Map optionsToKeys;\r
-\r
-    public IOptionGroup() {\r
-        super(CLASSNAME);\r
-        panel = (Panel) optionsContainer;\r
-        optionsToKeys = new HashMap();\r
-    }\r
-\r
-    /*\r
-     * Return true if no elements were changed, false otherwise.\r
-     */\r
-    @Override\r
-    protected void buildOptions(UIDL uidl) {\r
-        panel.clear();\r
-        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {\r
-            final UIDL opUidl = (UIDL) it.next();\r
-            CheckBox op;\r
-            if (isMultiselect()) {\r
-                op = new ICheckBox();\r
-                op.setText(opUidl.getStringAttribute("caption"));\r
-            } else {\r
-                op = new RadioButton(id, opUidl.getStringAttribute("caption"));\r
-                op.setStyleName("i-radiobutton");\r
-            }\r
-            op.addStyleName(CLASSNAME_OPTION);\r
-            op.setChecked(opUidl.getBooleanAttribute("selected"));\r
-            op.setEnabled(!opUidl.getBooleanAttribute("disabled")\r
-                    && !isReadonly() && !isDisabled());\r
-            op.addClickListener(this);\r
-            optionsToKeys.put(op, opUidl.getStringAttribute("key"));\r
-            panel.add(op);\r
-        }\r
-    }\r
-\r
-    @Override\r
-    protected Object[] getSelectedItems() {\r
-        return selectedKeys.toArray();\r
-    }\r
-\r
-    @Override\r
-    public void onClick(Widget sender) {\r
-        super.onClick(sender);\r
-        if (sender instanceof CheckBox) {\r
-            final boolean selected = ((CheckBox) sender).isChecked();\r
-            final String key = (String) optionsToKeys.get(sender);\r
-            if (!isMultiselect()) {\r
-                selectedKeys.clear();\r
-            }\r
-            if (selected) {\r
-                selectedKeys.add(key);\r
-            } else {\r
-                selectedKeys.remove(key);\r
-            }\r
-            client.updateVariable(id, "selected", getSelectedItems(),\r
-                    isImmediate());\r
-        }\r
-    }\r
-\r
-    @Override\r
-    protected void setTabIndex(int tabIndex) {\r
-        for (Iterator iterator = panel.iterator(); iterator.hasNext();) {\r
-            if (isMultiselect()) {\r
-                ICheckBox cb = (ICheckBox) iterator.next();\r
-                cb.setTabIndex(tabIndex);\r
-            } else {\r
-                RadioButton rb = (RadioButton) iterator.next();\r
-                rb.setTabIndex(tabIndex);\r
-            }\r
-        }\r
-    }\r
-\r
-    public void focus() {\r
-        Iterator<Widget> iterator = panel.iterator();\r
-        if (iterator.hasNext()) {\r
-            ((HasFocus) iterator.next()).setFocus(true);\r
-        }\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/IOptionGroupBase.java
deleted file mode 100644 (file)
index d91ade2..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Set;\r
-\r
-import com.google.gwt.user.client.ui.ChangeListener;\r
-import com.google.gwt.user.client.ui.ClickListener;\r
-import com.google.gwt.user.client.ui.Composite;\r
-import com.google.gwt.user.client.ui.FlowPanel;\r
-import com.google.gwt.user.client.ui.KeyboardListener;\r
-import com.google.gwt.user.client.ui.Panel;\r
-import com.google.gwt.user.client.ui.Widget;\r
-import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
-import com.vaadin.terminal.gwt.client.Focusable;\r
-import com.vaadin.terminal.gwt.client.Paintable;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-abstract class IOptionGroupBase extends Composite implements Paintable, Field,\r
-        ClickListener, ChangeListener, KeyboardListener, Focusable {\r
-\r
-    public static final String CLASSNAME_OPTION = "i-select-option";\r
-\r
-    protected ApplicationConnection client;\r
-\r
-    protected String id;\r
-\r
-    protected Set selectedKeys;\r
-\r
-    private boolean immediate;\r
-\r
-    private boolean multiselect;\r
-\r
-    private boolean disabled;\r
-\r
-    private boolean readonly;\r
-\r
-    private int cols = 0;\r
-\r
-    private int rows = 0;\r
-\r
-    private boolean nullSelectionAllowed = true;\r
-\r
-    private boolean nullSelectionItemAvailable = false;\r
-\r
-    /**\r
-     * Widget holding the different options (e.g. ListBox or Panel for radio\r
-     * buttons) (optional, fallbacks to container Panel)\r
-     */\r
-    protected Widget optionsContainer;\r
-\r
-    /**\r
-     * Panel containing the component\r
-     */\r
-    private final Panel container;\r
-\r
-    private ITextField newItemField;\r
-\r
-    private IButton newItemButton;\r
-\r
-    public IOptionGroupBase(String classname) {\r
-        container = new FlowPanel();\r
-        initWidget(container);\r
-        optionsContainer = container;\r
-        container.setStyleName(classname);\r
-        immediate = false;\r
-        multiselect = false;\r
-    }\r
-\r
-    /*\r
-     * Call this if you wish to specify your own container for the option\r
-     * elements (e.g. SELECT)\r
-     */\r
-    public IOptionGroupBase(Widget w, String classname) {\r
-        this(classname);\r
-        optionsContainer = w;\r
-        container.add(optionsContainer);\r
-    }\r
-\r
-    protected boolean isImmediate() {\r
-        return immediate;\r
-    }\r
-\r
-    protected boolean isMultiselect() {\r
-        return multiselect;\r
-    }\r
-\r
-    protected boolean isDisabled() {\r
-        return disabled;\r
-    }\r
-\r
-    protected boolean isReadonly() {\r
-        return readonly;\r
-    }\r
-\r
-    protected boolean isNullSelectionAllowed() {\r
-        return nullSelectionAllowed;\r
-    }\r
-\r
-    protected boolean isNullSelectionItemAvailable() {\r
-        return nullSelectionItemAvailable;\r
-    }\r
-\r
-    /**\r
-     * @return "cols" specified in uidl, 0 if not specified\r
-     */\r
-    protected int getColumns() {\r
-        return cols;\r
-    }\r
-\r
-    /**\r
-     * @return "rows" specified in uidl, 0 if not specified\r
-     */\r
-\r
-    protected int getRows() {\r
-        return rows;\r
-    }\r
-\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        this.client = client;\r
-        id = uidl.getId();\r
-\r
-        if (client.updateComponent(this, uidl, true)) {\r
-            return;\r
-        }\r
-\r
-        selectedKeys = uidl.getStringArrayVariableAsSet("selected");\r
-\r
-        readonly = uidl.getBooleanAttribute("readonly");\r
-        disabled = uidl.getBooleanAttribute("disabled");\r
-        multiselect = "multi".equals(uidl.getStringAttribute("selectmode"));\r
-        immediate = uidl.getBooleanAttribute("immediate");\r
-        nullSelectionAllowed = uidl.getBooleanAttribute("nullselect");\r
-        nullSelectionItemAvailable = uidl.getBooleanAttribute("nullselectitem");\r
-\r
-        cols = uidl.getIntAttribute("cols");\r
-        rows = uidl.getIntAttribute("rows");\r
-\r
-        final UIDL ops = uidl.getChildUIDL(0);\r
-\r
-        if (getColumns() > 0) {\r
-            container.setWidth(getColumns() + "em");\r
-            if (container != optionsContainer) {\r
-                optionsContainer.setWidth("100%");\r
-            }\r
-        }\r
-\r
-        buildOptions(ops);\r
-\r
-        if (uidl.getBooleanAttribute("allownewitem")) {\r
-            if (newItemField == null) {\r
-                newItemButton = new IButton();\r
-                newItemButton.setText("+");\r
-                newItemButton.setWidth("1.5em");\r
-                newItemButton.addClickListener(this);\r
-                newItemField = new ITextField();\r
-                newItemField.addKeyboardListener(this);\r
-                // newItemField.setColumns(16);\r
-                if (getColumns() > 0) {\r
-                    newItemField.setWidth((getColumns() - 2) + "em");\r
-                }\r
-            }\r
-            newItemField.setEnabled(!disabled && !readonly);\r
-            newItemButton.setEnabled(!disabled && !readonly);\r
-\r
-            if (newItemField == null || newItemField.getParent() != container) {\r
-                container.add(newItemField);\r
-                container.add(newItemButton);\r
-            }\r
-        } else if (newItemField != null) {\r
-            container.remove(newItemField);\r
-            container.remove(newItemButton);\r
-        }\r
-\r
-        setTabIndex(uidl.hasAttribute("tabindex") ? uidl\r
-                .getIntAttribute("tabindex") : 0);\r
-\r
-    }\r
-\r
-    abstract protected void setTabIndex(int tabIndex);\r
-\r
-    public void onClick(Widget sender) {\r
-        if (sender == newItemButton && !newItemField.getText().equals("")) {\r
-            client.updateVariable(id, "newitem", newItemField.getText(), true);\r
-            newItemField.setText("");\r
-        }\r
-    }\r
-\r
-    public void onChange(Widget sender) {\r
-        if (multiselect) {\r
-            client\r
-                    .updateVariable(id, "selected", getSelectedItems(),\r
-                            immediate);\r
-        } else {\r
-            client.updateVariable(id, "selected", new String[] { ""\r
-                    + getSelectedItem() }, immediate);\r
-        }\r
-    }\r
-\r
-    public void onKeyPress(Widget sender, char keyCode, int modifiers) {\r
-        if (sender == newItemField && keyCode == KeyboardListener.KEY_ENTER) {\r
-            newItemButton.click();\r
-        }\r
-    }\r
-\r
-    public void onKeyUp(Widget sender, char keyCode, int modifiers) {\r
-        // Ignore, subclasses may override\r
-    }\r
-\r
-    public void onKeyDown(Widget sender, char keyCode, int modifiers) {\r
-        // Ignore, subclasses may override\r
-    }\r
-\r
-    protected abstract void buildOptions(UIDL uidl);\r
-\r
-    protected abstract Object[] getSelectedItems();\r
-\r
-    protected Object getSelectedItem() {\r
-        final Object[] sel = getSelectedItems();\r
-        if (sel.length > 0) {\r
-            return sel[0];\r
-        } else {\r
-            return null;\r
-        }\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/IOrderedLayout.java
deleted file mode 100644 (file)
index 305b930..0000000
+++ /dev/null
@@ -1,876 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-import java.util.Set;\r
-\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.Paintable;\r
-import com.vaadin.terminal.gwt.client.RenderSpace;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-import com.vaadin.terminal.gwt.client.Util;\r
-import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;\r
-import com.vaadin.terminal.gwt.client.RenderInformation.Size;\r
-import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;\r
-import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;\r
-\r
-public class IOrderedLayout extends CellBasedLayout {\r
-\r
-    public static final String CLASSNAME = "i-orderedlayout";\r
-\r
-    private int orientation;\r
-\r
-    // Can be removed once OrderedLayout is removed\r
-    private boolean allowOrientationUpdate = false;\r
-\r
-    /**\r
-     * Size of the layout excluding any margins.\r
-     */\r
-    private Size activeLayoutSize = new Size(0, 0);\r
-\r
-    private boolean isRendering = false;\r
-\r
-    private String width = "";\r
-\r
-    private boolean sizeHasChangedDuringRendering = false;\r
-\r
-    public IOrderedLayout() {\r
-        this(CLASSNAME, ORIENTATION_VERTICAL);\r
-        allowOrientationUpdate = true;\r
-    }\r
-\r
-    protected IOrderedLayout(String className, int orientation) {\r
-        setStyleName(className);\r
-        this.orientation = orientation;\r
-\r
-        STYLENAME_SPACING = className + "-spacing";\r
-        STYLENAME_MARGIN_TOP = className + "-margin-top";\r
-        STYLENAME_MARGIN_RIGHT = className + "-margin-right";\r
-        STYLENAME_MARGIN_BOTTOM = className + "-margin-bottom";\r
-        STYLENAME_MARGIN_LEFT = className + "-margin-left";\r
-\r
-    }\r
-\r
-    @Override\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        isRendering = true;\r
-        super.updateFromUIDL(uidl, client);\r
-\r
-        // Only non-cached, visible UIDL:s can introduce changes\r
-        if (uidl.getBooleanAttribute("cached")\r
-                || uidl.getBooleanAttribute("invisible")) {\r
-            isRendering = false;\r
-            return;\r
-        }\r
-\r
-        if (allowOrientationUpdate) {\r
-            handleOrientationUpdate(uidl);\r
-        }\r
-\r
-        // IStopWatch w = new IStopWatch("OrderedLayout.updateFromUIDL");\r
-\r
-        ArrayList<Widget> uidlWidgets = new ArrayList<Widget>(uidl\r
-                .getChildCount());\r
-        ArrayList<ChildComponentContainer> relativeSizeComponents = new ArrayList<ChildComponentContainer>();\r
-        ArrayList<UIDL> relativeSizeComponentUIDL = new ArrayList<UIDL>();\r
-\r
-        int pos = 0;\r
-        for (final Iterator<UIDL> it = uidl.getChildIterator(); it.hasNext();) {\r
-            final UIDL childUIDL = it.next();\r
-            final Paintable child = client.getPaintable(childUIDL);\r
-            Widget widget = (Widget) child;\r
-\r
-            // Create container for component\r
-            ChildComponentContainer childComponentContainer = getComponentContainer(widget);\r
-\r
-            if (childComponentContainer == null) {\r
-                // This is a new component\r
-                childComponentContainer = createChildContainer(widget);\r
-            }\r
-\r
-            addOrMoveChild(childComponentContainer, pos++);\r
-\r
-            /*\r
-             * Components which are to be expanded in the same orientation as\r
-             * the layout are rendered later when it is clear how much space\r
-             * they can use\r
-             */\r
-            if (!Util.isCached(childUIDL)) {\r
-                FloatSize relativeSize = Util.parseRelativeSize(childUIDL);\r
-                childComponentContainer.setRelativeSize(relativeSize);\r
-            }\r
-\r
-            if (childComponentContainer.isComponentRelativeSized(orientation)) {\r
-                relativeSizeComponents.add(childComponentContainer);\r
-                relativeSizeComponentUIDL.add(childUIDL);\r
-            } else {\r
-                if (isDynamicWidth()) {\r
-                    childComponentContainer.renderChild(childUIDL, client, 0);\r
-                } else {\r
-                    childComponentContainer.renderChild(childUIDL, client,\r
-                            activeLayoutSize.getWidth());\r
-                }\r
-                if (sizeHasChangedDuringRendering && Util.isCached(childUIDL)) {\r
-                    // notify cached relative sized component about size\r
-                    // chance\r
-                    client.handleComponentRelativeSize(childComponentContainer\r
-                            .getWidget());\r
-                }\r
-            }\r
-\r
-            uidlWidgets.add(widget);\r
-\r
-        }\r
-\r
-        // w.mark("Rendering of "\r
-        // + (uidlWidgets.size() - relativeSizeComponents.size())\r
-        // + " absolute size components done");\r
-\r
-        /*\r
-         * Remove any children after pos. These are the ones that previously\r
-         * were in the layout but have now been removed\r
-         */\r
-        removeChildrenAfter(pos);\r
-\r
-        // w.mark("Old children removed");\r
-\r
-        /* Fetch alignments and expand ratio from UIDL */\r
-        updateAlignmentsAndExpandRatios(uidl, uidlWidgets);\r
-        // w.mark("Alignments and expand ratios updated");\r
-\r
-        /* Fetch widget sizes from rendered components */\r
-        updateWidgetSizes();\r
-        // w.mark("Widget sizes updated");\r
-\r
-        recalculateLayout();\r
-        // w.mark("Layout size calculated (" + activeLayoutSize +\r
-        // ") offsetSize: "\r
-        // + getOffsetWidth() + "," + getOffsetHeight());\r
-\r
-        /* Render relative size components */\r
-        for (int i = 0; i < relativeSizeComponents.size(); i++) {\r
-            ChildComponentContainer childComponentContainer = relativeSizeComponents\r
-                    .get(i);\r
-            UIDL childUIDL = relativeSizeComponentUIDL.get(i);\r
-\r
-            if (isDynamicWidth()) {\r
-                childComponentContainer.renderChild(childUIDL, client, 0);\r
-            } else {\r
-                childComponentContainer.renderChild(childUIDL, client,\r
-                        activeLayoutSize.getWidth());\r
-            }\r
-\r
-            if (Util.isCached(childUIDL)) {\r
-                /*\r
-                 * We must update the size of the relative sized component if\r
-                 * the expand ratio or something else in the layout changes\r
-                 * which affects the size of a relative sized component\r
-                 */\r
-                client.handleComponentRelativeSize(childComponentContainer\r
-                        .getWidget());\r
-            }\r
-\r
-            // childComponentContainer.updateWidgetSize();\r
-        }\r
-\r
-        // w.mark("Rendering of " + (relativeSizeComponents.size())\r
-        // + " relative size components done");\r
-\r
-        /* Fetch widget sizes for relative size components */\r
-        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
-                .values()) {\r
-\r
-            /* Update widget size from DOM */\r
-            childComponentContainer.updateWidgetSize();\r
-        }\r
-\r
-        // w.mark("Widget sizes updated");\r
-\r
-        /*\r
-         * Components with relative size in main direction may affect the layout\r
-         * size in the other direction\r
-         */\r
-        if ((isHorizontal() && isDynamicHeight())\r
-                || (isVertical() && isDynamicWidth())) {\r
-            layoutSizeMightHaveChanged();\r
-        }\r
-        // w.mark("Layout dimensions updated");\r
-\r
-        /* Update component spacing */\r
-        updateContainerMargins();\r
-\r
-        /*\r
-         * Update component sizes for components with relative size in non-main\r
-         * direction\r
-         */\r
-        if (updateRelativeSizesInNonMainDirection()) {\r
-            // Sizes updated - might affect the other dimension so we need to\r
-            // recheck the widget sizes and recalculate layout dimensions\r
-            updateWidgetSizes();\r
-            layoutSizeMightHaveChanged();\r
-        }\r
-        calculateAlignments();\r
-        // w.mark("recalculateComponentSizesAndAlignments done");\r
-\r
-        setRootSize();\r
-\r
-        if (BrowserInfo.get().isIE()) {\r
-            /*\r
-             * This should fix the issue with padding not always taken into\r
-             * account for the containers leading to no spacing between\r
-             * elements.\r
-             */\r
-            root.getStyle().setProperty("zoom", "1");\r
-        }\r
-\r
-        // w.mark("runDescendentsLayout done");\r
-        isRendering = false;\r
-        sizeHasChangedDuringRendering = false;\r
-    }\r
-\r
-    private void layoutSizeMightHaveChanged() {\r
-        Size oldSize = new Size(activeLayoutSize.getWidth(), activeLayoutSize\r
-                .getHeight());\r
-        calculateLayoutDimensions();\r
-\r
-        /*\r
-         * If layout dimension changes we must also update container sizes\r
-         */\r
-        if (!oldSize.equals(activeLayoutSize)) {\r
-            calculateContainerSize();\r
-        }\r
-    }\r
-\r
-    private void updateWidgetSizes() {\r
-        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
-                .values()) {\r
-\r
-            /*\r
-             * Update widget size from DOM\r
-             */\r
-            childComponentContainer.updateWidgetSize();\r
-        }\r
-    }\r
-\r
-    private void recalculateLayout() {\r
-\r
-        /* Calculate space for relative size components */\r
-        int spaceForExpansion = calculateLayoutDimensions();\r
-\r
-        if (!widgetToComponentContainer.isEmpty()) {\r
-            /* Divide expansion space between component containers */\r
-            expandComponentContainers(spaceForExpansion);\r
-\r
-            /* Update container sizes */\r
-            calculateContainerSize();\r
-        }\r
-\r
-    }\r
-\r
-    private void expandComponentContainers(int spaceForExpansion) {\r
-        int remaining = spaceForExpansion;\r
-        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
-                .values()) {\r
-            remaining -= childComponentContainer.expand(orientation,\r
-                    spaceForExpansion);\r
-        }\r
-\r
-        if (remaining > 0) {\r
-            // Some left-over pixels due to rounding errors\r
-\r
-            // Add one pixel to each container until there are no pixels left\r
-\r
-            Iterator<Widget> widgetIterator = iterator();\r
-            while (widgetIterator.hasNext() && remaining-- > 0) {\r
-                ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator\r
-                        .next();\r
-                childComponentContainer.expandExtra(orientation, 1);\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    private void handleOrientationUpdate(UIDL uidl) {\r
-        int newOrientation = ORIENTATION_VERTICAL;\r
-        if ("horizontal".equals(uidl.getStringAttribute("orientation"))) {\r
-            newOrientation = ORIENTATION_HORIZONTAL;\r
-        }\r
-\r
-        if (orientation != newOrientation) {\r
-            orientation = newOrientation;\r
-\r
-            for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
-                    .values()) {\r
-                childComponentContainer.setOrientation(orientation);\r
-            }\r
-        }\r
-\r
-    }\r
-\r
-    /**\r
-     * Updated components with relative height in horizontal layouts and\r
-     * components with relative width in vertical layouts. This is only needed\r
-     * if the height (horizontal layout) or width (vertical layout) has not been\r
-     * specified.\r
-     */\r
-    private boolean updateRelativeSizesInNonMainDirection() {\r
-        int updateDirection = 1 - orientation;\r
-        if ((updateDirection == ORIENTATION_HORIZONTAL && !isDynamicWidth())\r
-                || (updateDirection == ORIENTATION_VERTICAL && !isDynamicHeight())) {\r
-            return false;\r
-        }\r
-\r
-        boolean updated = false;\r
-        for (ChildComponentContainer componentContainer : widgetToComponentContainer\r
-                .values()) {\r
-            if (componentContainer.isComponentRelativeSized(updateDirection)) {\r
-                client.handleComponentRelativeSize(componentContainer\r
-                        .getWidget());\r
-            }\r
-\r
-            updated = true;\r
-        }\r
-\r
-        return updated;\r
-    }\r
-\r
-    private int calculateLayoutDimensions() {\r
-        int summedWidgetWidth = 0;\r
-        int summedWidgetHeight = 0;\r
-\r
-        int maxWidgetWidth = 0;\r
-        int maxWidgetHeight = 0;\r
-\r
-        // Calculate layout dimensions from component dimensions\r
-        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
-                .values()) {\r
-\r
-            int widgetHeight = 0;\r
-            int widgetWidth = 0;\r
-            if (childComponentContainer.isComponentRelativeSized(orientation)) {\r
-                if (orientation == ORIENTATION_HORIZONTAL) {\r
-                    widgetHeight = getWidgetHeight(childComponentContainer);\r
-                } else {\r
-                    widgetWidth = getWidgetWidth(childComponentContainer);\r
-                }\r
-            } else {\r
-                widgetWidth = getWidgetWidth(childComponentContainer);\r
-                widgetHeight = getWidgetHeight(childComponentContainer);\r
-            }\r
-\r
-            summedWidgetWidth += widgetWidth;\r
-            summedWidgetHeight += widgetHeight;\r
-\r
-            maxWidgetHeight = Math.max(maxWidgetHeight, widgetHeight);\r
-            maxWidgetWidth = Math.max(maxWidgetWidth, widgetWidth);\r
-        }\r
-\r
-        if (isHorizontal()) {\r
-            summedWidgetWidth += activeSpacing.hSpacing\r
-                    * (widgetToComponentContainer.size() - 1);\r
-        } else {\r
-            summedWidgetHeight += activeSpacing.vSpacing\r
-                    * (widgetToComponentContainer.size() - 1);\r
-        }\r
-\r
-        Size layoutSize = updateLayoutDimensions(summedWidgetWidth,\r
-                summedWidgetHeight, maxWidgetWidth, maxWidgetHeight);\r
-\r
-        int remainingSpace;\r
-        if (isHorizontal()) {\r
-            remainingSpace = layoutSize.getWidth() - summedWidgetWidth;\r
-        } else {\r
-            remainingSpace = layoutSize.getHeight() - summedWidgetHeight;\r
-        }\r
-        if (remainingSpace < 0) {\r
-            remainingSpace = 0;\r
-        }\r
-\r
-        // ApplicationConnection.getConsole().log(\r
-        // "Layout size: " + activeLayoutSize);\r
-        return remainingSpace;\r
-    }\r
-\r
-    private int getWidgetHeight(ChildComponentContainer childComponentContainer) {\r
-        Size s = childComponentContainer.getWidgetSize();\r
-        return s.getHeight()\r
-                + childComponentContainer.getCaptionHeightAboveComponent();\r
-    }\r
-\r
-    private int getWidgetWidth(ChildComponentContainer childComponentContainer) {\r
-        Size s = childComponentContainer.getWidgetSize();\r
-        int widgetWidth = s.getWidth()\r
-                + childComponentContainer.getCaptionWidthAfterComponent();\r
-\r
-        /*\r
-         * If the component does not have a specified size in the main direction\r
-         * the caption may determine the space used by the component\r
-         */\r
-        if (!childComponentContainer.widgetHasSizeSpecified(orientation)) {\r
-            int captionWidth = childComponentContainer\r
-                    .getCaptionRequiredWidth();\r
-\r
-            if (captionWidth > widgetWidth) {\r
-                widgetWidth = captionWidth;\r
-            }\r
-        }\r
-\r
-        return widgetWidth;\r
-    }\r
-\r
-    private void calculateAlignments() {\r
-        int w = 0;\r
-        int h = 0;\r
-\r
-        if (isHorizontal()) {\r
-            // HORIZONTAL\r
-            h = activeLayoutSize.getHeight();\r
-            if (!isDynamicWidth()) {\r
-                w = -1;\r
-            }\r
-\r
-        } else {\r
-            // VERTICAL\r
-            w = activeLayoutSize.getWidth();\r
-            if (!isDynamicHeight()) {\r
-                h = -1;\r
-            }\r
-        }\r
-\r
-        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
-                .values()) {\r
-            childComponentContainer.updateAlignments(w, h);\r
-        }\r
-\r
-    }\r
-\r
-    private void calculateContainerSize() {\r
-\r
-        /*\r
-         * Container size here means the size the container gets from the\r
-         * component. The expansion size is not include in this but taken\r
-         * separately into account.\r
-         */\r
-        int height = 0, width = 0;\r
-        Iterator<Widget> widgetIterator = iterator();\r
-        if (isHorizontal()) {\r
-            height = activeLayoutSize.getHeight();\r
-            int availableWidth = activeLayoutSize.getWidth();\r
-            boolean first = true;\r
-            while (widgetIterator.hasNext()) {\r
-                ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator\r
-                        .next();\r
-                if (!childComponentContainer\r
-                        .isComponentRelativeSized(ORIENTATION_HORIZONTAL)) {\r
-                    /*\r
-                     * Only components with non-relative size in the main\r
-                     * direction has a container size\r
-                     */\r
-                    width = childComponentContainer.getWidgetSize().getWidth()\r
-                            + childComponentContainer\r
-                                    .getCaptionWidthAfterComponent();\r
-\r
-                    /*\r
-                     * If the component does not have a specified size in the\r
-                     * main direction the caption may determine the space used\r
-                     * by the component\r
-                     */\r
-                    if (!childComponentContainer\r
-                            .widgetHasSizeSpecified(orientation)) {\r
-                        int captionWidth = childComponentContainer\r
-                                .getCaptionRequiredWidth();\r
-                        // ApplicationConnection.getConsole().log(\r
-                        // "Component width: " + width\r
-                        // + ", caption width: " + captionWidth);\r
-                        if (captionWidth > width) {\r
-                            width = captionWidth;\r
-                        }\r
-                    }\r
-                } else {\r
-                    width = 0;\r
-                }\r
-\r
-                if (!isDynamicWidth()) {\r
-                    if (availableWidth == 0) {\r
-                        /*\r
-                         * Let the overflowing components overflow. IE has\r
-                         * problems with zero sizes.\r
-                         */\r
-                        // width = 0;\r
-                        // height = 0;\r
-                    } else if (width > availableWidth) {\r
-                        width = availableWidth;\r
-\r
-                        if (!first) {\r
-                            width -= activeSpacing.hSpacing;\r
-                        }\r
-                        availableWidth = 0;\r
-                    } else {\r
-                        availableWidth -= width;\r
-                        if (!first) {\r
-                            availableWidth -= activeSpacing.hSpacing;\r
-                        }\r
-                    }\r
-\r
-                    first = false;\r
-                }\r
-\r
-                childComponentContainer.setContainerSize(width, height);\r
-            }\r
-        } else {\r
-            width = activeLayoutSize.getWidth();\r
-            while (widgetIterator.hasNext()) {\r
-                ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator\r
-                        .next();\r
-\r
-                if (!childComponentContainer\r
-                        .isComponentRelativeSized(ORIENTATION_VERTICAL)) {\r
-                    /*\r
-                     * Only components with non-relative size in the main\r
-                     * direction has a container size\r
-                     */\r
-                    height = childComponentContainer.getWidgetSize()\r
-                            .getHeight()\r
-                            + childComponentContainer\r
-                                    .getCaptionHeightAboveComponent();\r
-                } else {\r
-                    height = 0;\r
-                }\r
-\r
-                childComponentContainer.setContainerSize(width, height);\r
-            }\r
-\r
-        }\r
-\r
-    }\r
-\r
-    private Size updateLayoutDimensions(int totalComponentWidth,\r
-            int totalComponentHeight, int maxComponentWidth,\r
-            int maxComponentHeight) {\r
-\r
-        /* Only need to calculate dynamic dimensions */\r
-        if (!isDynamicHeight() && !isDynamicWidth()) {\r
-            return activeLayoutSize;\r
-        }\r
-\r
-        int activeLayoutWidth = 0;\r
-        int activeLayoutHeight = 0;\r
-\r
-        // Update layout dimensions\r
-        if (isHorizontal()) {\r
-            // Horizontal\r
-            if (isDynamicWidth()) {\r
-                activeLayoutWidth = totalComponentWidth;\r
-            }\r
-\r
-            if (isDynamicHeight()) {\r
-                activeLayoutHeight = maxComponentHeight;\r
-            }\r
-\r
-        } else {\r
-            // Vertical\r
-            if (isDynamicWidth()) {\r
-                activeLayoutWidth = maxComponentWidth;\r
-            }\r
-\r
-            if (isDynamicHeight()) {\r
-                activeLayoutHeight = totalComponentHeight;\r
-            }\r
-        }\r
-\r
-        if (isDynamicWidth()) {\r
-            setActiveLayoutWidth(activeLayoutWidth);\r
-            setOuterLayoutWidth(activeLayoutSize.getWidth());\r
-        }\r
-\r
-        if (isDynamicHeight()) {\r
-            setActiveLayoutHeight(activeLayoutHeight);\r
-            setOuterLayoutHeight(activeLayoutSize.getHeight());\r
-        }\r
-\r
-        return activeLayoutSize;\r
-    }\r
-\r
-    private void setActiveLayoutWidth(int activeLayoutWidth) {\r
-        if (activeLayoutWidth < 0) {\r
-            activeLayoutWidth = 0;\r
-        }\r
-        activeLayoutSize.setWidth(activeLayoutWidth);\r
-    }\r
-\r
-    private void setActiveLayoutHeight(int activeLayoutHeight) {\r
-        if (activeLayoutHeight < 0) {\r
-            activeLayoutHeight = 0;\r
-        }\r
-        activeLayoutSize.setHeight(activeLayoutHeight);\r
-\r
-    }\r
-\r
-    private void setOuterLayoutWidth(int activeLayoutWidth) {\r
-        super.setWidth((activeLayoutWidth + activeMargins.getHorizontal())\r
-                + "px");\r
-\r
-    }\r
-\r
-    private void setOuterLayoutHeight(int activeLayoutHeight) {\r
-        super.setHeight((activeLayoutHeight + activeMargins.getVertical())\r
-                + "px");\r
-\r
-    }\r
-\r
-    /**\r
-     * Updates the spacing between components. Needs to be done only when\r
-     * components are added/removed.\r
-     */\r
-    private void updateContainerMargins() {\r
-        ChildComponentContainer firstChildComponent = getFirstChildComponentContainer();\r
-        if (firstChildComponent != null) {\r
-            firstChildComponent.setMarginLeft(0);\r
-            firstChildComponent.setMarginTop(0);\r
-\r
-            for (ChildComponentContainer childComponent : widgetToComponentContainer\r
-                    .values()) {\r
-                if (childComponent == firstChildComponent) {\r
-                    continue;\r
-                }\r
-\r
-                if (isHorizontal()) {\r
-                    childComponent.setMarginLeft(activeSpacing.hSpacing);\r
-                } else {\r
-                    childComponent.setMarginTop(activeSpacing.vSpacing);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    private boolean isHorizontal() {\r
-        return orientation == ORIENTATION_HORIZONTAL;\r
-    }\r
-\r
-    private boolean isVertical() {\r
-        return orientation == ORIENTATION_VERTICAL;\r
-    }\r
-\r
-    private ChildComponentContainer createChildContainer(Widget child) {\r
-\r
-        // Create a container DIV for the child\r
-        ChildComponentContainer childComponent = new ChildComponentContainer(\r
-                child, orientation);\r
-\r
-        return childComponent;\r
-\r
-    }\r
-\r
-    public RenderSpace getAllocatedSpace(Widget child) {\r
-        int width = 0;\r
-        int height = 0;\r
-        ChildComponentContainer childComponentContainer = getComponentContainer(child);\r
-        // WIDTH CALCULATION\r
-        if (isVertical()) {\r
-            width = activeLayoutSize.getWidth();\r
-            width -= childComponentContainer.getCaptionWidthAfterComponent();\r
-        } else if (!isDynamicWidth()) {\r
-            // HORIZONTAL\r
-            width = childComponentContainer.getContSize().getWidth();\r
-            width -= childComponentContainer.getCaptionWidthAfterComponent();\r
-        }\r
-\r
-        // HEIGHT CALCULATION\r
-        if (isHorizontal()) {\r
-            height = activeLayoutSize.getHeight();\r
-            height -= childComponentContainer.getCaptionHeightAboveComponent();\r
-        } else if (!isDynamicHeight()) {\r
-            // VERTICAL\r
-            height = childComponentContainer.getContSize().getHeight();\r
-            height -= childComponentContainer.getCaptionHeightAboveComponent();\r
-        }\r
-\r
-        // ApplicationConnection.getConsole().log(\r
-        // "allocatedSpace for " + Util.getSimpleName(child) + ": "\r
-        // + width + "," + height);\r
-        RenderSpace space = new RenderSpace(width, height);\r
-        return space;\r
-    }\r
-\r
-    private void recalculateLayoutAndComponentSizes() {\r
-        recalculateLayout();\r
-\r
-        if (!(isDynamicHeight() && isDynamicWidth())) {\r
-            /* First update relative sized components */\r
-            for (ChildComponentContainer componentContainer : widgetToComponentContainer\r
-                    .values()) {\r
-                client.handleComponentRelativeSize(componentContainer\r
-                        .getWidget());\r
-\r
-                // Update widget size from DOM\r
-                componentContainer.updateWidgetSize();\r
-            }\r
-        }\r
-\r
-        if (isDynamicHeight()) {\r
-            /*\r
-             * Height is not necessarily correct anymore as the height of\r
-             * components might have changed if the width has changed.\r
-             */\r
-\r
-            /*\r
-             * Get the new widget sizes from DOM and calculate new container\r
-             * sizes\r
-             */\r
-            updateWidgetSizes();\r
-\r
-            /* Update layout dimensions based on widget sizes */\r
-            recalculateLayout();\r
-        }\r
-\r
-        updateRelativeSizesInNonMainDirection();\r
-        calculateAlignments();\r
-\r
-        setRootSize();\r
-    }\r
-\r
-    private void setRootSize() {\r
-        root.getStyle().setPropertyPx("width", activeLayoutSize.getWidth());\r
-        root.getStyle().setPropertyPx("height", activeLayoutSize.getHeight());\r
-    }\r
-\r
-    public boolean requestLayout(Set<Paintable> children) {\r
-        for (Paintable p : children) {\r
-            /* Update widget size from DOM */\r
-            ChildComponentContainer componentContainer = getComponentContainer((Widget) p);\r
-            // This should no longer be needed (after #2563)\r
-            // if (isDynamicWidth()) {\r
-            // componentContainer.setUnlimitedContainerWidth();\r
-            // } else {\r
-            // componentContainer.setLimitedContainerWidth(activeLayoutSize\r
-            // .getWidth());\r
-            // }\r
-\r
-            componentContainer.updateWidgetSize();\r
-\r
-            /*\r
-             * If this is the result of an caption icon onload event the caption\r
-             * size may have changed\r
-             */\r
-            componentContainer.updateCaptionSize();\r
-        }\r
-\r
-        Size sizeBefore = new Size(activeLayoutSize.getWidth(),\r
-                activeLayoutSize.getHeight());\r
-\r
-        recalculateLayoutAndComponentSizes();\r
-        boolean sameSize = (sizeBefore.equals(activeLayoutSize));\r
-        if (!sameSize) {\r
-            /* Must inform child components about possible size updates */\r
-            client.runDescendentsLayout(this);\r
-        }\r
-\r
-        /* Automatically propagated upwards if the size has changed */\r
-\r
-        return sameSize;\r
-    }\r
-\r
-    @Override\r
-    public void setHeight(String height) {\r
-        Size sizeBefore = new Size(activeLayoutSize.getWidth(),\r
-                activeLayoutSize.getHeight());\r
-\r
-        super.setHeight(height);\r
-\r
-        if (height != null && !height.equals("")) {\r
-            setActiveLayoutHeight(getOffsetHeight()\r
-                    - activeMargins.getVertical());\r
-        }\r
-\r
-        if (isRendering) {\r
-            sizeHasChangedDuringRendering = true;\r
-        } else {\r
-            recalculateLayoutAndComponentSizes();\r
-            boolean sameSize = (sizeBefore.equals(activeLayoutSize));\r
-            if (!sameSize) {\r
-                /* Must inform child components about possible size updates */\r
-                client.runDescendentsLayout(this);\r
-            }\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void setWidth(String width) {\r
-        if (this.width.equals(width)) {\r
-            return;\r
-        }\r
-        Size sizeBefore = new Size(activeLayoutSize.getWidth(),\r
-                activeLayoutSize.getHeight());\r
-\r
-        super.setWidth(width);\r
-        this.width = width;\r
-        if (width != null && !width.equals("")) {\r
-            setActiveLayoutWidth(getOffsetWidth()\r
-                    - activeMargins.getHorizontal());\r
-        }\r
-\r
-        if (isRendering) {\r
-            sizeHasChangedDuringRendering = true;\r
-        } else {\r
-            recalculateLayoutAndComponentSizes();\r
-            boolean sameSize = (sizeBefore.equals(activeLayoutSize));\r
-            if (!sameSize) {\r
-                /* Must inform child components about possible size updates */\r
-                client.runDescendentsLayout(this);\r
-            }\r
-            /*\r
-             * If the height changes as a consequence of this we must inform the\r
-             * parent also\r
-             */\r
-            if (isDynamicHeight()\r
-                    && sizeBefore.getHeight() != activeLayoutSize.getHeight()) {\r
-                Util.notifyParentOfSizeChange(this, false);\r
-            }\r
-\r
-        }\r
-    }\r
-\r
-    protected void updateAlignmentsAndExpandRatios(UIDL uidl,\r
-            ArrayList<Widget> renderedWidgets) {\r
-\r
-        /*\r
-         * UIDL contains component alignments as a comma separated list.\r
-         * \r
-         * See com.vaadin.terminal.gwt.client.ui.AlignmentInfo.java for\r
-         * possible values.\r
-         */\r
-        final int[] alignments = uidl.getIntArrayAttribute("alignments");\r
-\r
-        /*\r
-         * UIDL contains normalized expand ratios as a comma separated list.\r
-         */\r
-        final int[] expandRatios = uidl.getIntArrayAttribute("expandRatios");\r
-\r
-        for (int i = 0; i < renderedWidgets.size(); i++) {\r
-            Widget widget = renderedWidgets.get(i);\r
-\r
-            ChildComponentContainer container = getComponentContainer(widget);\r
-\r
-            // Calculate alignment info\r
-            container.setAlignment(new AlignmentInfo(alignments[i]));\r
-\r
-            // Update expand ratio\r
-            container.setExpandRatio(expandRatios[i]);\r
-        }\r
-    }\r
-\r
-    public void updateCaption(Paintable component, UIDL uidl) {\r
-        ChildComponentContainer componentContainer = getComponentContainer((Widget) component);\r
-        componentContainer.updateCaption(uidl, client);\r
-        if (!isRendering) {\r
-            /*\r
-             * This was a component-only update and the possible size change\r
-             * must be propagated to the layout\r
-             */\r
-            client.captionSizeUpdated(component);\r
-        }\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IPanel.java b/src/com/vaadin/terminal/gwt/client/ui/IPanel.java
deleted file mode 100644 (file)
index 7be9a11..0000000
+++ /dev/null
@@ -1,516 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Set;
-
-import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderInformation;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class IPanel extends SimplePanel implements Container {
-
-    public static final String CLASSNAME = "i-panel";
-
-    ApplicationConnection client;
-
-    String id;
-
-    private final Element captionNode = DOM.createDiv();
-
-    private final Element captionText = DOM.createSpan();
-
-    private Icon icon;
-
-    private final Element bottomDecoration = DOM.createDiv();
-
-    private final Element contentNode = DOM.createDiv();
-
-    private Element errorIndicatorElement;
-
-    private String height;
-
-    private Paintable layout;
-
-    ShortcutActionHandler shortcutHandler;
-
-    private String width = "";
-
-    private Element geckoCaptionMeter;
-
-    private int scrollTop;
-
-    private int scrollLeft;
-
-    private RenderInformation renderInformation = new RenderInformation();
-
-    private int borderPaddingHorizontal = -1;
-
-    private int borderPaddingVertical = -1;
-
-    private int captionPaddingHorizontal = -1;
-
-    private int captionMarginLeft = -1;
-
-    private boolean rendering;
-
-    private int contentMarginLeft = -1;
-
-    private String previousStyleName;
-
-    public IPanel() {
-        super();
-        DivElement captionWrap = Document.get().createDivElement();
-        captionWrap.appendChild(captionNode);
-        captionNode.appendChild(captionText);
-
-        captionWrap.setClassName(CLASSNAME + "-captionwrap");
-        captionNode.setClassName(CLASSNAME + "-caption");
-        contentNode.setClassName(CLASSNAME + "-content");
-        bottomDecoration.setClassName(CLASSNAME + "-deco");
-
-        getElement().appendChild(captionWrap);
-        getElement().appendChild(contentNode);
-        getElement().appendChild(bottomDecoration);
-        setStyleName(CLASSNAME);
-        DOM.sinkEvents(getElement(), Event.ONKEYDOWN);
-        DOM.sinkEvents(contentNode, Event.ONSCROLL);
-        contentNode.getStyle().setProperty("position", "relative");
-        getElement().getStyle().setProperty("overflow", "hidden");
-    }
-
-    @Override
-    protected Element getContainerElement() {
-        return contentNode;
-    }
-
-    private void setCaption(String text) {
-        DOM.setInnerHTML(captionText, text);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-        if (!uidl.hasAttribute("cached")) {
-            // Handle caption displaying and style names, prior generics.
-            // Affects size
-            // calculations
-
-            // Restore default stylenames
-            contentNode.setClassName(CLASSNAME + "-content");
-            bottomDecoration.setClassName(CLASSNAME + "-deco");
-            captionNode.setClassName(CLASSNAME + "-caption");
-            boolean hasCaption = false;
-            if (uidl.hasAttribute("caption")
-                    && !uidl.getStringAttribute("caption").equals("")) {
-                setCaption(uidl.getStringAttribute("caption"));
-                hasCaption = true;
-            } else {
-                setCaption("");
-                captionNode.setClassName(CLASSNAME + "-nocaption");
-            }
-
-            // Add proper stylenames for all elements. This way we can prevent
-            // unwanted CSS selector inheritance.
-            if (uidl.hasAttribute("style")) {
-                final String[] styles = uidl.getStringAttribute("style").split(
-                        " ");
-                final String captionBaseClass = CLASSNAME
-                        + (hasCaption ? "-caption" : "-nocaption");
-                final String contentBaseClass = CLASSNAME + "-content";
-                final String decoBaseClass = CLASSNAME + "-deco";
-                String captionClass = captionBaseClass;
-                String contentClass = contentBaseClass;
-                String decoClass = decoBaseClass;
-                for (int i = 0; i < styles.length; i++) {
-                    captionClass += " " + captionBaseClass + "-" + styles[i];
-                    contentClass += " " + contentBaseClass + "-" + styles[i];
-                    decoClass += " " + decoBaseClass + "-" + styles[i];
-                }
-                captionNode.setClassName(captionClass);
-                contentNode.setClassName(contentClass);
-                bottomDecoration.setClassName(decoClass);
-
-            }
-        }
-        // Ensure correct implementation
-        if (client.updateComponent(this, uidl, false)) {
-            rendering = false;
-            return;
-        }
-
-        this.client = client;
-        id = uidl.getId();
-
-        setIconUri(uidl, client);
-
-        handleError(uidl);
-
-        // Render content
-        final UIDL layoutUidl = uidl.getChildUIDL(0);
-        final Paintable newLayout = client.getPaintable(layoutUidl);
-        if (newLayout != layout) {
-            if (layout != null) {
-                client.unregisterPaintable(layout);
-            }
-            setWidget((Widget) newLayout);
-            layout = newLayout;
-        }
-        layout.updateFromUIDL(layoutUidl, client);
-
-        runHacks(false);
-        // We may have actions attached to this panel
-        if (uidl.getChildCount() > 1) {
-            final int cnt = uidl.getChildCount();
-            for (int i = 1; i < cnt; i++) {
-                UIDL childUidl = uidl.getChildUIDL(i);
-                if (childUidl.getTag().equals("actions")) {
-                    if (shortcutHandler == null) {
-                        shortcutHandler = new ShortcutActionHandler(id, client);
-                    }
-                    shortcutHandler.updateActionMap(childUidl);
-                }
-            }
-        }
-
-        if (uidl.hasVariable("scrollTop")
-                && uidl.getIntVariable("scrollTop") != scrollTop) {
-            scrollTop = uidl.getIntVariable("scrollTop");
-            DOM.setElementPropertyInt(contentNode, "scrollTop", scrollTop);
-        }
-
-        if (uidl.hasVariable("scrollLeft")
-                && uidl.getIntVariable("scrollLeft") != scrollLeft) {
-            scrollLeft = uidl.getIntVariable("scrollLeft");
-            DOM.setElementPropertyInt(contentNode, "scrollLeft", scrollLeft);
-        }
-
-        rendering = false;
-
-    }
-
-    @Override
-    public void setStyleName(String style) {
-        if (!style.equals(previousStyleName)) {
-            super.setStyleName(style);
-            detectContainerBorders();
-            previousStyleName = style;
-        }
-    }
-
-    private void handleError(UIDL uidl) {
-        if (uidl.hasAttribute("error")) {
-            if (errorIndicatorElement == null) {
-                errorIndicatorElement = DOM.createDiv();
-                DOM.setElementProperty(errorIndicatorElement, "className",
-                        "i-errorindicator");
-                DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS);
-                sinkEvents(Event.MOUSEEVENTS);
-            }
-            DOM.insertBefore(captionNode, errorIndicatorElement, captionText);
-        } else if (errorIndicatorElement != null) {
-            DOM.removeChild(captionNode, errorIndicatorElement);
-            errorIndicatorElement = null;
-        }
-    }
-
-    private void setIconUri(UIDL uidl, ApplicationConnection client) {
-        final String iconUri = uidl.hasAttribute("icon") ? uidl
-                .getStringAttribute("icon") : null;
-        if (iconUri == null) {
-            if (icon != null) {
-                DOM.removeChild(captionNode, icon.getElement());
-                icon = null;
-            }
-        } else {
-            if (icon == null) {
-                icon = new Icon(client);
-                DOM.insertChild(captionNode, icon.getElement(), 0);
-            }
-            icon.setUri(iconUri);
-        }
-    }
-
-    public void runHacks(boolean runGeckoFix) {
-        if (BrowserInfo.get().isIE6() && width != null && !width.equals("")) {
-            /*
-             * IE6 requires overflow-hidden elements to have a width specified
-             * so we calculate the width of the content and caption nodes when
-             * no width has been specified.
-             */
-            /*
-             * Fixes #1923 IPanel: Horizontal scrollbar does not appear in IE6
-             * with wide content
-             */
-
-            /*
-             * Caption must be shrunk for parent measurements to return correct
-             * result in IE6
-             */
-            DOM.setStyleAttribute(captionNode, "width", "1px");
-
-            int parentPadding = Util.measureHorizontalPaddingAndBorder(
-                    getElement(), 0);
-
-            int parentWidthExcludingPadding = getElement().getOffsetWidth()
-                    - parentPadding;
-
-            Util.setWidthExcludingPaddingAndBorder(captionNode,
-                    parentWidthExcludingPadding - getCaptionMarginLeft(), 26,
-                    false);
-
-            int contentMarginLeft = getContentMarginLeft();
-
-            Util.setWidthExcludingPaddingAndBorder(contentNode,
-                    parentWidthExcludingPadding - contentMarginLeft, 2, false);
-
-        }
-
-        if ((BrowserInfo.get().isIE() || BrowserInfo.get().isFF2())
-                && (width == null || width.equals(""))) {
-            /*
-             * IE and FF2 needs width to be specified for the root DIV so we
-             * calculate that from the sizes of the caption and layout
-             */
-            int captionWidth = captionText.getOffsetWidth()
-                    + getCaptionMarginLeft() + getCaptionPaddingHorizontal();
-            int layoutWidth = ((Widget) layout).getOffsetWidth()
-                    + getContainerBorderWidth();
-            int width = layoutWidth;
-            if (captionWidth > width) {
-                width = captionWidth;
-            }
-
-            if (BrowserInfo.get().isIE7()) {
-                Util.setWidthExcludingPaddingAndBorder(captionNode, width
-                        - getCaptionMarginLeft(), 26, false);
-            }
-
-            super.setWidth(width + "px");
-        }
-
-        if (runGeckoFix && BrowserInfo.get().isGecko()) {
-            // workaround for #1764
-            if (width == null || width.equals("")) {
-                if (geckoCaptionMeter == null) {
-                    geckoCaptionMeter = DOM.createDiv();
-                    DOM.appendChild(captionNode, geckoCaptionMeter);
-                }
-                int captionWidth = DOM.getElementPropertyInt(captionText,
-                        "offsetWidth");
-                int availWidth = DOM.getElementPropertyInt(geckoCaptionMeter,
-                        "offsetWidth");
-                if (captionWidth == availWidth) {
-                    /*
-                     * Caption width defines panel width -> Gecko based browsers
-                     * somehow fails to float things right, without the
-                     * "noncode" below
-                     */
-                    setWidth(getOffsetWidth() + "px");
-                } else {
-                    DOM.setStyleAttribute(captionNode, "width", "");
-                }
-            }
-        }
-
-        client.runDescendentsLayout(this);
-
-        Util.runWebkitOverflowAutoFix(contentNode);
-
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        final Element target = DOM.eventGetTarget(event);
-        final int type = DOM.eventGetType(event);
-        if (type == Event.ONKEYDOWN && shortcutHandler != null) {
-            shortcutHandler.handleKeyboardEvent(event);
-            return;
-        }
-        if (type == Event.ONSCROLL) {
-            int newscrollTop = DOM.getElementPropertyInt(contentNode,
-                    "scrollTop");
-            int newscrollLeft = DOM.getElementPropertyInt(contentNode,
-                    "scrollLeft");
-            if (client != null
-                    && (newscrollLeft != scrollLeft || newscrollTop != scrollTop)) {
-                scrollLeft = newscrollLeft;
-                scrollTop = newscrollTop;
-                client.updateVariable(id, "scrollTop", scrollTop, false);
-                client.updateVariable(id, "scrollLeft", scrollLeft, false);
-            }
-        } else if (captionNode.isOrHasChild(target)) {
-            if (client != null) {
-                client.handleTooltipEvent(event, this);
-            }
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        this.height = height;
-        super.setHeight(height);
-        if (height != null && height != "") {
-            final int targetHeight = getOffsetHeight();
-            int containerHeight = targetHeight - captionNode.getOffsetHeight()
-                    - bottomDecoration.getOffsetHeight()
-                    - getContainerBorderHeight();
-            if (containerHeight < 0) {
-                containerHeight = 0;
-            }
-            DOM
-                    .setStyleAttribute(contentNode, "height", containerHeight
-                            + "px");
-        } else {
-            DOM.setStyleAttribute(contentNode, "height", "");
-        }
-        if (!rendering) {
-            runHacks(true);
-        }
-    }
-
-    private int getCaptionMarginLeft() {
-        if (captionMarginLeft < 0) {
-            detectContainerBorders();
-        }
-        return captionMarginLeft;
-    }
-
-    private int getContentMarginLeft() {
-        if (contentMarginLeft < 0) {
-            detectContainerBorders();
-        }
-        return contentMarginLeft;
-    }
-
-    private int getCaptionPaddingHorizontal() {
-        if (captionPaddingHorizontal < 0) {
-            detectContainerBorders();
-        }
-        return captionPaddingHorizontal;
-    }
-
-    private int getContainerBorderHeight() {
-        if (borderPaddingVertical < 0) {
-            detectContainerBorders();
-        }
-        return borderPaddingVertical;
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        this.width = width;
-        super.setWidth(width);
-        if (!rendering) {
-            runHacks(true);
-
-            if (height.equals("")) {
-                // Width change may affect height
-                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
-            }
-
-        }
-    }
-
-    private int getContainerBorderWidth() {
-        if (borderPaddingHorizontal < 0) {
-            detectContainerBorders();
-        }
-        return borderPaddingHorizontal;
-    }
-
-    private void detectContainerBorders() {
-        DOM.setStyleAttribute(contentNode, "overflow", "hidden");
-
-        borderPaddingHorizontal = Util.measureHorizontalBorder(contentNode);
-        borderPaddingVertical = Util.measureVerticalBorder(contentNode);
-
-        DOM.setStyleAttribute(contentNode, "overflow", "auto");
-
-        captionPaddingHorizontal = Util.measureHorizontalPaddingAndBorder(
-                captionNode, 26);
-
-        captionMarginLeft = Util.measureMarginLeft(captionNode);
-        contentMarginLeft = Util.measureMarginLeft(contentNode);
-
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (component != null && component == layout) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        // TODO This is untested as no layouts require this
-        if (oldComponent != layout) {
-            return;
-        }
-
-        setWidget(newComponent);
-        layout = (Paintable) newComponent;
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        int w = 0;
-        int h = 0;
-
-        if (width != null && !width.equals("")) {
-            w = getOffsetWidth() - getContainerBorderWidth();
-            if (w < 0) {
-                w = 0;
-            }
-        }
-
-        if (height != null && !height.equals("")) {
-            h = contentNode.getOffsetHeight() - getContainerBorderHeight();
-            if (h < 0) {
-                h = 0;
-            }
-        }
-
-        return new RenderSpace(w, h, true);
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        if (height != null && height != "" && width != null && width != "") {
-            /*
-             * If the height and width has been specified the child components
-             * cannot make the size of the layout change
-             */
-            return true;
-        }
-        runHacks(false);
-        return !renderInformation.updateSize(getElement());
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        // NOP: layouts caption, errors etc not rendered in Panel
-    }
-
-    @Override
-    protected void onAttach() {
-        super.onAttach();
-        detectContainerBorders();
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IPasswordField.java b/src/com/vaadin/terminal/gwt/client/ui/IPasswordField.java
deleted file mode 100644 (file)
index 569076e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import com.google.gwt.user.client.DOM;\r
-\r
-/**\r
- * This class represents a password field.\r
- * \r
- * @author IT Mill Ltd.\r
- * \r
- */\r
-public class IPasswordField extends ITextField {\r
-\r
-    public IPasswordField() {\r
-        super(DOM.createInputPassword());\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/IPopupCalendar.java
deleted file mode 100644 (file)
index 0b876f1..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import com.google.gwt.user.client.DOM;\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.ClickListener;\r
-import com.google.gwt.user.client.ui.PopupListener;\r
-import com.google.gwt.user.client.ui.PopupPanel;\r
-import com.google.gwt.user.client.ui.Widget;\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.Paintable;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class IPopupCalendar extends ITextualDate implements Paintable, Field,\r
-        ClickListener, PopupListener {\r
-\r
-    private final Button calendarToggle;\r
-\r
-    private final ICalendarPanel calendar;\r
-\r
-    private final IToolkitOverlay popup;\r
-    private boolean open = false;\r
-\r
-    public IPopupCalendar() {\r
-        super();\r
-\r
-        calendarToggle = new Button();\r
-        calendarToggle.setStyleName(CLASSNAME + "-button");\r
-        calendarToggle.setText("");\r
-        calendarToggle.addClickListener(this);\r
-        add(calendarToggle);\r
-\r
-        calendar = new ICalendarPanel(this);\r
-        popup = new IToolkitOverlay(true, true, true);\r
-        popup.setStyleName(IDateField.CLASSNAME + "-popup");\r
-        popup.setWidget(calendar);\r
-        popup.addPopupListener(this);\r
-\r
-        DOM.setElementProperty(calendar.getElement(), "id",\r
-                "PID_TOOLKIT_POPUPCAL");\r
-\r
-    }\r
-\r
-    @Override\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        super.updateFromUIDL(uidl, client);\r
-        if (date != null) {\r
-            calendar.updateCalendar();\r
-        }\r
-        calendarToggle.setEnabled(enabled);\r
-    }\r
-\r
-    public void onClick(Widget sender) {\r
-        if (sender == calendarToggle && !open) {\r
-            open = true;\r
-            calendar.updateCalendar();\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
-                    int t = calendarToggle.getAbsoluteTop();\r
-                    int l = calendarToggle.getAbsoluteLeft();\r
-                    if (l + w > Window.getClientWidth()\r
-                            + Window.getScrollLeft()) {\r
-                        l = Window.getClientWidth() + Window.getScrollLeft()\r
-                                - w;\r
-                    }\r
-                    if (t + h + calendarToggle.getOffsetHeight() + 30 > Window\r
-                            .getClientHeight()\r
-                            + Window.getScrollTop()) {\r
-                        t = Window.getClientHeight() + Window.getScrollTop()\r
-                                - h - calendarToggle.getOffsetHeight() - 30;\r
-                        l += calendarToggle.getOffsetWidth();\r
-                    }\r
-\r
-                    // fix size\r
-                    popup.setWidth(w + "px");\r
-                    popup.setHeight(h + "px");\r
-\r
-                    popup.setPopupPosition(l, t\r
-                            + calendarToggle.getOffsetHeight() + 2);\r
-\r
-                    setFocus(true);\r
-                }\r
-            });\r
-        }\r
-    }\r
-\r
-    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {\r
-        if (sender == popup) {\r
-            buildDate();\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
-    @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
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/IPopupView.java
deleted file mode 100644 (file)
index 8e89b45..0000000
+++ /dev/null
@@ -1,417 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HasFocus;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.PopupListener;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.ICaption;
-import com.vaadin.terminal.gwt.client.ICaptionWrapper;
-import com.vaadin.terminal.gwt.client.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.RenderInformation.Size;
-
-public class IPopupView extends HTML implements Container {
-
-    public static final String CLASSNAME = "i-popupview";
-
-    /** For server-client communication */
-    private String uidlId;
-    private ApplicationConnection client;
-
-    /** This variable helps to communicate popup visibility to the server */
-    private boolean hostPopupVisible;
-
-    private final CustomPopup popup;
-    private final Label loading = new Label("Loading...");
-
-    /**
-     * loading constructor
-     */
-    public IPopupView() {
-        super();
-        popup = new CustomPopup();
-
-        setStyleName(CLASSNAME);
-        popup.setStylePrimaryName(CLASSNAME + "-popup");
-
-        setHTML("(No HTML defined for PopupView)");
-        popup.setWidget(loading);
-
-        // When we click to open the popup...
-        addClickListener(new ClickListener() {
-            public void onClick(Widget sender) {
-                updateState(true);
-            }
-        });
-
-        // ..and when we close it
-        popup.addPopupListener(new PopupListener() {
-            public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
-                updateState(false);
-            }
-        });
-
-        popup.setAnimationEnabled(true);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-    }
-
-    /**
-     * 
-     * 
-     * @see com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal.gwt.client.UIDL,
-     *      com.vaadin.terminal.gwt.client.ApplicationConnection)
-     */
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // This call should be made first. Ensure correct implementation,
-        // and don't let the containing layout manage caption.
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-        // These are for future server connections
-        this.client = client;
-        uidlId = uidl.getId();
-
-        hostPopupVisible = uidl.getBooleanVariable("popupVisibility");
-
-        setHTML(uidl.getStringAttribute("html"));
-
-        if (uidl.hasAttribute("hideOnMouseOut")) {
-            popup.setHideOnMouseOut(uidl.getBooleanAttribute("hideOnMouseOut"));
-        }
-
-        // Render the popup if visible and show it.
-        if (hostPopupVisible) {
-            UIDL popupUIDL = uidl.getChildUIDL(0);
-
-            // showPopupOnTop(popup, hostReference);
-            preparePopup(popup);
-            popup.updateFromUIDL(popupUIDL, client);
-            if (uidl.hasAttribute("style")) {
-                final String[] styles = uidl.getStringAttribute("style").split(
-                        " ");
-                final StringBuffer styleBuf = new StringBuffer();
-                final String primaryName = popup.getStylePrimaryName();
-                styleBuf.append(primaryName);
-                for (int i = 0; i < styles.length; i++) {
-                    styleBuf.append(" ");
-                    styleBuf.append(primaryName);
-                    styleBuf.append("-");
-                    styleBuf.append(styles[i]);
-                }
-                popup.setStyleName(styleBuf.toString());
-            } else {
-                popup.setStyleName(popup.getStylePrimaryName());
-            }
-            showPopup(popup);
-
-            // The popup shouldn't be visible, try to hide it.
-        } else {
-            popup.hide();
-        }
-    }// updateFromUIDL
-
-    /**
-     * Update popup visibility to server
-     * 
-     * @param visibility
-     */
-    private void updateState(boolean visible) {
-        // If we know the server connection
-        // then update the current situation
-        if (uidlId != null && client != null && isAttached()) {
-            client.updateVariable(uidlId, "popupVisibility", visible, true);
-        }
-    }
-
-    private void preparePopup(final CustomPopup popup) {
-        popup.setVisible(false);
-        popup.show();
-    }
-
-    private void showPopup(final CustomPopup popup) {
-        int windowTop = RootPanel.get().getAbsoluteTop();
-        int windowLeft = RootPanel.get().getAbsoluteLeft();
-        int windowRight = windowLeft + RootPanel.get().getOffsetWidth();
-        int windowBottom = windowTop + RootPanel.get().getOffsetHeight();
-
-        int offsetWidth = popup.getOffsetWidth();
-        int offsetHeight = popup.getOffsetHeight();
-
-        int hostHorizontalCenter = IPopupView.this.getAbsoluteLeft()
-                + IPopupView.this.getOffsetWidth() / 2;
-        int hostVerticalCenter = IPopupView.this.getAbsoluteTop()
-                + IPopupView.this.getOffsetHeight() / 2;
-
-        int left = hostHorizontalCenter - offsetWidth / 2;
-        int top = hostVerticalCenter - offsetHeight / 2;
-
-        // Superclass takes care of top and left
-        if ((left + offsetWidth) > windowRight) {
-            left -= (left + offsetWidth) - windowRight;
-        }
-
-        if ((top + offsetHeight) > windowBottom) {
-            top -= (top + offsetHeight) - windowBottom;
-        }
-
-        popup.setPopupPosition(left, top);
-
-        popup.setVisible(true);
-    }
-
-    /**
-     * Make sure that we remove the popup when the main widget is removed.
-     * 
-     * @see com.google.gwt.user.client.ui.Widget#onUnload()
-     */
-    @Override
-    protected void onDetach() {
-        popup.hide();
-        super.onDetach();
-    }
-
-    private static native void nativeBlur(Element e)
-    /*-{ 
-        if(e && e.blur) {
-            e.blur();
-        }
-    }-*/;
-
-    private class CustomPopup extends IToolkitOverlay {
-
-        private Paintable popupComponentPaintable = null;
-        private Widget popupComponentWidget = null;
-        private ICaptionWrapper captionWrapper = null;
-
-        private boolean hasHadMouseOver = false;
-        private boolean hideOnMouseOut = true;
-        private final Set<Element> activeChildren = new HashSet<Element>();
-        private boolean hiding = false;
-
-        public CustomPopup() {
-            super(true, false, true); // autoHide, not modal, dropshadow
-        }
-
-        // For some reason ONMOUSEOUT events are not always received, so we have
-        // to use ONMOUSEMOVE that doesn't target the popup
-        @Override
-        public boolean onEventPreview(Event event) {
-            Element target = DOM.eventGetTarget(event);
-            boolean eventTargetsPopup = DOM.isOrHasChild(getElement(), target);
-            int type = DOM.eventGetType(event);
-
-            // Catch children that use keyboard, so we can unfocus them when
-            // hiding
-            if (eventTargetsPopup && type == Event.ONKEYPRESS) {
-                activeChildren.add(target);
-            }
-
-            if (eventTargetsPopup && type == Event.ONMOUSEMOVE) {
-                hasHadMouseOver = true;
-            }
-
-            if (!eventTargetsPopup && type == Event.ONMOUSEMOVE) {
-
-                if (hasHadMouseOver && hideOnMouseOut) {
-                    hide();
-                    return true;
-                }
-            }
-
-            return super.onEventPreview(event);
-        }
-
-        @Override
-        public void hide(boolean autoClosed) {
-            hiding = true;
-            syncChildren();
-            unregisterPaintables();
-            if (popupComponentWidget != null && popupComponentWidget != loading) {
-                remove(popupComponentWidget);
-            }
-            hasHadMouseOver = false;
-            super.hide(autoClosed);
-        }
-
-        @Override
-        public void show() {
-            hiding = false;
-            super.show();
-        }
-
-        /**
-         * Try to sync all known active child widgets to server
-         */
-        public void syncChildren() {
-            // Notify children with focus
-            if ((popupComponentWidget instanceof HasFocus)) {
-                ((HasFocus) popupComponentWidget).setFocus(false);
-            }
-
-            // Notify children that have used the keyboard
-            for (Element e : activeChildren) {
-                try {
-                    nativeBlur(e);
-                } catch (Exception ignored) {
-                }
-            }
-            activeChildren.clear();
-        }
-
-        @Override
-        public boolean remove(Widget w) {
-
-            popupComponentPaintable = null;
-            popupComponentWidget = null;
-            captionWrapper = null;
-
-            return super.remove(w);
-        }
-
-        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-
-            Paintable newPopupComponent = client.getPaintable(uidl
-                    .getChildUIDL(0));
-
-            if (newPopupComponent != popupComponentPaintable) {
-
-                setWidget((Widget) newPopupComponent);
-
-                popupComponentWidget = (Widget) newPopupComponent;
-
-                popupComponentPaintable = newPopupComponent;
-            }
-
-            popupComponentPaintable
-                    .updateFromUIDL(uidl.getChildUIDL(0), client);
-
-        }
-
-        public void unregisterPaintables() {
-            if (popupComponentPaintable != null) {
-                client.unregisterPaintable(popupComponentPaintable);
-            }
-        }
-
-        public void setHideOnMouseOut(boolean hideOnMouseOut) {
-            this.hideOnMouseOut = hideOnMouseOut;
-        }
-
-        /*
-         * 
-         * We need a hack make popup act as a child of IPopupView in toolkits
-         * component tree, but work in default GWT manner when closing or
-         * opening.
-         * 
-         * (non-Javadoc)
-         * 
-         * @see com.google.gwt.user.client.ui.Widget#getParent()
-         */
-        @Override
-        public Widget getParent() {
-            if (!isAttached() || hiding) {
-                return super.getParent();
-            } else {
-                return IPopupView.this;
-            }
-        }
-
-        @Override
-        protected void onDetach() {
-            super.onDetach();
-            hiding = false;
-        }
-
-        @Override
-        public Element getContainerElement() {
-            return super.getContainerElement();
-        }
-
-    }// class CustomPopup
-
-    // Container methods
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        Size popupExtra = calculatePopupExtra();
-
-        return new RenderSpace(RootPanel.get().getOffsetWidth()
-                - popupExtra.getWidth(), RootPanel.get().getOffsetHeight()
-                - popupExtra.getHeight());
-    }
-
-    /**
-     * Calculate extra space taken by the popup decorations
-     * 
-     * @return
-     */
-    protected Size calculatePopupExtra() {
-        Element pe = popup.getElement();
-        Element ipe = popup.getContainerElement();
-
-        // border + padding
-        int width = Util.getRequiredWidth(pe) - Util.getRequiredWidth(ipe);
-        int height = Util.getRequiredHeight(pe) - Util.getRequiredHeight(ipe);
-
-        return new Size(width, height);
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (popup.popupComponentWidget != null) {
-            return popup.popupComponentWidget == component;
-        } else {
-            return false;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        popup.setWidget(newComponent);
-        popup.popupComponentWidget = newComponent;
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        return true;
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        if (ICaption.isNeeded(uidl)) {
-            if (popup.captionWrapper != null) {
-                popup.captionWrapper.updateCaption(uidl);
-            } else {
-                popup.captionWrapper = new ICaptionWrapper(component, client);
-                popup.setWidget(popup.captionWrapper);
-                popup.captionWrapper.updateCaption(uidl);
-            }
-        } else {
-            if (popup.captionWrapper != null) {
-                popup.setWidget(popup.popupComponentWidget);
-            }
-        }
-
-        popup.popupComponentWidget = (Widget) component;
-        popup.popupComponentPaintable = component;
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        if (client != null) {
-            client.handleTooltipEvent(event, this);
-        }
-    }
-
-}// class IPopupView
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IProgressIndicator.java b/src/com/vaadin/terminal/gwt/client/ui/IProgressIndicator.java
deleted file mode 100644 (file)
index 0490dd0..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IProgressIndicator extends Widget implements Paintable {
-
-    private static final String CLASSNAME = "i-progressindicator";
-    Element wrapper = DOM.createDiv();
-    Element indicator = DOM.createDiv();
-    private ApplicationConnection client;
-    private final Poller poller;
-    private boolean indeterminate = false;
-    private boolean pollerSuspendedDueDetach;
-
-    public IProgressIndicator() {
-        setElement(DOM.createDiv());
-        getElement().appendChild(wrapper);
-        setStyleName(CLASSNAME);
-        wrapper.appendChild(indicator);
-        indicator.setClassName(CLASSNAME + "-indicator");
-        wrapper.setClassName(CLASSNAME + "-wrapper");
-        poller = new Poller();
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        poller.cancel();
-        this.client = client;
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        indeterminate = uidl.getBooleanAttribute("indeterminate");
-
-        if (indeterminate) {
-            String basename = CLASSNAME + "-indeterminate";
-            IProgressIndicator.setStyleName(getElement(), basename, true);
-            IProgressIndicator.setStyleName(getElement(), basename
-                    + "-disabled", uidl.getBooleanAttribute("disabled"));
-        } else {
-            try {
-                final float f = Float.parseFloat(uidl
-                        .getStringAttribute("state"));
-                final int size = Math.round(100 * f);
-                DOM.setStyleAttribute(indicator, "width", size + "%");
-            } catch (final Exception e) {
-            }
-        }
-
-        if (!uidl.getBooleanAttribute("disabled")) {
-            poller.scheduleRepeating(uidl.getIntAttribute("pollinginterval"));
-        }
-    }
-
-    @Override
-    protected void onAttach() {
-        super.onAttach();
-        if (pollerSuspendedDueDetach) {
-            poller.run();
-        }
-    }
-
-    @Override
-    protected void onDetach() {
-        super.onDetach();
-        poller.cancel();
-        pollerSuspendedDueDetach = true;
-    }
-
-    @Override
-    public void setVisible(boolean visible) {
-        super.setVisible(visible);
-        if (!visible) {
-            poller.cancel();
-        }
-    }
-
-    class Poller extends Timer {
-
-        @Override
-        public void run() {
-            client.sendPendingVariableChanges();
-        }
-
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/IScrollTable.java
deleted file mode 100644 (file)
index 2b085eb..0000000
+++ /dev/null
@@ -1,2841 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.Vector;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.NodeList;
-import com.google.gwt.dom.client.TableCellElement;
-import com.google.gwt.dom.client.TableRowElement;
-import com.google.gwt.dom.client.TableSectionElement;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-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.FlowPanel;
-import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.ScrollListener;
-import com.google.gwt.user.client.ui.ScrollPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.ui.IScrollTable.IScrollTableBody.IScrollTableRow;
-
-/**
- * IScrollTable
- * 
- * IScrollTable is a FlowPanel having two widgets in it: * TableHead component *
- * ScrollPanel
- * 
- * TableHead contains table's header and widgets + logic for resizing,
- * reordering and hiding columns.
- * 
- * ScrollPanel contains IScrollTableBody object which handles content. To save
- * some bandwidth and to improve clients responsiveness with loads of data, in
- * IScrollTableBody all rows are not necessary rendered. There are "spacers" in
- * IScrollTableBody to use the exact same space as non-rendered rows would use.
- * This way we can use seamlessly traditional scrollbars and scrolling to fetch
- * more rows instead of "paging".
- * 
- * In IScrollTable we listen to scroll events. On horizontal scrolling we also
- * update TableHeads scroll position which has its scrollbars hidden. On
- * vertical scroll events we will check if we are reaching the end of area where
- * we have rows rendered and
- * 
- * TODO implement unregistering for child components in Cells
- */
-public class IScrollTable extends FlowPanel implements Table, ScrollListener {
-
-    public static final String CLASSNAME = "i-table";
-    /**
-     * multiple of pagelength which component will cache when requesting more
-     * rows
-     */
-    private static final double CACHE_RATE = 2;
-    /**
-     * fraction of pageLenght which can be scrolled without making new request
-     */
-    private static final double CACHE_REACT_RATE = 1.5;
-
-    public static final char ALIGN_CENTER = 'c';
-    public static final char ALIGN_LEFT = 'b';
-    public static final char ALIGN_RIGHT = 'e';
-    private int firstRowInViewPort = 0;
-    private int pageLength = 15;
-    private int lastRequestedFirstvisible = 0; // to detect "serverside scroll"
-
-    private boolean showRowHeaders = false;
-
-    private String[] columnOrder;
-
-    private ApplicationConnection client;
-    private String paintableId;
-
-    private boolean immediate;
-
-    private int selectMode = Table.SELECT_MODE_NONE;
-
-    private final HashSet<String> selectedRowKeys = new HashSet<String>();
-
-    private boolean initializedAndAttached = false;
-
-    /**
-     * Flag to indicate if a column width recalculation is needed due update.
-     */
-    private boolean headerChangedDuringUpdate = false;
-
-    private final TableHead tHead = new TableHead();
-
-    private final ScrollPanel bodyContainer = new ScrollPanel();
-
-    private int totalRows;
-
-    private Set<String> collapsedColumns;
-
-    private final RowRequestHandler rowRequestHandler;
-    private IScrollTableBody tBody;
-    private int firstvisible = 0;
-    private boolean sortAscending;
-    private String sortColumn;
-    private boolean columnReordering;
-
-    /**
-     * This map contains captions and icon urls for actions like: * "33_c" ->
-     * "Edit" * "33_i" -> "http://dom.com/edit.png"
-     */
-    private final HashMap<Object, String> actionMap = new HashMap<Object, String>();
-    private String[] visibleColOrder;
-    private boolean initialContentReceived = false;
-    private Element scrollPositionElement;
-    private boolean enabled;
-    private boolean showColHeaders;
-
-    /** flag to indicate that table body has changed */
-    private boolean isNewBody = true;
-
-    private boolean emitClickEvents;
-
-    /*
-     * Read from the "recalcWidths" -attribute. When it is true, the table will
-     * recalculate the widths for columns - desirable in some cases. For #1983,
-     * marked experimental.
-     */
-    boolean recalcWidths = false;
-
-    private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>();
-    private String height;
-    private String width = "";
-    private boolean rendering = false;
-
-    public IScrollTable() {
-        bodyContainer.addScrollListener(this);
-        bodyContainer.setStyleName(CLASSNAME + "-body");
-
-        setStyleName(CLASSNAME);
-        add(tHead);
-        add(bodyContainer);
-
-        rowRequestHandler = new RowRequestHandler();
-
-    }
-
-    @SuppressWarnings("unchecked")
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-
-        // we may have pending cache row fetch, cancel it. See #2136
-        rowRequestHandler.cancel();
-
-        enabled = !uidl.hasAttribute("disabled");
-
-        this.client = client;
-        paintableId = uidl.getStringAttribute("id");
-        immediate = uidl.getBooleanAttribute("immediate");
-        emitClickEvents = uidl.getBooleanAttribute("listenClicks");
-        final int newTotalRows = uidl.getIntAttribute("totalrows");
-        if (newTotalRows != totalRows) {
-            if (tBody != null) {
-                if (totalRows == 0) {
-                    tHead.clear();
-                }
-                initializedAndAttached = false;
-                initialContentReceived = false;
-                isNewBody = true;
-            }
-            totalRows = newTotalRows;
-        }
-
-        recalcWidths = uidl.hasAttribute("recalcWidths");
-
-        pageLength = uidl.getIntAttribute("pagelength");
-        if (pageLength == 0) {
-            pageLength = totalRows;
-        }
-        firstvisible = uidl.hasVariable("firstvisible") ? uidl
-                .getIntVariable("firstvisible") : 0;
-        if (firstvisible != lastRequestedFirstvisible && tBody != null) {
-            // received 'surprising' firstvisible from server: scroll there
-            firstRowInViewPort = firstvisible;
-            bodyContainer
-                    .setScrollPosition(firstvisible * tBody.getRowHeight());
-        }
-
-        showRowHeaders = uidl.getBooleanAttribute("rowheaders");
-        showColHeaders = uidl.getBooleanAttribute("colheaders");
-
-        if (uidl.hasVariable("sortascending")) {
-            sortAscending = uidl.getBooleanVariable("sortascending");
-            sortColumn = uidl.getStringVariable("sortcolumn");
-        }
-
-        if (uidl.hasVariable("selected")) {
-            final Set<String> selectedKeys = uidl
-                    .getStringArrayVariableAsSet("selected");
-            selectedRowKeys.clear();
-            for (String string : selectedKeys) {
-                selectedRowKeys.add(string);
-            }
-        }
-
-        if (uidl.hasAttribute("selectmode")) {
-            if (uidl.getBooleanAttribute("readonly")) {
-                selectMode = Table.SELECT_MODE_NONE;
-            } else if (uidl.getStringAttribute("selectmode").equals("multi")) {
-                selectMode = Table.SELECT_MODE_MULTI;
-            } else if (uidl.getStringAttribute("selectmode").equals("single")) {
-                selectMode = Table.SELECT_MODE_SINGLE;
-            } else {
-                selectMode = Table.SELECT_MODE_NONE;
-            }
-        }
-
-        if (uidl.hasVariable("columnorder")) {
-            columnReordering = true;
-            columnOrder = uidl.getStringArrayVariable("columnorder");
-        }
-
-        if (uidl.hasVariable("collapsedcolumns")) {
-            tHead.setColumnCollapsingAllowed(true);
-            collapsedColumns = uidl
-                    .getStringArrayVariableAsSet("collapsedcolumns");
-        } else {
-            tHead.setColumnCollapsingAllowed(false);
-        }
-
-        UIDL rowData = null;
-        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
-            final UIDL c = (UIDL) it.next();
-            if (c.getTag().equals("rows")) {
-                rowData = c;
-            } else if (c.getTag().equals("actions")) {
-                updateActionMap(c);
-            } else if (c.getTag().equals("visiblecolumns")) {
-                tHead.updateCellsFromUIDL(c);
-            }
-        }
-        updateHeader(uidl.getStringArrayAttribute("vcolorder"));
-
-        if (!recalcWidths && initializedAndAttached) {
-            updateBody(rowData, uidl.getIntAttribute("firstrow"), uidl
-                    .getIntAttribute("rows"));
-            if (headerChangedDuringUpdate) {
-                lazyAdjustColumnWidths.schedule(1);
-            }
-        } else {
-            if (tBody != null) {
-                tBody.removeFromParent();
-                lazyUnregistryBag.add(tBody);
-            }
-            tBody = new IScrollTableBody();
-
-            tBody.renderInitialRows(rowData, uidl.getIntAttribute("firstrow"),
-                    uidl.getIntAttribute("rows"));
-            bodyContainer.add(tBody);
-            initialContentReceived = true;
-            if (isAttached()) {
-                sizeInit();
-            }
-        }
-        hideScrollPositionAnnotation();
-        purgeUnregistryBag();
-        rendering = false;
-        headerChangedDuringUpdate = false;
-    }
-
-    /**
-     * Unregisters Paintables in "trashed" HasWidgets (IScrollTableBodys or
-     * IScrollTableRows). This is done lazily as Table must survive from
-     * "subtreecaching" logic.
-     */
-    private void purgeUnregistryBag() {
-        for (Iterator<Panel> iterator = lazyUnregistryBag.iterator(); iterator
-                .hasNext();) {
-            client.unregisterChildPaintables(iterator.next());
-        }
-        lazyUnregistryBag.clear();
-    }
-
-    private void updateActionMap(UIDL c) {
-        final Iterator<?> it = c.getChildIterator();
-        while (it.hasNext()) {
-            final UIDL action = (UIDL) it.next();
-            final String key = action.getStringAttribute("key");
-            final String caption = action.getStringAttribute("caption");
-            actionMap.put(key + "_c", caption);
-            if (action.hasAttribute("icon")) {
-                // TODO need some uri handling ??
-                actionMap.put(key + "_i", client.translateToolkitUri(action
-                        .getStringAttribute("icon")));
-            }
-        }
-
-    }
-
-    public String getActionCaption(String actionKey) {
-        return actionMap.get(actionKey + "_c");
-    }
-
-    public String getActionIcon(String actionKey) {
-        return actionMap.get(actionKey + "_i");
-    }
-
-    private void updateHeader(String[] strings) {
-        if (strings == null) {
-            return;
-        }
-
-        int visibleCols = strings.length;
-        int colIndex = 0;
-        if (showRowHeaders) {
-            tHead.enableColumn("0", colIndex);
-            visibleCols++;
-            visibleColOrder = new String[visibleCols];
-            visibleColOrder[colIndex] = "0";
-            colIndex++;
-        } else {
-            visibleColOrder = new String[visibleCols];
-            tHead.removeCell("0");
-        }
-
-        int i;
-        for (i = 0; i < strings.length; i++) {
-            final String cid = strings[i];
-            visibleColOrder[colIndex] = cid;
-            tHead.enableColumn(cid, colIndex);
-            colIndex++;
-        }
-
-        tHead.setVisible(showColHeaders);
-
-    }
-
-    /**
-     * @param uidl
-     *            which contains row data
-     * @param firstRow
-     *            first row in data set
-     * @param reqRows
-     *            amount of rows in data set
-     */
-    private void updateBody(UIDL uidl, int firstRow, int reqRows) {
-        if (uidl == null || reqRows < 1) {
-            // container is empty, remove possibly existing rows
-            if (firstRow < 0) {
-                while (tBody.getLastRendered() > tBody.firstRendered) {
-                    tBody.unlinkRow(false);
-                }
-                tBody.unlinkRow(false);
-            }
-            return;
-        }
-
-        tBody.renderRows(uidl, firstRow, reqRows);
-
-        final int optimalFirstRow = (int) (firstRowInViewPort - pageLength
-                * CACHE_RATE);
-        boolean cont = true;
-        while (cont && tBody.getLastRendered() > optimalFirstRow
-                && tBody.getFirstRendered() < optimalFirstRow) {
-            // client.console.log("removing row from start");
-            cont = tBody.unlinkRow(true);
-        }
-        final int optimalLastRow = (int) (firstRowInViewPort + pageLength + pageLength
-                * CACHE_RATE);
-        cont = true;
-        while (cont && tBody.getLastRendered() > optimalLastRow) {
-            // client.console.log("removing row from the end");
-            cont = tBody.unlinkRow(false);
-        }
-        tBody.fixSpacers();
-
-    }
-
-    /**
-     * Gives correct column index for given column key ("cid" in UIDL).
-     * 
-     * @param colKey
-     * @return column index of visible columns, -1 if column not visible
-     */
-    private int getColIndexByKey(String colKey) {
-        // return 0 if asked for rowHeaders
-        if ("0".equals(colKey)) {
-            return 0;
-        }
-        for (int i = 0; i < visibleColOrder.length; i++) {
-            if (visibleColOrder[i].equals(colKey)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    private boolean isCollapsedColumn(String colKey) {
-        if (collapsedColumns == null) {
-            return false;
-        }
-        if (collapsedColumns.contains(colKey)) {
-            return true;
-        }
-        return false;
-    }
-
-    private String getColKeyByIndex(int index) {
-        return tHead.getHeaderCell(index).getColKey();
-    }
-
-    private void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
-        final HeaderCell cell = tHead.getHeaderCell(colIndex);
-        cell.setWidth(w, isDefinedWidth);
-        tBody.setColWidth(colIndex, w);
-    }
-
-    private int getColWidth(String colKey) {
-        return tHead.getHeaderCell(colKey).getWidth();
-    }
-
-    private IScrollTableRow getRenderedRowByKey(String key) {
-        final Iterator<Widget> it = tBody.iterator();
-        IScrollTableRow r = null;
-        while (it.hasNext()) {
-            r = (IScrollTableRow) it.next();
-            if (r.getKey().equals(key)) {
-                return r;
-            }
-        }
-        return null;
-    }
-
-    private void reOrderColumn(String columnKey, int newIndex) {
-
-        final int oldIndex = getColIndexByKey(columnKey);
-
-        // Change header order
-        tHead.moveCell(oldIndex, newIndex);
-
-        // Change body order
-        tBody.moveCol(oldIndex, newIndex);
-
-        /*
-         * Build new columnOrder and update it to server Note that columnOrder
-         * also contains collapsed columns so we cannot directly build it from
-         * cells vector Loop the old columnOrder and append in order to new
-         * array unless on moved columnKey. On new index also put the moved key
-         * i == index on columnOrder, j == index on newOrder
-         */
-        final String oldKeyOnNewIndex = visibleColOrder[newIndex];
-        if (showRowHeaders) {
-            newIndex--; // columnOrder don't have rowHeader
-        }
-        // add back hidden rows,
-        for (int i = 0; i < columnOrder.length; i++) {
-            if (columnOrder[i].equals(oldKeyOnNewIndex)) {
-                break; // break loop at target
-            }
-            if (isCollapsedColumn(columnOrder[i])) {
-                newIndex++;
-            }
-        }
-        // finally we can build the new columnOrder for server
-        final String[] newOrder = new String[columnOrder.length];
-        for (int i = 0, j = 0; j < newOrder.length; i++) {
-            if (j == newIndex) {
-                newOrder[j] = columnKey;
-                j++;
-            }
-            if (i == columnOrder.length) {
-                break;
-            }
-            if (columnOrder[i].equals(columnKey)) {
-                continue;
-            }
-            newOrder[j] = columnOrder[i];
-            j++;
-        }
-        columnOrder = newOrder;
-        // also update visibleColumnOrder
-        int i = showRowHeaders ? 1 : 0;
-        for (int j = 0; j < newOrder.length; j++) {
-            final String cid = newOrder[j];
-            if (!isCollapsedColumn(cid)) {
-                visibleColOrder[i++] = cid;
-            }
-        }
-        client.updateVariable(paintableId, "columnorder", columnOrder, false);
-    }
-
-    @Override
-    protected void onAttach() {
-        super.onAttach();
-        if (initialContentReceived) {
-            sizeInit();
-        }
-    }
-
-    @Override
-    protected void onDetach() {
-        rowRequestHandler.cancel();
-        super.onDetach();
-        // ensure that scrollPosElement will be detached
-        if (scrollPositionElement != null) {
-            final Element parent = DOM.getParent(scrollPositionElement);
-            if (parent != null) {
-                DOM.removeChild(parent, scrollPositionElement);
-            }
-        }
-    }
-
-    /**
-     * Run only once when component is attached and received its initial
-     * content. This function : * Syncs headers and bodys "natural widths and
-     * saves the values. * Sets proper width and height * Makes deferred request
-     * to get some cache rows
-     */
-    private void sizeInit() {
-        /*
-         * We will use browsers table rendering algorithm to find proper column
-         * widths. If content and header take less space than available, we will
-         * divide extra space relatively to each column which has not width set.
-         * 
-         * Overflow pixels are added to last column.
-         */
-
-        Iterator<Widget> headCells = tHead.iterator();
-        int i = 0;
-        int totalExplicitColumnsWidths = 0;
-        int total = 0;
-        float expandRatioDivider = 0;
-
-        final int[] widths = new int[tHead.visibleCells.size()];
-
-        tHead.enableBrowserIntelligence();
-        // first loop: collect natural widths
-        while (headCells.hasNext()) {
-            final HeaderCell hCell = (HeaderCell) headCells.next();
-            int w = hCell.getWidth();
-            if (hCell.isDefinedWidth()) {
-                // server has defined column width explicitly
-                totalExplicitColumnsWidths += w;
-            } else {
-                if (hCell.getExpandRatio() > 0) {
-                    expandRatioDivider += hCell.getExpandRatio();
-                    w = 0;
-                } else {
-                    // get and store greater of header width and column width,
-                    // and
-                    // store it as a minimumn natural col width
-                    w = hCell.getNaturalColumnWidth(i);
-                }
-                hCell.setNaturalMinimumColumnWidth(w);
-            }
-            widths[i] = w;
-            total += w;
-            i++;
-        }
-
-        tHead.disableBrowserIntelligence();
-
-        boolean willHaveScrollbarz = willHaveScrollbars();
-
-        // fix "natural" width if width not set
-        if (width == null || "".equals(width)) {
-            int w = total;
-            w += tBody.getCellExtraWidth() * visibleColOrder.length;
-            if (willHaveScrollbarz) {
-                w += Util.getNativeScrollbarSize();
-            }
-            setContentWidth(w);
-        }
-
-        int availW = tBody.getAvailableWidth();
-        if (BrowserInfo.get().isIE()) {
-            // Hey IE, are you really sure about this?
-            availW = tBody.getAvailableWidth();
-        }
-        availW -= tBody.getCellExtraWidth() * visibleColOrder.length;
-
-        if (willHaveScrollbarz) {
-            availW -= Util.getNativeScrollbarSize();
-        }
-
-        boolean needsReLayout = false;
-
-        if (availW > total) {
-            // natural size is smaller than available space
-            final int extraSpace = availW - total;
-            final int totalWidthR = total - totalExplicitColumnsWidths;
-            if (totalWidthR > 0) {
-                needsReLayout = true;
-
-                if (expandRatioDivider > 0) {
-                    // visible columns have some active expand ratios, excess
-                    // space is divided according to them
-                    headCells = tHead.iterator();
-                    i = 0;
-                    while (headCells.hasNext()) {
-                        HeaderCell hCell = (HeaderCell) headCells.next();
-                        if (hCell.getExpandRatio() > 0) {
-                            int w = widths[i];
-                            final int newSpace = (int) (extraSpace * (hCell
-                                    .getExpandRatio() / expandRatioDivider));
-                            w += newSpace;
-                            widths[i] = w;
-                        }
-                        i++;
-                    }
-                } else {
-                    // now we will share this sum relatively to those without
-                    // explicit width
-                    headCells = tHead.iterator();
-                    i = 0;
-                    while (headCells.hasNext()) {
-                        HeaderCell hCell = (HeaderCell) headCells.next();
-                        if (!hCell.isDefinedWidth()) {
-                            int w = widths[i];
-                            final int newSpace = extraSpace * w / totalWidthR;
-                            w += newSpace;
-                            widths[i] = w;
-                        }
-                        i++;
-                    }
-                }
-            }
-
-        } else {
-            // bodys size will be more than available and scrollbar will appear
-        }
-
-        // last loop: set possibly modified values or reset if new tBody
-        i = 0;
-        headCells = tHead.iterator();
-        while (headCells.hasNext()) {
-            final HeaderCell hCell = (HeaderCell) headCells.next();
-            if (isNewBody || hCell.getWidth() == -1) {
-                final int w = widths[i];
-                setColWidth(i, w, false);
-            }
-            i++;
-        }
-        if (needsReLayout) {
-            tBody.reLayoutComponents();
-        }
-
-        /*
-         * Fix "natural" height if height is not set. This must be after width
-         * fixing so the components' widths have been adjusted.
-         */
-        if (height == null || "".equals(height)) {
-            /*
-             * We must force an update of the row height as this point as it
-             * might have been (incorrectly) calculated earlier
-             */
-            if (pageLength == totalRows) {
-                /*
-                 * A hack to support variable height rows when paging is off.
-                 * Generally this is not supported by scrolltable. We want to
-                 * show all rows so the bodyHeight should be equal to the table
-                 * height.
-                 */
-                int bodyHeight = tBody.getOffsetHeight();
-                bodyContainer.setHeight(bodyHeight + "px");
-                Util.runWebkitOverflowAutoFix(bodyContainer.getElement());
-            } else {
-                int bodyHeight = (tBody.getRowHeight(true) * pageLength);
-                bodyContainer.setHeight(bodyHeight + "px");
-            }
-        }
-
-        isNewBody = false;
-
-        if (firstvisible > 0) {
-            // Deferred due some Firefox oddities. IE & Safari could survive
-            // without
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    bodyContainer.setScrollPosition(firstvisible
-                            * tBody.getRowHeight());
-                    firstRowInViewPort = firstvisible;
-                }
-            });
-        }
-
-        if (enabled) {
-            // Do we need cache rows
-            if (tBody.getLastRendered() + 1 < firstRowInViewPort + pageLength
-                    + CACHE_REACT_RATE * pageLength) {
-                if (totalRows - 1 > tBody.getLastRendered()) {
-                    // fetch cache rows
-                    rowRequestHandler
-                            .setReqFirstRow(tBody.getLastRendered() + 1);
-                    rowRequestHandler
-                            .setReqRows((int) (pageLength * CACHE_RATE));
-                    rowRequestHandler.deferRowFetch(1);
-                }
-            }
-        }
-        initializedAndAttached = true;
-    }
-
-    private boolean willHaveScrollbars() {
-        if (!(height != null && !height.equals(""))) {
-            if (pageLength < totalRows) {
-                return true;
-            }
-        } else {
-            int fakeheight = tBody.getRowHeight() * totalRows;
-            int availableHeight = bodyContainer.getElement().getPropertyInt(
-                    "clientHeight");
-            if (fakeheight > availableHeight) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * This method has logic which rows needs to be requested from server when
-     * user scrolls
-     */
-    public void onScroll(Widget widget, int scrollLeft, int scrollTop) {
-        if (!initializedAndAttached) {
-            return;
-        }
-        if (!enabled) {
-            bodyContainer.setScrollPosition(firstRowInViewPort
-                    * tBody.getRowHeight());
-            return;
-        }
-
-        rowRequestHandler.cancel();
-
-        // fix headers horizontal scrolling
-        tHead.setHorizontalScrollPosition(scrollLeft);
-
-        firstRowInViewPort = (int) Math.ceil(scrollTop
-                / (double) tBody.getRowHeight());
-
-        int postLimit = (int) (firstRowInViewPort + pageLength + pageLength
-                * CACHE_REACT_RATE);
-        if (postLimit > totalRows - 1) {
-            postLimit = totalRows - 1;
-        }
-        int preLimit = (int) (firstRowInViewPort - pageLength
-                * CACHE_REACT_RATE);
-        if (preLimit < 0) {
-            preLimit = 0;
-        }
-        final int lastRendered = tBody.getLastRendered();
-        final int firstRendered = tBody.getFirstRendered();
-
-        if (postLimit <= lastRendered && preLimit >= firstRendered) {
-            // remember which firstvisible we requested, in case the server has
-            // a differing opinion
-            lastRequestedFirstvisible = firstRowInViewPort;
-            client.updateVariable(paintableId, "firstvisible",
-                    firstRowInViewPort, false);
-            return; // scrolled withing "non-react area"
-        }
-
-        if (firstRowInViewPort - pageLength * CACHE_RATE > lastRendered
-                || firstRowInViewPort + pageLength + pageLength * CACHE_RATE < firstRendered) {
-            // need a totally new set
-            rowRequestHandler
-                    .setReqFirstRow((int) (firstRowInViewPort - pageLength
-                            * CACHE_RATE));
-            int last = firstRowInViewPort + (int) CACHE_RATE * pageLength
-                    + pageLength;
-            if (last > totalRows) {
-                last = totalRows - 1;
-            }
-            rowRequestHandler.setReqRows(last
-                    - rowRequestHandler.getReqFirstRow() + 1);
-            rowRequestHandler.deferRowFetch();
-            return;
-        }
-        if (preLimit < firstRendered) {
-            // need some rows to the beginning of the rendered area
-            rowRequestHandler
-                    .setReqFirstRow((int) (firstRowInViewPort - pageLength
-                            * CACHE_RATE));
-            rowRequestHandler.setReqRows(firstRendered
-                    - rowRequestHandler.getReqFirstRow());
-            rowRequestHandler.deferRowFetch();
-
-            return;
-        }
-        if (postLimit > lastRendered) {
-            // need some rows to the end of the rendered area
-            rowRequestHandler.setReqFirstRow(lastRendered + 1);
-            rowRequestHandler.setReqRows((int) ((firstRowInViewPort
-                    + pageLength + pageLength * CACHE_RATE) - lastRendered));
-            rowRequestHandler.deferRowFetch();
-        }
-
-    }
-
-    private void announceScrollPosition() {
-        if (scrollPositionElement == null) {
-            scrollPositionElement = DOM.createDiv();
-            DOM.setElementProperty(scrollPositionElement, "className",
-                    "i-table-scrollposition");
-            DOM.appendChild(getElement(), scrollPositionElement);
-        }
-
-        DOM.setStyleAttribute(scrollPositionElement, "position", "absolute");
-        DOM.setStyleAttribute(scrollPositionElement, "marginLeft", (DOM
-                .getElementPropertyInt(getElement(), "offsetWidth") / 2 - 80)
-                + "px");
-        DOM.setStyleAttribute(scrollPositionElement, "marginTop", -(DOM
-                .getElementPropertyInt(getElement(), "offsetHeight") - 2)
-                + "px");
-
-        // indexes go from 1-totalRows, as rowheaders in index-mode indicate
-        int last = (firstRowInViewPort + (bodyContainer.getOffsetHeight() / tBody
-                .getRowHeight()));
-        if (last > totalRows) {
-            last = totalRows;
-        }
-        DOM.setInnerHTML(scrollPositionElement, "<span>"
-                + (firstRowInViewPort + 1) + " &ndash; " + last + "..."
-                + "</span>");
-        DOM.setStyleAttribute(scrollPositionElement, "display", "block");
-    }
-
-    private void hideScrollPositionAnnotation() {
-        if (scrollPositionElement != null) {
-            DOM.setStyleAttribute(scrollPositionElement, "display", "none");
-        }
-    }
-
-    private class RowRequestHandler extends Timer {
-
-        private int reqFirstRow = 0;
-        private int reqRows = 0;
-
-        public void deferRowFetch() {
-            deferRowFetch(250);
-        }
-
-        public void deferRowFetch(int msec) {
-            if (reqRows > 0 && reqFirstRow < totalRows) {
-                schedule(msec);
-
-                // tell scroll position to user if currently "visible" rows are
-                // not rendered
-                if ((firstRowInViewPort + pageLength > tBody.getLastRendered())
-                        || (firstRowInViewPort < tBody.getFirstRendered())) {
-                    announceScrollPosition();
-                } else {
-                    hideScrollPositionAnnotation();
-                }
-            }
-        }
-
-        public void setReqFirstRow(int reqFirstRow) {
-            if (reqFirstRow < 0) {
-                reqFirstRow = 0;
-            } else if (reqFirstRow >= totalRows) {
-                reqFirstRow = totalRows - 1;
-            }
-            this.reqFirstRow = reqFirstRow;
-        }
-
-        public void setReqRows(int reqRows) {
-            this.reqRows = reqRows;
-        }
-
-        @Override
-        public void run() {
-            if (client.hasActiveRequest()) {
-                // if client connection is busy, don't bother loading it more
-                schedule(250);
-
-            } else {
-
-                int firstToBeRendered = tBody.firstRendered;
-                if (reqFirstRow < firstToBeRendered) {
-                    firstToBeRendered = reqFirstRow;
-                } else if (firstRowInViewPort - (int) (CACHE_RATE * pageLength) > firstToBeRendered) {
-                    firstToBeRendered = firstRowInViewPort
-                            - (int) (CACHE_RATE * pageLength);
-                    if (firstToBeRendered < 0) {
-                        firstToBeRendered = 0;
-                    }
-                }
-
-                int lastToBeRendered = tBody.lastRendered;
-
-                if (reqFirstRow + reqRows - 1 > lastToBeRendered) {
-                    lastToBeRendered = reqFirstRow + reqRows - 1;
-                } else if (firstRowInViewPort + pageLength + pageLength
-                        * CACHE_RATE < lastToBeRendered) {
-                    lastToBeRendered = (firstRowInViewPort + pageLength + (int) (pageLength * CACHE_RATE));
-                    if (lastToBeRendered >= totalRows) {
-                        lastToBeRendered = totalRows - 1;
-                    }
-                    // due Safari 3.1 bug (see #2607), verify reqrows, original
-                    // problem unknown, but this should catch the issue
-                    if (reqFirstRow + reqRows - 1 > lastToBeRendered) {
-                        reqRows = lastToBeRendered - reqFirstRow;
-                    }
-                }
-
-                client.updateVariable(paintableId, "firstToBeRendered",
-                        firstToBeRendered, false);
-
-                client.updateVariable(paintableId, "lastToBeRendered",
-                        lastToBeRendered, false);
-                // remember which firstvisible we requested, in case the server
-                // has
-                // a differing opinion
-                lastRequestedFirstvisible = firstRowInViewPort;
-                client.updateVariable(paintableId, "firstvisible",
-                        firstRowInViewPort, false);
-                client.updateVariable(paintableId, "reqfirstrow", reqFirstRow,
-                        false);
-                client.updateVariable(paintableId, "reqrows", reqRows, true);
-
-            }
-        }
-
-        public int getReqFirstRow() {
-            return reqFirstRow;
-        }
-
-        public int getReqRows() {
-            return reqRows;
-        }
-
-        /**
-         * Sends request to refresh content at this position.
-         */
-        public void refreshContent() {
-            int first = (int) (firstRowInViewPort - pageLength * CACHE_RATE);
-            int reqRows = (int) (2 * pageLength * CACHE_RATE + pageLength);
-            if (first < 0) {
-                reqRows = reqRows + first;
-                first = 0;
-            }
-            setReqFirstRow(first);
-            setReqRows(reqRows);
-            run();
-        }
-    }
-
-    public class HeaderCell extends Widget {
-
-        Element td = DOM.createTD();
-
-        Element captionContainer = DOM.createDiv();
-
-        Element colResizeWidget = DOM.createDiv();
-
-        Element floatingCopyOfHeaderCell;
-
-        private boolean sortable = false;
-        private final String cid;
-        private boolean dragging;
-
-        private int dragStartX;
-        private int colIndex;
-        private int originalWidth;
-
-        private boolean isResizing;
-
-        private int headerX;
-
-        private boolean moved;
-
-        private int closestSlot;
-
-        private int width = -1;
-
-        private int naturalWidth = -1;
-
-        private char align = ALIGN_LEFT;
-
-        boolean definedWidth = false;
-
-        private float expandRatio = 0;
-
-        public void setSortable(boolean b) {
-            sortable = b;
-        }
-
-        public void setNaturalMinimumColumnWidth(int w) {
-            naturalWidth = w;
-        }
-
-        public HeaderCell(String colId, String headerText) {
-            cid = colId;
-
-            DOM.setElementProperty(colResizeWidget, "className", CLASSNAME
-                    + "-resizer");
-            DOM.sinkEvents(colResizeWidget, Event.MOUSEEVENTS);
-
-            setText(headerText);
-
-            DOM.appendChild(td, colResizeWidget);
-
-            DOM.setElementProperty(captionContainer, "className", CLASSNAME
-                    + "-caption-container");
-
-            // ensure no clipping initially (problem on column additions)
-            DOM.setStyleAttribute(captionContainer, "overflow", "visible");
-
-            DOM.sinkEvents(captionContainer, Event.MOUSEEVENTS);
-
-            DOM.appendChild(td, captionContainer);
-
-            DOM.sinkEvents(td, Event.MOUSEEVENTS);
-
-            setElement(td);
-        }
-
-        public void setWidth(int w, boolean ensureDefinedWidth) {
-            if (ensureDefinedWidth) {
-                definedWidth = true;
-                // on column resize expand ratio becomes zero
-                expandRatio = 0;
-            }
-            if (width == w) {
-                return;
-            }
-            if (width == -1) {
-                // go to default mode, clip content if necessary
-                DOM.setStyleAttribute(captionContainer, "overflow", "");
-            }
-            width = w;
-            if (w == -1) {
-                DOM.setStyleAttribute(captionContainer, "width", "");
-                setWidth("");
-            } else {
-
-                captionContainer.getStyle().setPropertyPx("width", w);
-
-                /*
-                 * if we already have tBody, set the header width properly, if
-                 * not defer it. IE will fail with complex float in table header
-                 * unless TD width is not explicitly set.
-                 */
-                if (tBody != null) {
-                    int tdWidth = width + tBody.getCellExtraWidth();
-                    setWidth(tdWidth + "px");
-                } else {
-                    DeferredCommand.addCommand(new Command() {
-                        public void execute() {
-                            int tdWidth = width + tBody.getCellExtraWidth();
-                            setWidth(tdWidth + "px");
-                        }
-                    });
-                }
-            }
-        }
-
-        public void setUndefinedWidth() {
-            definedWidth = false;
-            setWidth(-1, false);
-        }
-
-        /**
-         * Detects if width is fixed by developer on server side or resized to
-         * current width by user.
-         * 
-         * @return true if defined, false if "natural" width
-         */
-        public boolean isDefinedWidth() {
-            return definedWidth;
-        }
-
-        public int getWidth() {
-            return width;
-        }
-
-        public void setText(String headerText) {
-            DOM.setInnerHTML(captionContainer, headerText);
-        }
-
-        public String getColKey() {
-            return cid;
-        }
-
-        private void setSorted(boolean sorted) {
-            if (sorted) {
-                if (sortAscending) {
-                    this.setStyleName(CLASSNAME + "-header-cell-asc");
-                } else {
-                    this.setStyleName(CLASSNAME + "-header-cell-desc");
-                }
-            } else {
-                this.setStyleName(CLASSNAME + "-header-cell");
-            }
-        }
-
-        /**
-         * Handle column reordering.
-         */
-        @Override
-        public void onBrowserEvent(Event event) {
-            if (enabled && event != null) {
-                if (isResizing || event.getTarget() == colResizeWidget) {
-                    onResizeEvent(event);
-                } else {
-                    handleCaptionEvent(event);
-                }
-            }
-        }
-
-        private void createFloatingCopy() {
-            floatingCopyOfHeaderCell = DOM.createDiv();
-            DOM.setInnerHTML(floatingCopyOfHeaderCell, DOM.getInnerHTML(td));
-            floatingCopyOfHeaderCell = DOM
-                    .getChild(floatingCopyOfHeaderCell, 1);
-            DOM.setElementProperty(floatingCopyOfHeaderCell, "className",
-                    CLASSNAME + "-header-drag");
-            updateFloatingCopysPosition(DOM.getAbsoluteLeft(td), DOM
-                    .getAbsoluteTop(td));
-            DOM.appendChild(RootPanel.get().getElement(),
-                    floatingCopyOfHeaderCell);
-        }
-
-        private void updateFloatingCopysPosition(int x, int y) {
-            x -= DOM.getElementPropertyInt(floatingCopyOfHeaderCell,
-                    "offsetWidth") / 2;
-            DOM.setStyleAttribute(floatingCopyOfHeaderCell, "left", x + "px");
-            if (y > 0) {
-                DOM.setStyleAttribute(floatingCopyOfHeaderCell, "top", (y + 7)
-                        + "px");
-            }
-        }
-
-        private void hideFloatingCopy() {
-            DOM.removeChild(RootPanel.get().getElement(),
-                    floatingCopyOfHeaderCell);
-            floatingCopyOfHeaderCell = null;
-        }
-
-        protected void handleCaptionEvent(Event event) {
-            switch (DOM.eventGetType(event)) {
-            case Event.ONMOUSEDOWN:
-                if (columnReordering) {
-                    dragging = true;
-                    moved = false;
-                    colIndex = getColIndexByKey(cid);
-                    DOM.setCapture(getElement());
-                    headerX = tHead.getAbsoluteLeft();
-                    DOM.eventPreventDefault(event); // prevent selecting text
-                }
-                break;
-            case Event.ONMOUSEUP:
-                if (columnReordering) {
-                    dragging = false;
-                    DOM.releaseCapture(getElement());
-                    if (moved) {
-                        hideFloatingCopy();
-                        tHead.removeSlotFocus();
-                        if (closestSlot != colIndex
-                                && closestSlot != (colIndex + 1)) {
-                            if (closestSlot > colIndex) {
-                                reOrderColumn(cid, closestSlot - 1);
-                            } else {
-                                reOrderColumn(cid, closestSlot);
-                            }
-                        }
-                    }
-                }
-
-                if (!moved) {
-                    // mouse event was a click to header -> sort column
-                    if (sortable) {
-                        if (sortColumn.equals(cid)) {
-                            // just toggle order
-                            client.updateVariable(paintableId, "sortascending",
-                                    !sortAscending, false);
-                        } else {
-                            // set table scrolled by this column
-                            client.updateVariable(paintableId, "sortcolumn",
-                                    cid, false);
-                        }
-                        // get also cache columns at the same request
-                        bodyContainer.setScrollPosition(0);
-                        firstvisible = 0;
-                        rowRequestHandler.setReqFirstRow(0);
-                        rowRequestHandler.setReqRows((int) (2 * pageLength
-                                * CACHE_RATE + pageLength));
-                        rowRequestHandler.deferRowFetch();
-                    }
-                    break;
-                }
-                break;
-            case Event.ONMOUSEMOVE:
-                if (dragging) {
-                    if (!moved) {
-                        createFloatingCopy();
-                        moved = true;
-                    }
-                    final int x = DOM.eventGetClientX(event)
-                            + DOM.getElementPropertyInt(tHead.hTableWrapper,
-                                    "scrollLeft");
-                    int slotX = headerX;
-                    closestSlot = colIndex;
-                    int closestDistance = -1;
-                    int start = 0;
-                    if (showRowHeaders) {
-                        start++;
-                    }
-                    final int visibleCellCount = tHead.getVisibleCellCount();
-                    for (int i = start; i <= visibleCellCount; i++) {
-                        if (i > 0) {
-                            final String colKey = getColKeyByIndex(i - 1);
-                            slotX += getColWidth(colKey);
-                        }
-                        final int dist = Math.abs(x - slotX);
-                        if (closestDistance == -1 || dist < closestDistance) {
-                            closestDistance = dist;
-                            closestSlot = i;
-                        }
-                    }
-                    tHead.focusSlot(closestSlot);
-
-                    updateFloatingCopysPosition(DOM.eventGetClientX(event), -1);
-                }
-                break;
-            default:
-                break;
-            }
-        }
-
-        private void onResizeEvent(Event event) {
-            switch (DOM.eventGetType(event)) {
-            case Event.ONMOUSEDOWN:
-                isResizing = true;
-                DOM.setCapture(getElement());
-                dragStartX = DOM.eventGetClientX(event);
-                colIndex = getColIndexByKey(cid);
-                originalWidth = getWidth();
-                DOM.eventPreventDefault(event);
-                break;
-            case Event.ONMOUSEUP:
-                isResizing = false;
-                DOM.releaseCapture(getElement());
-                // readjust undefined width columns
-                lazyAdjustColumnWidths.cancel();
-                lazyAdjustColumnWidths.schedule(1);
-                break;
-            case Event.ONMOUSEMOVE:
-                if (isResizing) {
-                    final int deltaX = DOM.eventGetClientX(event) - dragStartX;
-                    if (deltaX == 0) {
-                        return;
-                    }
-
-                    int newWidth = originalWidth + deltaX;
-                    if (newWidth < tBody.getCellExtraWidth()) {
-                        newWidth = tBody.getCellExtraWidth();
-                    }
-                    setColWidth(colIndex, newWidth, true);
-                }
-                break;
-            default:
-                break;
-            }
-        }
-
-        public String getCaption() {
-            return DOM.getInnerText(captionContainer);
-        }
-
-        public boolean isEnabled() {
-            return getParent() != null;
-        }
-
-        public void setAlign(char c) {
-            if (align != c) {
-                switch (c) {
-                case ALIGN_CENTER:
-                    DOM.setStyleAttribute(captionContainer, "textAlign",
-                            "center");
-                    break;
-                case ALIGN_RIGHT:
-                    DOM.setStyleAttribute(captionContainer, "textAlign",
-                            "right");
-                    break;
-                default:
-                    DOM.setStyleAttribute(captionContainer, "textAlign", "");
-                    break;
-                }
-            }
-            align = c;
-        }
-
-        public char getAlign() {
-            return align;
-        }
-
-        /**
-         * Detects the natural minimum width for the column of this header cell.
-         * If column is resized by user or the width is defined by server the
-         * actual width is returned. Else the natural min width is returned.
-         * 
-         * @param columnIndex
-         *            column index hint, if -1 (unknown) it will be detected
-         * 
-         * @return
-         */
-        public int getNaturalColumnWidth(int columnIndex) {
-            if (isDefinedWidth()) {
-                return width;
-            } else {
-                if (naturalWidth < 0) {
-                    // This is recently revealed column. Try to detect a proper
-                    // value (greater of header and data
-                    // cols)
-
-                    final int hw = ((Element) getElement().getLastChild())
-                            .getOffsetWidth()
-                            + tBody.getCellExtraWidth();
-                    if (columnIndex < 0) {
-                        columnIndex = 0;
-                        for (Iterator<Widget> it = tHead.iterator(); it
-                                .hasNext(); columnIndex++) {
-                            if (it.next() == this) {
-                                break;
-                            }
-                        }
-                    }
-                    final int cw = tBody.getColWidth(columnIndex);
-                    naturalWidth = (hw > cw ? hw : cw);
-                }
-                return naturalWidth;
-            }
-        }
-
-        public void setExpandRatio(float floatAttribute) {
-            expandRatio = floatAttribute;
-        }
-
-        public float getExpandRatio() {
-            return expandRatio;
-        }
-
-    }
-
-    /**
-     * HeaderCell that is header cell for row headers.
-     * 
-     * Reordering disabled and clicking on it resets sorting.
-     */
-    public class RowHeadersHeaderCell extends HeaderCell {
-
-        RowHeadersHeaderCell() {
-            super("0", "");
-        }
-
-        @Override
-        protected void handleCaptionEvent(Event event) {
-            // NOP: RowHeaders cannot be reordered
-            // TODO It'd be nice to reset sorting here
-        }
-    }
-
-    public class TableHead extends Panel implements ActionOwner {
-
-        private static final int WRAPPER_WIDTH = 9000;
-
-        Vector<Widget> visibleCells = new Vector<Widget>();
-
-        HashMap<String, HeaderCell> availableCells = new HashMap<String, HeaderCell>();
-
-        Element div = DOM.createDiv();
-        Element hTableWrapper = DOM.createDiv();
-        Element hTableContainer = DOM.createDiv();
-        Element table = DOM.createTable();
-        Element headerTableBody = DOM.createTBody();
-        Element tr = DOM.createTR();
-
-        private final Element columnSelector = DOM.createDiv();
-
-        private int focusedSlot = -1;
-
-        public TableHead() {
-            if (BrowserInfo.get().isIE()) {
-                table.setPropertyInt("cellSpacing", 0);
-            }
-
-            DOM.setStyleAttribute(hTableWrapper, "overflow", "hidden");
-            DOM.setElementProperty(hTableWrapper, "className", CLASSNAME
-                    + "-header");
-
-            // TODO move styles to CSS
-            DOM.setElementProperty(columnSelector, "className", CLASSNAME
-                    + "-column-selector");
-            DOM.setStyleAttribute(columnSelector, "display", "none");
-
-            DOM.appendChild(table, headerTableBody);
-            DOM.appendChild(headerTableBody, tr);
-            DOM.appendChild(hTableContainer, table);
-            DOM.appendChild(hTableWrapper, hTableContainer);
-            DOM.appendChild(div, hTableWrapper);
-            DOM.appendChild(div, columnSelector);
-            setElement(div);
-
-            setStyleName(CLASSNAME + "-header-wrap");
-
-            DOM.sinkEvents(columnSelector, Event.ONCLICK);
-
-            availableCells.put("0", new RowHeadersHeaderCell());
-        }
-
-        @Override
-        public void clear() {
-            for (String cid : availableCells.keySet()) {
-                removeCell(cid);
-            }
-            availableCells.clear();
-            availableCells.put("0", new RowHeadersHeaderCell());
-        }
-
-        public void updateCellsFromUIDL(UIDL uidl) {
-            Iterator<?> it = uidl.getChildIterator();
-            HashSet<String> updated = new HashSet<String>();
-            updated.add("0");
-            while (it.hasNext()) {
-                final UIDL col = (UIDL) it.next();
-                final String cid = col.getStringAttribute("cid");
-                updated.add(cid);
-
-                String caption = buildCaptionHtmlSnippet(col);
-                HeaderCell c = getHeaderCell(cid);
-                if (c == null) {
-                    c = new HeaderCell(cid, caption);
-                    availableCells.put(cid, c);
-                    if (initializedAndAttached) {
-                        // we will need a column width recalculation
-                        initializedAndAttached = false;
-                        initialContentReceived = false;
-                        isNewBody = true;
-                    }
-                } else {
-                    c.setText(caption);
-                }
-
-                if (col.hasAttribute("sortable")) {
-                    c.setSortable(true);
-                    if (cid.equals(sortColumn)) {
-                        c.setSorted(true);
-                    } else {
-                        c.setSorted(false);
-                    }
-                } else {
-                    c.setSortable(false);
-                }
-
-                if (col.hasAttribute("align")) {
-                    c.setAlign(col.getStringAttribute("align").charAt(0));
-                }
-                if (col.hasAttribute("width")) {
-                    final String width = col.getStringAttribute("width");
-                    c.setWidth(Integer.parseInt(width), true);
-                } else if (recalcWidths) {
-                    c.setUndefinedWidth();
-                }
-                if (col.hasAttribute("er")) {
-                    c.setExpandRatio(col.getFloatAttribute("er"));
-                }
-            }
-            // check for orphaned header cells
-            for (String cid : availableCells.keySet()) {
-                if (!updated.contains(cid)) {
-                    removeCell(cid);
-                    it.remove();
-                }
-            }
-
-        }
-
-        public void enableColumn(String cid, int index) {
-            final HeaderCell c = getHeaderCell(cid);
-            if (!c.isEnabled() || getHeaderCell(index) != c) {
-                setHeaderCell(index, c);
-                if (initializedAndAttached) {
-                    headerChangedDuringUpdate = true;
-                }
-            }
-        }
-
-        public int getVisibleCellCount() {
-            return visibleCells.size();
-        }
-
-        public void setHorizontalScrollPosition(int scrollLeft) {
-            DOM.setElementPropertyInt(hTableWrapper, "scrollLeft", scrollLeft);
-        }
-
-        public void setColumnCollapsingAllowed(boolean cc) {
-            if (cc) {
-                DOM.setStyleAttribute(columnSelector, "display", "block");
-            } else {
-                DOM.setStyleAttribute(columnSelector, "display", "none");
-            }
-        }
-
-        public void disableBrowserIntelligence() {
-            DOM.setStyleAttribute(hTableContainer, "width", WRAPPER_WIDTH
-                    + "px");
-        }
-
-        public void enableBrowserIntelligence() {
-            DOM.setStyleAttribute(hTableContainer, "width", "");
-        }
-
-        public void setHeaderCell(int index, HeaderCell cell) {
-            if (cell.isEnabled()) {
-                // we're moving the cell
-                DOM.removeChild(tr, cell.getElement());
-                orphan(cell);
-            }
-            if (index < visibleCells.size()) {
-                // insert to right slot
-                DOM.insertChild(tr, cell.getElement(), index);
-                adopt(cell);
-                visibleCells.insertElementAt(cell, index);
-
-            } else if (index == visibleCells.size()) {
-                // simply append
-                DOM.appendChild(tr, cell.getElement());
-                adopt(cell);
-                visibleCells.add(cell);
-            } else {
-                throw new RuntimeException(
-                        "Header cells must be appended in order");
-            }
-        }
-
-        public HeaderCell getHeaderCell(int index) {
-            if (index < visibleCells.size()) {
-                return (HeaderCell) visibleCells.get(index);
-            } else {
-                return null;
-            }
-        }
-
-        /**
-         * Get's HeaderCell by it's column Key.
-         * 
-         * Note that this returns HeaderCell even if it is currently collapsed.
-         * 
-         * @param cid
-         *            Column key of accessed HeaderCell
-         * @return HeaderCell
-         */
-        public HeaderCell getHeaderCell(String cid) {
-            return availableCells.get(cid);
-        }
-
-        public void moveCell(int oldIndex, int newIndex) {
-            final HeaderCell hCell = getHeaderCell(oldIndex);
-            final Element cell = hCell.getElement();
-
-            visibleCells.remove(oldIndex);
-            DOM.removeChild(tr, cell);
-
-            DOM.insertChild(tr, cell, newIndex);
-            visibleCells.insertElementAt(hCell, newIndex);
-        }
-
-        public Iterator<Widget> iterator() {
-            return visibleCells.iterator();
-        }
-
-        @Override
-        public boolean remove(Widget w) {
-            if (visibleCells.contains(w)) {
-                visibleCells.remove(w);
-                orphan(w);
-                DOM.removeChild(DOM.getParent(w.getElement()), w.getElement());
-                return true;
-            }
-            return false;
-        }
-
-        public void removeCell(String colKey) {
-            final HeaderCell c = getHeaderCell(colKey);
-            remove(c);
-        }
-
-        private void focusSlot(int index) {
-            removeSlotFocus();
-            if (index > 0) {
-                DOM.setElementProperty(DOM.getFirstChild(DOM.getChild(tr,
-                        index - 1)), "className", CLASSNAME + "-resizer "
-                        + CLASSNAME + "-focus-slot-right");
-            } else {
-                DOM.setElementProperty(DOM.getFirstChild(DOM
-                        .getChild(tr, index)), "className", CLASSNAME
-                        + "-resizer " + CLASSNAME + "-focus-slot-left");
-            }
-            focusedSlot = index;
-        }
-
-        private void removeSlotFocus() {
-            if (focusedSlot < 0) {
-                return;
-            }
-            if (focusedSlot == 0) {
-                DOM.setElementProperty(DOM.getFirstChild(DOM.getChild(tr,
-                        focusedSlot)), "className", CLASSNAME + "-resizer");
-            } else if (focusedSlot > 0) {
-                DOM.setElementProperty(DOM.getFirstChild(DOM.getChild(tr,
-                        focusedSlot - 1)), "className", CLASSNAME + "-resizer");
-            }
-            focusedSlot = -1;
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            if (enabled) {
-                if (event.getTarget() == columnSelector) {
-                    final int left = DOM.getAbsoluteLeft(columnSelector);
-                    final int top = DOM.getAbsoluteTop(columnSelector)
-                            + DOM.getElementPropertyInt(columnSelector,
-                                    "offsetHeight");
-                    client.getContextMenu().showAt(this, left, top);
-                }
-            }
-        }
-
-        class VisibleColumnAction extends Action {
-
-            String colKey;
-            private boolean collapsed;
-
-            public VisibleColumnAction(String colKey) {
-                super(IScrollTable.TableHead.this);
-                this.colKey = colKey;
-                caption = tHead.getHeaderCell(colKey).getCaption();
-            }
-
-            @Override
-            public void execute() {
-                client.getContextMenu().hide();
-                // toggle selected column
-                if (collapsedColumns.contains(colKey)) {
-                    collapsedColumns.remove(colKey);
-                } else {
-                    tHead.removeCell(colKey);
-                    collapsedColumns.add(colKey);
-                    lazyAdjustColumnWidths.schedule(1);
-                }
-
-                // update variable to server
-                client.updateVariable(paintableId, "collapsedcolumns",
-                        collapsedColumns.toArray(), false);
-                // let rowRequestHandler determine proper rows
-                rowRequestHandler.refreshContent();
-            }
-
-            public void setCollapsed(boolean b) {
-                collapsed = b;
-            }
-
-            /**
-             * Override default method to distinguish on/off columns
-             */
-            @Override
-            public String getHTML() {
-                final StringBuffer buf = new StringBuffer();
-                if (collapsed) {
-                    buf.append("<span class=\"i-off\">");
-                } else {
-                    buf.append("<span class=\"i-on\">");
-                }
-                buf.append(super.getHTML());
-                buf.append("</span>");
-
-                return buf.toString();
-            }
-
-        }
-
-        /*
-         * Returns columns as Action array for column select popup
-         */
-        public Action[] getActions() {
-            Object[] cols;
-            if (columnReordering) {
-                cols = columnOrder;
-            } else {
-                // if columnReordering is disabled, we need different way to get
-                // all available columns
-                cols = visibleColOrder;
-                cols = new Object[visibleColOrder.length
-                        + collapsedColumns.size()];
-                int i;
-                for (i = 0; i < visibleColOrder.length; i++) {
-                    cols[i] = visibleColOrder[i];
-                }
-                for (final Iterator<String> it = collapsedColumns.iterator(); it
-                        .hasNext();) {
-                    cols[i++] = it.next();
-                }
-            }
-            final Action[] actions = new Action[cols.length];
-
-            for (int i = 0; i < cols.length; i++) {
-                final String cid = (String) cols[i];
-                final HeaderCell c = getHeaderCell(cid);
-                final VisibleColumnAction a = new VisibleColumnAction(c
-                        .getColKey());
-                a.setCaption(c.getCaption());
-                if (!c.isEnabled()) {
-                    a.setCollapsed(true);
-                }
-                actions[i] = a;
-            }
-            return actions;
-        }
-
-        public ApplicationConnection getClient() {
-            return client;
-        }
-
-        public String getPaintableId() {
-            return paintableId;
-        }
-
-        /**
-         * Returns column alignments for visible columns
-         */
-        public char[] getColumnAlignments() {
-            final Iterator<Widget> it = visibleCells.iterator();
-            final char[] aligns = new char[visibleCells.size()];
-            int colIndex = 0;
-            while (it.hasNext()) {
-                aligns[colIndex++] = ((HeaderCell) it.next()).getAlign();
-            }
-            return aligns;
-        }
-
-    }
-
-    /**
-     * This Panel can only contain IScrollTableRow type of widgets. This
-     * "simulates" very large table, keeping spacers which take room of
-     * unrendered rows.
-     * 
-     */
-    public class IScrollTableBody extends Panel {
-
-        public static final int DEFAULT_ROW_HEIGHT = 24;
-
-        private int rowHeight = -1;
-
-        private final List<Widget> renderedRows = new Vector<Widget>();
-
-        /**
-         * Due some optimizations row height measuring is deferred and initial
-         * set of rows is rendered detached. Flag set on when table body has
-         * been attached in dom and rowheight has been measured.
-         */
-        private boolean tBodyMeasurementsDone = false;
-
-        Element preSpacer = DOM.createDiv();
-        Element postSpacer = DOM.createDiv();
-
-        Element container = DOM.createDiv();
-
-        TableSectionElement tBodyElement = Document.get().createTBodyElement();
-        Element table = DOM.createTable();
-
-        private int firstRendered;
-
-        private int lastRendered;
-
-        private char[] aligns;
-
-        IScrollTableBody() {
-            constructDOM();
-
-            setElement(container);
-        }
-
-        private void constructDOM() {
-            DOM.setElementProperty(table, "className", CLASSNAME + "-table");
-            if (BrowserInfo.get().isIE()) {
-                table.setPropertyInt("cellSpacing", 0);
-            }
-            DOM.setElementProperty(preSpacer, "className", CLASSNAME
-                    + "-row-spacer");
-            DOM.setElementProperty(postSpacer, "className", CLASSNAME
-                    + "-row-spacer");
-
-            table.appendChild(tBodyElement);
-            DOM.appendChild(container, preSpacer);
-            DOM.appendChild(container, table);
-            DOM.appendChild(container, postSpacer);
-
-        }
-
-        public int getAvailableWidth() {
-            int availW = bodyContainer.getOffsetWidth() - getBorderWidth();
-            return availW;
-        }
-
-        public void renderInitialRows(UIDL rowData, int firstIndex, int rows) {
-            firstRendered = firstIndex;
-            lastRendered = firstIndex + rows - 1;
-            final Iterator<?> it = rowData.getChildIterator();
-            aligns = tHead.getColumnAlignments();
-            while (it.hasNext()) {
-                final IScrollTableRow row = new IScrollTableRow((UIDL) it
-                        .next(), aligns);
-                addRow(row);
-            }
-            if (isAttached()) {
-                fixSpacers();
-            }
-        }
-
-        public void renderRows(UIDL rowData, int firstIndex, int rows) {
-            // FIXME REVIEW
-            aligns = tHead.getColumnAlignments();
-            final Iterator<?> it = rowData.getChildIterator();
-            if (firstIndex == lastRendered + 1) {
-                while (it.hasNext()) {
-                    final IScrollTableRow row = createRow((UIDL) it.next());
-                    addRow(row);
-                    lastRendered++;
-                }
-                fixSpacers();
-            } else if (firstIndex + rows == firstRendered) {
-                final IScrollTableRow[] rowArray = new IScrollTableRow[rows];
-                int i = rows;
-                while (it.hasNext()) {
-                    i--;
-                    rowArray[i] = createRow((UIDL) it.next());
-                }
-                for (i = 0; i < rows; i++) {
-                    addRowBeforeFirstRendered(rowArray[i]);
-                    firstRendered--;
-                }
-            } else {
-                // completely new set of rows
-                while (lastRendered + 1 > firstRendered) {
-                    unlinkRow(false);
-                }
-                final IScrollTableRow row = createRow((UIDL) it.next());
-                firstRendered = firstIndex;
-                lastRendered = firstIndex - 1;
-                addRow(row);
-                lastRendered++;
-                setContainerHeight();
-                fixSpacers();
-                while (it.hasNext()) {
-                    addRow(createRow((UIDL) it.next()));
-                    lastRendered++;
-                }
-                fixSpacers();
-            }
-            // this may be a new set of rows due content change,
-            // ensure we have proper cache rows
-            int reactFirstRow = (int) (firstRowInViewPort - pageLength
-                    * CACHE_REACT_RATE);
-            int reactLastRow = (int) (firstRowInViewPort + pageLength + pageLength
-                    * CACHE_REACT_RATE);
-            if (reactFirstRow < 0) {
-                reactFirstRow = 0;
-            }
-            if (reactLastRow > totalRows) {
-                reactLastRow = totalRows - 1;
-            }
-            if (lastRendered < reactLastRow) {
-                // get some cache rows below visible area
-                rowRequestHandler.setReqFirstRow(lastRendered + 1);
-                rowRequestHandler.setReqRows(reactLastRow - lastRendered - 1);
-                rowRequestHandler.deferRowFetch(1);
-            } else if (tBody.getFirstRendered() > reactFirstRow) {
-                /*
-                 * Branch for fetching cache above visible area.
-                 * 
-                 * If cache needed for both before and after visible area, this
-                 * will be rendered after-cache is reveived and rendered. So in
-                 * some rare situations table may take two cache visits to
-                 * server.
-                 */
-                rowRequestHandler.setReqFirstRow(reactFirstRow);
-                rowRequestHandler.setReqRows(firstRendered - reactFirstRow);
-                rowRequestHandler.deferRowFetch(1);
-            }
-        }
-
-        /**
-         * This method is used to instantiate new rows for this table. It
-         * automatically sets correct widths to rows cells and assigns correct
-         * client reference for child widgets.
-         * 
-         * This method can be called only after table has been initialized
-         * 
-         * @param uidl
-         */
-        private IScrollTableRow createRow(UIDL uidl) {
-            final IScrollTableRow row = new IScrollTableRow(uidl, aligns);
-            final int cells = DOM.getChildCount(row.getElement());
-            for (int i = 0; i < cells; i++) {
-                final Element cell = DOM.getChild(row.getElement(), i);
-                int w = IScrollTable.this.getColWidth(getColKeyByIndex(i));
-                if (w < 0) {
-                    w = 0;
-                }
-                cell.getFirstChildElement().getStyle()
-                        .setPropertyPx("width", w);
-                cell.getStyle().setPropertyPx("width", w);
-            }
-            return row;
-        }
-
-        private void addRowBeforeFirstRendered(IScrollTableRow row) {
-            IScrollTableRow first = null;
-            if (renderedRows.size() > 0) {
-                first = (IScrollTableRow) renderedRows.get(0);
-            }
-            if (first != null && first.getStyleName().indexOf("-odd") == -1) {
-                row.addStyleName(CLASSNAME + "-row-odd");
-            } else {
-                row.addStyleName(CLASSNAME + "-row");
-            }
-            if (row.isSelected()) {
-                row.addStyleName("i-selected");
-            }
-            tBodyElement.insertBefore(row.getElement(), tBodyElement
-                    .getFirstChild());
-            adopt(row);
-            renderedRows.add(0, row);
-        }
-
-        private void addRow(IScrollTableRow row) {
-            IScrollTableRow last = null;
-            if (renderedRows.size() > 0) {
-                last = (IScrollTableRow) renderedRows
-                        .get(renderedRows.size() - 1);
-            }
-            if (last != null && last.getStyleName().indexOf("-odd") == -1) {
-                row.addStyleName(CLASSNAME + "-row-odd");
-            } else {
-                row.addStyleName(CLASSNAME + "-row");
-            }
-            if (row.isSelected()) {
-                row.addStyleName("i-selected");
-            }
-            tBodyElement.appendChild(row.getElement());
-            adopt(row);
-            renderedRows.add(row);
-        }
-
-        public Iterator<Widget> iterator() {
-            return renderedRows.iterator();
-        }
-
-        /**
-         * @return false if couldn't remove row
-         */
-        public boolean unlinkRow(boolean fromBeginning) {
-            if (lastRendered - firstRendered < 0) {
-                return false;
-            }
-            int index;
-            if (fromBeginning) {
-                index = 0;
-                firstRendered++;
-            } else {
-                index = renderedRows.size() - 1;
-                lastRendered--;
-            }
-            if (index >= 0) {
-                final IScrollTableRow toBeRemoved = (IScrollTableRow) renderedRows
-                        .get(index);
-                lazyUnregistryBag.add(toBeRemoved);
-                tBodyElement.removeChild(toBeRemoved.getElement());
-                orphan(toBeRemoved);
-                renderedRows.remove(index);
-                fixSpacers();
-                return true;
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public boolean remove(Widget w) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        protected void onAttach() {
-            super.onAttach();
-            setContainerHeight();
-        }
-
-        /**
-         * Fix container blocks height according to totalRows to avoid
-         * "bouncing" when scrolling
-         */
-        private void setContainerHeight() {
-            fixSpacers();
-            DOM.setStyleAttribute(container, "height", totalRows
-                    * getRowHeight() + "px");
-        }
-
-        private void fixSpacers() {
-            int prepx = getRowHeight() * firstRendered;
-            if (prepx < 0) {
-                prepx = 0;
-            }
-            DOM.setStyleAttribute(preSpacer, "height", prepx + "px");
-            int postpx = getRowHeight() * (totalRows - 1 - lastRendered);
-            if (postpx < 0) {
-                postpx = 0;
-            }
-            DOM.setStyleAttribute(postSpacer, "height", postpx + "px");
-        }
-
-        public int getRowHeight() {
-            return getRowHeight(false);
-        }
-
-        public int getRowHeight(boolean forceUpdate) {
-            if (tBodyMeasurementsDone && !forceUpdate) {
-                return rowHeight;
-            } else {
-
-                if (tBodyElement.getRows().getLength() > 0) {
-                    rowHeight = getTableHeight()
-                            / tBodyElement.getRows().getLength();
-                } else {
-                    if (isAttached()) {
-                        // measure row height by adding a dummy row
-                        IScrollTableRow scrollTableRow = new IScrollTableRow();
-                        tBodyElement.appendChild(scrollTableRow.getElement());
-                        getRowHeight(forceUpdate);
-                        tBodyElement.removeChild(scrollTableRow.getElement());
-                    } else {
-                        // TODO investigate if this can never happen anymore
-                        return DEFAULT_ROW_HEIGHT;
-                    }
-                }
-                tBodyMeasurementsDone = true;
-                return rowHeight;
-            }
-        }
-
-        public int getTableHeight() {
-            return table.getOffsetHeight();
-        }
-
-        /**
-         * Returns the width available for column content.
-         * 
-         * @param columnIndex
-         * @return
-         */
-        public int getColWidth(int columnIndex) {
-            if (tBodyMeasurementsDone) {
-                NodeList<TableRowElement> rows = tBodyElement.getRows();
-                if (rows.getLength() == 0) {
-                    // no rows yet rendered
-                    return 0;
-                } else {
-                    com.google.gwt.dom.client.Element wrapperdiv = rows
-                            .getItem(0).getCells().getItem(columnIndex)
-                            .getFirstChildElement();
-                    return wrapperdiv.getOffsetWidth();
-                }
-            } else {
-                return 0;
-            }
-        }
-
-        /**
-         * Sets the content width of a column.
-         * 
-         * Due IE limitation, we must set the width to a wrapper elements inside
-         * table cells (with overflow hidden, which does not work on td
-         * elements).
-         * 
-         * To get this work properly crossplatform, we will also set the width
-         * of td.
-         * 
-         * @param colIndex
-         * @param w
-         */
-        public void setColWidth(int colIndex, int w) {
-            NodeList<TableRowElement> rows2 = tBodyElement.getRows();
-            final int rows = rows2.getLength();
-            for (int i = 0; i < rows; i++) {
-                TableRowElement row = rows2.getItem(i);
-                TableCellElement cell = row.getCells().getItem(colIndex);
-                cell.getFirstChildElement().getStyle()
-                        .setPropertyPx("width", w);
-                cell.getStyle().setPropertyPx("width", w);
-            }
-        }
-
-        private int cellExtraWidth = -1;
-
-        /**
-         * Method to return the space used for cell paddings + border.
-         */
-        private int getCellExtraWidth() {
-            if (cellExtraWidth < 0) {
-                detectExtrawidth();
-            }
-            return cellExtraWidth;
-        }
-
-        private void detectExtrawidth() {
-            NodeList<TableRowElement> rows = tBodyElement.getRows();
-            if (rows.getLength() == 0) {
-                /* need to temporary add empty row and detect */
-                IScrollTableRow scrollTableRow = new IScrollTableRow();
-                tBodyElement.appendChild(scrollTableRow.getElement());
-                detectExtrawidth();
-                tBodyElement.removeChild(scrollTableRow.getElement());
-            } else {
-                TableRowElement item = rows.getItem(0);
-                TableCellElement firstTD = item.getCells().getItem(0);
-                com.google.gwt.dom.client.Element wrapper = firstTD
-                        .getFirstChildElement();
-                cellExtraWidth = firstTD.getOffsetWidth()
-                        - wrapper.getOffsetWidth();
-            }
-        }
-
-        private void reLayoutComponents() {
-            for (Widget w : this) {
-                IScrollTableRow r = (IScrollTableRow) w;
-                for (Widget widget : r) {
-                    client.handleComponentRelativeSize(widget);
-                }
-            }
-        }
-
-        public int getLastRendered() {
-            return lastRendered;
-        }
-
-        public int getFirstRendered() {
-            return firstRendered;
-        }
-
-        public void moveCol(int oldIndex, int newIndex) {
-
-            // loop all rows and move given index to its new place
-            final Iterator<?> rows = iterator();
-            while (rows.hasNext()) {
-                final IScrollTableRow row = (IScrollTableRow) rows.next();
-
-                final Element td = DOM.getChild(row.getElement(), oldIndex);
-                DOM.removeChild(row.getElement(), td);
-
-                DOM.insertChild(row.getElement(), td, newIndex);
-
-            }
-
-        }
-
-        public class IScrollTableRow extends Panel implements ActionOwner,
-                Container {
-
-            Vector<Widget> childWidgets = new Vector<Widget>();
-            private boolean selected = false;
-            private final int rowKey;
-            private List<UIDL> pendingComponentPaints;
-
-            private String[] actionKeys = null;
-            private TableRowElement rowElement;
-
-            private IScrollTableRow(int rowKey) {
-                this.rowKey = rowKey;
-                rowElement = Document.get().createTRElement();
-                setElement(rowElement);
-                DOM.sinkEvents(getElement(), Event.ONCLICK | Event.ONDBLCLICK
-                        | Event.ONCONTEXTMENU);
-            }
-
-            private void paintComponent(Paintable p, UIDL uidl) {
-                if (isAttached()) {
-                    p.updateFromUIDL(uidl, client);
-                } else {
-                    if (pendingComponentPaints == null) {
-                        pendingComponentPaints = new LinkedList<UIDL>();
-                    }
-                    pendingComponentPaints.add(uidl);
-                }
-            }
-
-            @Override
-            protected void onAttach() {
-                super.onAttach();
-                if (pendingComponentPaints != null) {
-                    for (UIDL uidl : pendingComponentPaints) {
-                        Paintable paintable = client.getPaintable(uidl);
-                        paintable.updateFromUIDL(uidl, client);
-                    }
-                }
-            }
-
-            public String getKey() {
-                return String.valueOf(rowKey);
-            }
-
-            public IScrollTableRow(UIDL uidl, char[] aligns) {
-                this(uidl.getIntAttribute("key"));
-
-                String rowStyle = uidl.getStringAttribute("rowstyle");
-                if (rowStyle != null) {
-                    addStyleName(CLASSNAME + "-row-" + rowStyle);
-                }
-
-                tHead.getColumnAlignments();
-                int col = 0;
-                int visibleColumnIndex = -1;
-
-                // row header
-                if (showRowHeaders) {
-                    addCell(buildCaptionHtmlSnippet(uidl), aligns[col++], "",
-                            true);
-                }
-
-                if (uidl.hasAttribute("al")) {
-                    actionKeys = uidl.getStringArrayAttribute("al");
-                }
-
-                final Iterator<?> cells = uidl.getChildIterator();
-                while (cells.hasNext()) {
-                    final Object cell = cells.next();
-                    visibleColumnIndex++;
-
-                    String columnId = visibleColOrder[visibleColumnIndex];
-
-                    String style = "";
-                    if (uidl.hasAttribute("style-" + columnId)) {
-                        style = uidl.getStringAttribute("style-" + columnId);
-                    }
-
-                    if (cell instanceof String) {
-                        addCell(cell.toString(), aligns[col++], style, false);
-                    } else {
-                        final Paintable cellContent = client
-                                .getPaintable((UIDL) cell);
-
-                        addCell((Widget) cellContent, aligns[col++], style);
-                        paintComponent(cellContent, (UIDL) cell);
-                    }
-                }
-                if (uidl.hasAttribute("selected") && !isSelected()) {
-                    toggleSelection();
-                }
-            }
-
-            /**
-             * Add a dummy row, used for measurements if Table is empty.
-             */
-            public IScrollTableRow() {
-                this(0);
-                addStyleName(CLASSNAME + "-row");
-                addCell("_", 'b', "", true);
-            }
-
-            public void addCell(String text, char align, String style,
-                    boolean textIsHTML) {
-                // String only content is optimized by not using Label widget
-                final Element td = DOM.createTD();
-                final Element container = DOM.createDiv();
-                String className = CLASSNAME + "-cell-content";
-                if (style != null && !style.equals("")) {
-                    className += " " + CLASSNAME + "-cell-content-" + style;
-                }
-                td.setClassName(className);
-                container.setClassName(CLASSNAME + "-cell-wrapper");
-                if (textIsHTML) {
-                    container.setInnerHTML(text);
-                } else {
-                    container.setInnerText(text);
-                }
-                if (align != ALIGN_LEFT) {
-                    switch (align) {
-                    case ALIGN_CENTER:
-                        container.getStyle().setProperty("textAlign", "center");
-                        break;
-                    case ALIGN_RIGHT:
-                    default:
-                        container.getStyle().setProperty("textAlign", "right");
-                        break;
-                    }
-                }
-                td.appendChild(container);
-                getElement().appendChild(td);
-            }
-
-            public void addCell(Widget w, char align, String style) {
-                final Element td = DOM.createTD();
-                final Element container = DOM.createDiv();
-                String className = CLASSNAME + "-cell-content";
-                if (style != null && !style.equals("")) {
-                    className += " " + CLASSNAME + "-cell-content-" + style;
-                }
-                td.setClassName(className);
-                container.setClassName(CLASSNAME + "-cell-wrapper");
-                // TODO most components work with this, but not all (e.g.
-                // Select)
-                // Old comment: make widget cells respect align.
-                // text-align:center for IE, margin: auto for others
-                if (align != ALIGN_LEFT) {
-                    switch (align) {
-                    case ALIGN_CENTER:
-                        container.getStyle().setProperty("textAlign", "center");
-                        break;
-                    case ALIGN_RIGHT:
-                    default:
-                        container.getStyle().setProperty("textAlign", "right");
-                        break;
-                    }
-                }
-                td.appendChild(container);
-                getElement().appendChild(td);
-                // ensure widget not attached to another element (possible tBody
-                // change)
-                w.removeFromParent();
-                container.appendChild(w.getElement());
-                adopt(w);
-                childWidgets.add(w);
-            }
-
-            public Iterator<Widget> iterator() {
-                return childWidgets.iterator();
-            }
-
-            @Override
-            public boolean remove(Widget w) {
-                if (childWidgets.contains(w)) {
-                    orphan(w);
-                    DOM.removeChild(DOM.getParent(w.getElement()), w
-                            .getElement());
-                    childWidgets.remove(w);
-                    return true;
-                } else {
-                    return false;
-                }
-            }
-
-            private void handleClickEvent(Event event, Element targetTdOrTr) {
-                if (emitClickEvents) {
-                    boolean doubleClick = (DOM.eventGetType(event) == Event.ONDBLCLICK);
-
-                    /* This row was clicked */
-                    client.updateVariable(paintableId, "clickedKey", ""
-                            + rowKey, false);
-
-                    if (getElement() == targetTdOrTr.getParentElement()) {
-                        /* A specific column was clicked */
-                        int childIndex = DOM.getChildIndex(getElement(),
-                                targetTdOrTr);
-                        String colKey = null;
-                        colKey = tHead.getHeaderCell(childIndex).getColKey();
-                        client.updateVariable(paintableId, "clickedColKey",
-                                colKey, false);
-                    }
-
-                    MouseEventDetails details = new MouseEventDetails(event);
-                    // Note: the 'immediate' logic would need to be more
-                    // involved (see #2104), but iscrolltable always sends
-                    // select event, even though nullselectionallowed wont let
-                    // the change trough. Will need to be updated if that is
-                    // changed.
-                    client
-                            .updateVariable(
-                                    paintableId,
-                                    "clickEvent",
-                                    details.toString(),
-                                    !(!doubleClick
-                                            && selectMode > Table.SELECT_MODE_NONE && immediate));
-                }
-            }
-
-            /*
-             * React on click that occur on content cells only
-             */
-            @Override
-            public void onBrowserEvent(Event event) {
-                if (enabled) {
-                    Element targetTdOrTr = getEventTargetTdOrTr(event);
-                    if (targetTdOrTr != null) {
-                        switch (DOM.eventGetType(event)) {
-                        case Event.ONCLICK:
-                            handleClickEvent(event, targetTdOrTr);
-                            if (selectMode > Table.SELECT_MODE_NONE) {
-                                toggleSelection();
-                                // Note: changing the immediateness of this
-                                // might
-                                // require changes to "clickEvent" immediateness
-                                // also.
-                                client.updateVariable(paintableId, "selected",
-                                        selectedRowKeys.toArray(), immediate);
-                            }
-                            break;
-                        case Event.ONDBLCLICK:
-                            handleClickEvent(event, targetTdOrTr);
-                            break;
-                        case Event.ONCONTEXTMENU:
-                            showContextMenu(event);
-                            break;
-                        default:
-                            break;
-                        }
-                    }
-                }
-                super.onBrowserEvent(event);
-            }
-
-            /**
-             * Finds the TD that the event interacts with. Returns null if the
-             * target of the event should not be handled. If the event target is
-             * the row directly this method returns the TR element instead of
-             * the TD.
-             * 
-             * @param event
-             * @return TD or TR element that the event targets (the actual event
-             *         target is this element or a child of it)
-             */
-            private Element getEventTargetTdOrTr(Event event) {
-                Element targetTdOrTr = null;
-
-                final Element eventTarget = DOM.eventGetTarget(event);
-                final Element eventTargetParent = DOM.getParent(eventTarget);
-                final Element eventTargetGrandParent = DOM
-                        .getParent(eventTargetParent);
-
-                final Element thisTrElement = getElement();
-
-                if (eventTarget == thisTrElement) {
-                    // This was a click on the TR element
-                    targetTdOrTr = eventTarget;
-                    // rowTarget = true;
-                } else if (thisTrElement == eventTargetParent) {
-                    // Target parent is the TR, so the actual target is the TD
-                    targetTdOrTr = eventTarget;
-                } else if (thisTrElement == eventTargetGrandParent) {
-                    // Target grand parent is the TR, so the parent is the TD
-                    targetTdOrTr = eventTargetParent;
-                } else {
-                    /*
-                     * This is a workaround to make Labels and Embedded in a
-                     * Table clickable (see #2688). It is really not a fix as it
-                     * does not work for a custom component (not extending
-                     * ILabel/IEmbedded) or for read only textfields etc.
-                     */
-                    Element tdElement = eventTargetParent;
-                    while (DOM.getParent(tdElement) != thisTrElement) {
-                        tdElement = DOM.getParent(tdElement);
-                    }
-
-                    Element componentElement = tdElement.getFirstChildElement()
-                            .getFirstChildElement().cast();
-                    Widget widget = (Widget) client
-                            .getPaintable(componentElement);
-                    if (widget instanceof ILabel || widget instanceof IEmbedded) {
-                        targetTdOrTr = tdElement;
-                    }
-                }
-
-                return targetTdOrTr;
-            }
-
-            public void showContextMenu(Event event) {
-                if (enabled && actionKeys != null) {
-                    int left = event.getClientX();
-                    int top = event.getClientY();
-                    top += Window.getScrollTop();
-                    left += Window.getScrollLeft();
-                    client.getContextMenu().showAt(this, left, top);
-                }
-                event.cancelBubble(true);
-                event.preventDefault();
-            }
-
-            public boolean isSelected() {
-                return selected;
-            }
-
-            private void toggleSelection() {
-                selected = !selected;
-                if (selected) {
-                    if (selectMode == Table.SELECT_MODE_SINGLE) {
-                        deselectAll();
-                    }
-                    selectedRowKeys.add(String.valueOf(rowKey));
-                    addStyleName("i-selected");
-                } else {
-                    selectedRowKeys.remove(String.valueOf(rowKey));
-                    removeStyleName("i-selected");
-                }
-            }
-
-            /*
-             * (non-Javadoc)
-             * 
-             * @see
-             * com.vaadin.terminal.gwt.client.ui.IActionOwner#getActions
-             * ()
-             */
-            public Action[] getActions() {
-                if (actionKeys == null) {
-                    return new Action[] {};
-                }
-                final Action[] actions = new Action[actionKeys.length];
-                for (int i = 0; i < actions.length; i++) {
-                    final String actionKey = actionKeys[i];
-                    final TreeAction a = new TreeAction(this, String
-                            .valueOf(rowKey), actionKey);
-                    a.setCaption(getActionCaption(actionKey));
-                    a.setIconUrl(getActionIcon(actionKey));
-                    actions[i] = a;
-                }
-                return actions;
-            }
-
-            public ApplicationConnection getClient() {
-                return client;
-            }
-
-            public String getPaintableId() {
-                return paintableId;
-            }
-
-            public RenderSpace getAllocatedSpace(Widget child) {
-                int w = 0;
-                int i = getColIndexOf(child);
-                HeaderCell headerCell = tHead.getHeaderCell(i);
-                if (headerCell != null) {
-                    if (initializedAndAttached) {
-                        w = headerCell.getWidth();
-                    } else {
-                        // header offset width is not absolutely correct value,
-                        // but a best guess (expecting similar content in all
-                        // columns ->
-                        // if one component is relative width so are others)
-                        w = headerCell.getOffsetWidth() - getCellExtraWidth();
-                    }
-                }
-                return new RenderSpace(w, getRowHeight());
-            }
-
-            private int getColIndexOf(Widget child) {
-                com.google.gwt.dom.client.Element widgetCell = child
-                        .getElement().getParentElement().getParentElement();
-                NodeList<TableCellElement> cells = rowElement.getCells();
-                for (int i = 0; i < cells.getLength(); i++) {
-                    if (cells.getItem(i) == widgetCell) {
-                        return i;
-                    }
-                }
-                return -1;
-            }
-
-            public boolean hasChildComponent(Widget component) {
-                return childWidgets.contains(component);
-            }
-
-            public void replaceChildComponent(Widget oldComponent,
-                    Widget newComponent) {
-                com.google.gwt.dom.client.Element parentElement = oldComponent
-                        .getElement().getParentElement();
-                int index = childWidgets.indexOf(oldComponent);
-                oldComponent.removeFromParent();
-
-                parentElement.appendChild(newComponent.getElement());
-                childWidgets.insertElementAt(newComponent, index);
-                adopt(newComponent);
-
-            }
-
-            public boolean requestLayout(Set<Paintable> children) {
-                // row size should never change and system wouldn't event
-                // survive as this is a kind of fake paitable
-                return true;
-            }
-
-            public void updateCaption(Paintable component, UIDL uidl) {
-                // NOP, not rendered
-            }
-
-            public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-                // Should never be called,
-                // Component container interface faked here to get layouts
-                // render properly
-            }
-        }
-    }
-
-    public void deselectAll() {
-        final Object[] keys = selectedRowKeys.toArray();
-        for (int i = 0; i < keys.length; i++) {
-            final IScrollTableRow row = getRenderedRowByKey((String) keys[i]);
-            if (row != null && row.isSelected()) {
-                row.toggleSelection();
-            }
-        }
-        // still ensure all selects are removed from (not necessary rendered)
-        selectedRowKeys.clear();
-
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        this.width = width;
-        if (width != null && !"".equals(width)) {
-            super.setWidth(width);
-            int innerPixels = getOffsetWidth() - getBorderWidth();
-            if (innerPixels < 0) {
-                innerPixels = 0;
-            }
-            setContentWidth(innerPixels);
-
-            if (!rendering) {
-                // readjust undefined width columns
-                lazyAdjustColumnWidths.cancel();
-                lazyAdjustColumnWidths.schedule(LAZY_COLUMN_ADJUST_TIMEOUT);
-            }
-
-        } else {
-            super.setWidth("");
-        }
-
-    }
-
-    private static final int LAZY_COLUMN_ADJUST_TIMEOUT = 300;
-
-    private final Timer lazyAdjustColumnWidths = new Timer() {
-        /**
-         * Check for column widths, and available width, to see if we can fix
-         * column widths "optimally". Doing this lazily to avoid expensive
-         * calculation when resizing is not yet finished.
-         */
-        @Override
-        public void run() {
-
-            Iterator<Widget> headCells = tHead.iterator();
-            int usedMinimumWidth = 0;
-            int totalExplicitColumnsWidths = 0;
-            float expandRatioDivider = 0;
-            int colIndex = 0;
-            while (headCells.hasNext()) {
-                final HeaderCell hCell = (HeaderCell) headCells.next();
-                if (hCell.isDefinedWidth()) {
-                    totalExplicitColumnsWidths += hCell.getWidth();
-                    usedMinimumWidth += hCell.getWidth();
-                } else {
-                    usedMinimumWidth += hCell.getNaturalColumnWidth(colIndex);
-                    expandRatioDivider += hCell.getExpandRatio();
-                }
-                colIndex++;
-            }
-
-            int availW = tBody.getAvailableWidth();
-            // Hey IE, are you really sure about this?
-            availW = tBody.getAvailableWidth();
-            availW -= tBody.getCellExtraWidth() * visibleColOrder.length;
-            if (willHaveScrollbars()) {
-                availW -= Util.getNativeScrollbarSize();
-            }
-
-            int extraSpace = availW - usedMinimumWidth;
-            if (extraSpace < 0) {
-                extraSpace = 0;
-            }
-
-            int totalUndefinedNaturaWidths = usedMinimumWidth
-                    - totalExplicitColumnsWidths;
-
-            // we have some space that can be divided optimally
-            HeaderCell hCell;
-            colIndex = 0;
-            headCells = tHead.iterator();
-            while (headCells.hasNext()) {
-                hCell = (HeaderCell) headCells.next();
-                if (!hCell.isDefinedWidth()) {
-                    int w = hCell.getNaturalColumnWidth(colIndex);
-                    int newSpace;
-                    if (expandRatioDivider > 0) {
-                        // divide excess space by expand ratios
-                        newSpace = (int) (w + extraSpace
-                                * hCell.getExpandRatio() / expandRatioDivider);
-                    } else {
-                        if (totalUndefinedNaturaWidths != 0) {
-                            // divide relatively to natural column widths
-                            newSpace = w + extraSpace * w
-                                    / totalUndefinedNaturaWidths;
-                        } else {
-                            newSpace = w;
-                        }
-                    }
-                    setColWidth(colIndex, newSpace, false);
-                }
-                colIndex++;
-            }
-            Util.runWebkitOverflowAutoFix(bodyContainer.getElement());
-            tBody.reLayoutComponents();
-        }
-    };
-
-    /**
-     * helper to set pixel size of head and body part
-     * 
-     * @param pixels
-     */
-    private void setContentWidth(int pixels) {
-        tHead.setWidth(pixels + "px");
-        bodyContainer.setWidth(pixels + "px");
-    }
-
-    private int borderWidth = -1;
-
-    /**
-     * @return border left + border right
-     */
-    private int getBorderWidth() {
-        if (borderWidth < 0) {
-            borderWidth = Util.measureHorizontalPaddingAndBorder(bodyContainer
-                    .getElement(), 2);
-            if (borderWidth < 0) {
-                borderWidth = 0;
-            }
-        }
-        return borderWidth;
-    }
-
-    /**
-     * Ensures scrollable area is properly sized.
-     */
-    private void setContainerHeight() {
-        if (height != null && !"".equals(height)) {
-            int contentH = getOffsetHeight() - tHead.getOffsetHeight();
-            contentH -= getContentAreaBorderHeight();
-            if (contentH < 0) {
-                contentH = 0;
-            }
-            bodyContainer.setHeight(contentH + "px");
-        }
-    }
-
-    private int contentAreaBorderHeight = -1;
-
-    /**
-     * @return border top + border bottom of the scrollable area of table
-     */
-    private int getContentAreaBorderHeight() {
-        if (contentAreaBorderHeight < 0) {
-            DOM.setStyleAttribute(bodyContainer.getElement(), "overflow",
-                    "hidden");
-            contentAreaBorderHeight = bodyContainer.getOffsetHeight()
-                    - bodyContainer.getElement().getPropertyInt("clientHeight");
-            DOM.setStyleAttribute(bodyContainer.getElement(), "overflow",
-                    "auto");
-        }
-        return contentAreaBorderHeight;
-    }
-
-    @Override
-    public void setHeight(String height) {
-        this.height = height;
-        super.setHeight(height);
-        setContainerHeight();
-    }
-
-    /*
-     * Overridden due Table might not survive of visibility change (scroll pos
-     * lost). Example ITabPanel just set contained components invisible and back
-     * when changing tabs.
-     */
-    @Override
-    public void setVisible(boolean visible) {
-        if (isVisible() != visible) {
-            super.setVisible(visible);
-            if (initializedAndAttached) {
-                if (visible) {
-                    DeferredCommand.addCommand(new Command() {
-                        public void execute() {
-                            bodyContainer.setScrollPosition(firstRowInViewPort
-                                    * tBody.getRowHeight());
-                        }
-                    });
-                }
-            }
-        }
-    }
-
-    /**
-     * Helper function to build html snippet for column or row headers
-     * 
-     * @param uidl
-     *            possibly with values caption and icon
-     * @return html snippet containing possibly an icon + caption text
-     */
-    private String buildCaptionHtmlSnippet(UIDL uidl) {
-        String s = uidl.getStringAttribute("caption");
-        if (uidl.hasAttribute("icon")) {
-            s = "<img src=\""
-                    + client.translateToolkitUri(uidl
-                            .getStringAttribute("icon"))
-                    + "\" alt=\"icon\" class=\"i-icon\">" + s;
-        }
-        return s;
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ISlider.java b/src/com/vaadin/terminal/gwt/client/ui/ISlider.java
deleted file mode 100644 (file)
index 0cd04f6..0000000
+++ /dev/null
@@ -1,436 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-// \r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import com.google.gwt.user.client.Command;\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.DeferredCommand;\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.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.UIDL;\r
-\r
-public class ISlider extends Widget implements Paintable, Field,\r
-        ContainerResizedListener {\r
-\r
-    public static final String CLASSNAME = "i-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 handleSize;\r
-    private double min;\r
-    private double max;\r
-    private int resolution;\r
-    private Double value;\r
-    private boolean vertical;\r
-    private int size = -1;\r
-    private boolean arrows;\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
-    public ISlider() {\r
-        super();\r
-\r
-        setElement(DOM.createDiv());\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
-        DOM.sinkEvents(getElement(), Event.MOUSEEVENTS | Event.ONMOUSEWHEEL);\r
-        DOM.sinkEvents(base, Event.ONCLICK);\r
-        DOM.sinkEvents(handle, Event.MOUSEEVENTS);\r
-        DOM.sinkEvents(smaller, Event.ONMOUSEDOWN | Event.ONMOUSEUP\r
-                | Event.ONMOUSEOUT);\r
-        DOM.sinkEvents(bigger, Event.ONMOUSEDOWN | Event.ONMOUSEUP\r
-                | Event.ONMOUSEOUT);\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
-        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
-            DeferredCommand.addCommand(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 buildBase() {\r
-        final String styleAttribute = vertical ? "height" : "width";\r
-        final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
-\r
-        if (size == -1) {\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
-                DeferredCommand.addCommand(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
-        } else {\r
-            DOM.setStyleAttribute(base, styleAttribute, size + "px");\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.doubleValue() < min) {\r
-            value = new Double(min);\r
-        } else if (value.doubleValue() > max) {\r
-            value = new Double(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))\r
-                - (2 * BASE_BORDER_WIDTH);\r
-\r
-        final int range = baseSize - handleSize;\r
-        double v = value.doubleValue();\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
-        }\r
-        final double pos = p;\r
-\r
-        DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px");\r
-\r
-        // TODO give more detailed info when dragging and do roundup\r
-        DOM.setElementAttribute(handle, "title", "" + v);\r
-\r
-        // Update value\r
-        this.value = new Double(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 {\r
-            processBaseEvent(event);\r
-        }\r
-    }\r
-\r
-    private Timer scrollTimer;\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
-        if (scrollTimer != null) {\r
-            scrollTimer.cancel();\r
-        }\r
-        scrollTimer = new Timer() {\r
-            @Override\r
-            public void run() {\r
-                updateValueToServer();\r
-            }\r
-        };\r
-        scrollTimer.schedule(100);\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
-            if (!disabled && !readonly) {\r
-                dragging = true;\r
-                DOM.setCapture(getElement());\r
-                DOM.eventPreventDefault(event); // prevent selecting text\r
-                DOM.eventCancelBubble(event, true);\r
-            }\r
-            break;\r
-        case Event.ONMOUSEMOVE:\r
-            if (dragging) {\r
-                // DOM.setCapture(getElement());\r
-                setValueByEvent(event, false);\r
-            }\r
-            break;\r
-        case Event.ONMOUSEUP:\r
-            dragging = false;\r
-            DOM.releaseCapture(getElement());\r
-            setValueByEvent(event, true);\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
-        } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) {\r
-            dragging = false;\r
-            DOM.releaseCapture(getElement());\r
-            setValueByEvent(event, true);\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 = vertical ? DOM.eventGetClientY(event) : DOM\r
-                .eventGetClientX(event);\r
-        final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
-\r
-        final double handleSize = Integer.parseInt(DOM.getElementProperty(\r
-                handle, domProperty));\r
-        final double baseSize = Integer.parseInt(DOM.getElementProperty(base,\r
-                domProperty));\r
-        final double baseOffset = vertical ? DOM.getAbsoluteTop(base)\r
-                - handleSize / 2 : DOM.getAbsoluteLeft(base) + handleSize / 2;\r
-\r
-        if (vertical) {\r
-            v = ((baseSize - (coord - baseOffset)) / (baseSize - handleSize))\r
-                    * (max - min) + min;\r
-        } else {\r
-            v = ((coord - baseOffset) / (baseSize - handleSize)) * (max - min)\r
-                    + min;\r
-        }\r
-\r
-        if (v < min) {\r
-            v = min;\r
-        } else if (v > max) {\r
-            v = max;\r
-        }\r
-\r
-        setValue(new Double(v), updateToServer);\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
-        if (size == -1) {\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
-        } else {\r
-            DOM.setStyleAttribute(base, "height", size + "px");\r
-        }\r
-        DOM.setStyleAttribute(base, "overflow", "");\r
-    }\r
-\r
-    private void updateValueToServer() {\r
-        client.updateVariable(id, "value", value.doubleValue(), immediate);\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ISplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/ISplitPanel.java
deleted file mode 100644 (file)
index 74ca6b5..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Set;
-
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.ContainerResizedListener;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderInformation;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class ISplitPanel extends ComplexPanel implements Container,
-        ContainerResizedListener {
-    public static final String CLASSNAME = "i-splitpanel";
-
-    public static final int ORIENTATION_HORIZONTAL = 0;
-
-    public static final int ORIENTATION_VERTICAL = 1;
-
-    private static final int MIN_SIZE = 30;
-
-    private int orientation = ORIENTATION_HORIZONTAL;
-
-    private Widget firstChild;
-
-    private Widget secondChild;
-
-    private final Element wrapper = DOM.createDiv();
-
-    private final Element firstContainer = DOM.createDiv();
-
-    private final Element secondContainer = DOM.createDiv();
-
-    private final Element splitter = DOM.createDiv();
-
-    private boolean resizing;
-
-    private int origX;
-
-    private int origY;
-
-    private int origMouseX;
-
-    private int origMouseY;
-
-    private boolean locked = false;
-
-    private String[] componentStyleNames;
-
-    private Element draggingCurtain;
-
-    private ApplicationConnection client;
-
-    private String width = "";
-
-    private String height = "";
-
-    private RenderSpace firstRenderSpace = new RenderSpace(0, 0, true);
-    private RenderSpace secondRenderSpace = new RenderSpace(0, 0, true);
-
-    RenderInformation renderInformation = new RenderInformation();
-
-    private String id;
-
-    private boolean immediate;
-
-    private boolean rendering = false;
-
-    public ISplitPanel() {
-        this(ORIENTATION_HORIZONTAL);
-    }
-
-    public ISplitPanel(int orientation) {
-        setElement(DOM.createDiv());
-        switch (orientation) {
-        case ORIENTATION_HORIZONTAL:
-            setStyleName(CLASSNAME + "-horizontal");
-            break;
-        case ORIENTATION_VERTICAL:
-        default:
-            setStyleName(CLASSNAME + "-vertical");
-            break;
-        }
-        // size below will be overridden in update from uidl, initial size
-        // needed to keep IE alive
-        setWidth(MIN_SIZE + "px");
-        setHeight(MIN_SIZE + "px");
-        constructDom();
-        setOrientation(orientation);
-        DOM.sinkEvents(splitter, (Event.MOUSEEVENTS));
-        DOM.sinkEvents(getElement(), (Event.MOUSEEVENTS));
-    }
-
-    protected void constructDom() {
-        DOM.appendChild(splitter, DOM.createDiv()); // for styling
-        DOM.appendChild(getElement(), wrapper);
-        DOM.setStyleAttribute(wrapper, "position", "relative");
-        DOM.setStyleAttribute(wrapper, "width", "100%");
-        DOM.setStyleAttribute(wrapper, "height", "100%");
-
-        DOM.appendChild(wrapper, secondContainer);
-        DOM.appendChild(wrapper, firstContainer);
-        DOM.appendChild(wrapper, splitter);
-
-        DOM.setStyleAttribute(splitter, "position", "absolute");
-        DOM.setStyleAttribute(secondContainer, "position", "absolute");
-
-        DOM.setStyleAttribute(firstContainer, "overflow", "auto");
-        DOM.setStyleAttribute(secondContainer, "overflow", "auto");
-
-    }
-
-    private void setOrientation(int orientation) {
-        this.orientation = orientation;
-        if (orientation == ORIENTATION_HORIZONTAL) {
-            DOM.setStyleAttribute(splitter, "height", "100%");
-            DOM.setStyleAttribute(splitter, "top", "0");
-            DOM.setStyleAttribute(firstContainer, "height", "100%");
-            DOM.setStyleAttribute(secondContainer, "height", "100%");
-        } else {
-            DOM.setStyleAttribute(splitter, "width", "100%");
-            DOM.setStyleAttribute(splitter, "left", "0");
-            DOM.setStyleAttribute(firstContainer, "width", "100%");
-            DOM.setStyleAttribute(secondContainer, "width", "100%");
-        }
-
-        DOM.setElementProperty(firstContainer, "className", CLASSNAME
-                + "-first-container");
-        DOM.setElementProperty(secondContainer, "className", CLASSNAME
-                + "-second-container");
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-        id = uidl.getId();
-        rendering = true;
-
-        immediate = uidl.hasAttribute("immediate");
-
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-
-        if (uidl.hasAttribute("style")) {
-            componentStyleNames = uidl.getStringAttribute("style").split(" ");
-        } else {
-            componentStyleNames = new String[0];
-        }
-
-        setLocked(uidl.getBooleanAttribute("locked"));
-
-        setStylenames();
-
-        setSplitPosition(uidl.getStringAttribute("position"));
-
-        final Paintable newFirstChild = client.getPaintable(uidl
-                .getChildUIDL(0));
-        final Paintable newSecondChild = client.getPaintable(uidl
-                .getChildUIDL(1));
-        if (firstChild != newFirstChild) {
-            if (firstChild != null) {
-                client.unregisterPaintable((Paintable) firstChild);
-            }
-            setFirstWidget((Widget) newFirstChild);
-        }
-        if (secondChild != newSecondChild) {
-            if (secondChild != null) {
-                client.unregisterPaintable((Paintable) secondChild);
-            }
-            setSecondWidget((Widget) newSecondChild);
-        }
-        newFirstChild.updateFromUIDL(uidl.getChildUIDL(0), client);
-        newSecondChild.updateFromUIDL(uidl.getChildUIDL(1), client);
-
-        renderInformation.updateSize(getElement());
-
-        if (BrowserInfo.get().isIE7()) {
-            // Part III of IE7 hack
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    iLayout();
-                }
-            });
-        }
-        rendering = false;
-
-    }
-
-    private void setLocked(boolean newValue) {
-        if (locked != newValue) {
-            locked = newValue;
-            splitterSize = -1;
-            setStylenames();
-        }
-    }
-
-    private void setSplitPosition(String pos) {
-        if (orientation == ORIENTATION_HORIZONTAL) {
-            DOM.setStyleAttribute(splitter, "left", pos);
-        } else {
-            DOM.setStyleAttribute(splitter, "top", pos);
-        }
-        iLayout();
-        client.runDescendentsLayout(this);
-
-    }
-
-    /*
-     * Calculates absolutely positioned container places/sizes (non-Javadoc)
-     * 
-     * @see com.vaadin.terminal.gwt.client.NeedsLayout#layout()
-     */
-    public void iLayout() {
-        if (!isAttached()) {
-            return;
-        }
-
-        renderInformation.updateSize(getElement());
-
-        int wholeSize;
-        int pixelPosition;
-
-        switch (orientation) {
-        case ORIENTATION_HORIZONTAL:
-            wholeSize = DOM.getElementPropertyInt(wrapper, "clientWidth");
-            pixelPosition = DOM.getElementPropertyInt(splitter, "offsetLeft");
-
-            // reposition splitter in case it is out of box
-            if (pixelPosition > 0
-                    && pixelPosition + getSplitterSize() > wholeSize) {
-                pixelPosition = wholeSize - getSplitterSize();
-                if (pixelPosition < 0) {
-                    pixelPosition = 0;
-                }
-                setSplitPosition(pixelPosition + "px");
-                return;
-            }
-
-            DOM
-                    .setStyleAttribute(firstContainer, "width", pixelPosition
-                            + "px");
-            int secondContainerWidth = (wholeSize - pixelPosition - getSplitterSize());
-            if (secondContainerWidth < 0) {
-                secondContainerWidth = 0;
-            }
-            DOM.setStyleAttribute(secondContainer, "width",
-                    secondContainerWidth + "px");
-            DOM.setStyleAttribute(secondContainer, "left",
-                    (pixelPosition + getSplitterSize()) + "px");
-
-            int contentHeight = renderInformation.getRenderedSize().getHeight();
-            firstRenderSpace.setHeight(contentHeight);
-            firstRenderSpace.setWidth(pixelPosition);
-            secondRenderSpace.setHeight(contentHeight);
-            secondRenderSpace.setWidth(secondContainerWidth);
-
-            break;
-        case ORIENTATION_VERTICAL:
-            wholeSize = DOM.getElementPropertyInt(wrapper, "clientHeight");
-            pixelPosition = DOM.getElementPropertyInt(splitter, "offsetTop");
-
-            // reposition splitter in case it is out of box
-            if (pixelPosition > 0
-                    && pixelPosition + getSplitterSize() > wholeSize) {
-                pixelPosition = wholeSize - getSplitterSize();
-                if (pixelPosition < 0) {
-                    pixelPosition = 0;
-                }
-                setSplitPosition(pixelPosition + "px");
-                return;
-            }
-
-            DOM.setStyleAttribute(firstContainer, "height", pixelPosition
-                    + "px");
-            int secondContainerHeight = (wholeSize - pixelPosition - getSplitterSize());
-            if (secondContainerHeight < 0) {
-                secondContainerHeight = 0;
-            }
-            DOM.setStyleAttribute(secondContainer, "height",
-                    secondContainerHeight + "px");
-            DOM.setStyleAttribute(secondContainer, "top",
-                    (pixelPosition + getSplitterSize()) + "px");
-
-            int contentWidth = renderInformation.getRenderedSize().getWidth();
-            firstRenderSpace.setHeight(pixelPosition);
-            firstRenderSpace.setWidth(contentWidth);
-            secondRenderSpace.setHeight(secondContainerHeight);
-            secondRenderSpace.setWidth(contentWidth);
-
-            break;
-        }
-
-        // fixes scrollbars issues on webkit based browsers
-        Util.runWebkitOverflowAutoFix(secondContainer);
-        Util.runWebkitOverflowAutoFix(firstContainer);
-
-    }
-
-    private void setFirstWidget(Widget w) {
-        if (firstChild != null) {
-            firstChild.removeFromParent();
-        }
-        super.add(w, firstContainer);
-        firstChild = w;
-    }
-
-    private void setSecondWidget(Widget w) {
-        if (secondChild != null) {
-            secondChild.removeFromParent();
-        }
-        super.add(w, secondContainer);
-        secondChild = w;
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        switch (DOM.eventGetType(event)) {
-        case Event.ONMOUSEMOVE:
-            if (resizing) {
-                onMouseMove(event);
-            }
-            break;
-        case Event.ONMOUSEDOWN:
-            onMouseDown(event);
-            break;
-        case Event.ONMOUSEUP:
-            if (resizing) {
-                onMouseUp(event);
-            }
-            break;
-        case Event.ONCLICK:
-            resizing = false;
-            break;
-        }
-    }
-
-    public void onMouseDown(Event event) {
-        if (locked) {
-            return;
-        }
-        final Element trg = DOM.eventGetTarget(event);
-        if (trg == splitter || trg == DOM.getChild(splitter, 0)) {
-            resizing = true;
-            if (BrowserInfo.get().isGecko()) {
-                showDraggingCurtain();
-            }
-            DOM.setCapture(getElement());
-            origX = DOM.getElementPropertyInt(splitter, "offsetLeft");
-            origY = DOM.getElementPropertyInt(splitter, "offsetTop");
-            origMouseX = DOM.eventGetClientX(event);
-            origMouseY = DOM.eventGetClientY(event);
-            DOM.eventCancelBubble(event, true);
-            DOM.eventPreventDefault(event);
-        }
-    }
-
-    public void onMouseMove(Event event) {
-        switch (orientation) {
-        case ORIENTATION_HORIZONTAL:
-            final int x = DOM.eventGetClientX(event);
-            onHorizontalMouseMove(x);
-            break;
-        case ORIENTATION_VERTICAL:
-        default:
-            final int y = DOM.eventGetClientY(event);
-            onVerticalMouseMove(y);
-            break;
-        }
-        iLayout();
-        // TODO Check if this is needed
-        client.runDescendentsLayout(this);
-
-    }
-
-    private void onHorizontalMouseMove(int x) {
-        int newX = origX + x - origMouseX;
-        if (newX < 0) {
-            newX = 0;
-        }
-        if (newX + getSplitterSize() > getOffsetWidth()) {
-            newX = getOffsetWidth() - getSplitterSize();
-        }
-        DOM.setStyleAttribute(splitter, "left", newX + "px");
-        updateSplitPosition(newX);
-    }
-
-    private void onVerticalMouseMove(int y) {
-        int newY = origY + y - origMouseY;
-        if (newY < 0) {
-            newY = 0;
-        }
-
-        if (newY + getSplitterSize() > getOffsetHeight()) {
-            newY = getOffsetHeight() - getSplitterSize();
-        }
-        DOM.setStyleAttribute(splitter, "top", newY + "px");
-        updateSplitPosition(newY);
-    }
-
-    public void onMouseUp(Event event) {
-        DOM.releaseCapture(getElement());
-        if (BrowserInfo.get().isGecko()) {
-            hideDraggingCurtain();
-        }
-        resizing = false;
-        onMouseMove(event);
-    }
-
-    /**
-     * Used in FF to avoid losing mouse capture when pointer is moved on an
-     * iframe.
-     */
-    private void showDraggingCurtain() {
-        if (draggingCurtain == null) {
-            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", ""
-                    + IToolkitOverlay.Z_INDEX);
-            DOM.appendChild(RootPanel.getBodyElement(), draggingCurtain);
-        }
-    }
-
-    /**
-     * Hides dragging curtain
-     */
-    private void hideDraggingCurtain() {
-        if (draggingCurtain != null) {
-            DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain);
-            draggingCurtain = null;
-        }
-    }
-
-    private int splitterSize = -1;
-
-    private int getSplitterSize() {
-        if (splitterSize < 0) {
-            if (isAttached()) {
-                switch (orientation) {
-                case ORIENTATION_HORIZONTAL:
-                    splitterSize = DOM.getElementPropertyInt(splitter,
-                            "offsetWidth");
-                    break;
-
-                default:
-                    splitterSize = DOM.getElementPropertyInt(splitter,
-                            "offsetHeight");
-                    break;
-                }
-            }
-        }
-        return splitterSize;
-    }
-
-    @Override
-    public void setHeight(String height) {
-        if (this.height.equals(height)) {
-            return;
-        }
-
-        this.height = height;
-        super.setHeight(height);
-        if (!rendering && client != null) {
-            iLayout();
-            client.runDescendentsLayout(this);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        this.width = width;
-        super.setWidth(width);
-        if (!rendering && client != null) {
-            iLayout();
-            client.runDescendentsLayout(this);
-        }
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        if (child == firstChild) {
-            return firstRenderSpace;
-        } else if (child == secondChild) {
-            return secondRenderSpace;
-        }
-
-        return null;
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        return (component != null && (component == firstChild || component == secondChild));
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        if (oldComponent == firstChild) {
-            setFirstWidget(newComponent);
-        } else if (oldComponent == secondChild) {
-            setSecondWidget(newComponent);
-        }
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        if (height != null && width != null) {
-            /*
-             * If the height and width has been specified the child components
-             * cannot make the size of the layout change
-             */
-
-            return true;
-        }
-
-        if (renderInformation.updateSize(getElement())) {
-            return false;
-        } else {
-            return true;
-        }
-
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        // TODO Implement caption handling
-    }
-
-    /**
-     * Updates the new split position back to server.
-     * 
-     * @param pos
-     *            The new position of the split handle.
-     */
-    private void updateSplitPosition(int pos) {
-        // We always send pixel values to server
-        client.updateVariable(id, "position", pos, immediate);
-    }
-
-    private void setStylenames() {
-        final String splitterSuffix = (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter"
-                : "-vsplitter");
-        final String firstContainerSuffix = "-first-container";
-        final String secondContainerSuffix = "-second-container";
-        String lockedSuffix = "";
-
-        String splitterStyle = CLASSNAME + splitterSuffix;
-        String firstStyle = CLASSNAME + firstContainerSuffix;
-        String secondStyle = CLASSNAME + secondContainerSuffix;
-
-        if (locked) {
-            splitterStyle = CLASSNAME + splitterSuffix + "-locked";
-            lockedSuffix = "-locked";
-        }
-        for (int i = 0; i < componentStyleNames.length; i++) {
-            splitterStyle += " " + CLASSNAME + splitterSuffix + "-"
-                    + componentStyleNames[i] + lockedSuffix;
-            firstStyle += " " + CLASSNAME + firstContainerSuffix + "-"
-                    + componentStyleNames[i];
-            secondStyle += " " + CLASSNAME + secondContainerSuffix + "-"
-                    + componentStyleNames[i];
-        }
-        DOM.setElementProperty(splitter, "className", splitterStyle);
-        DOM.setElementProperty(firstContainer, "className", firstStyle);
-        DOM.setElementProperty(secondContainer, "className", secondStyle);
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ISplitPanelHorizontal.java b/src/com/vaadin/terminal/gwt/client/ui/ISplitPanelHorizontal.java
deleted file mode 100644 (file)
index 1408814..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-public class ISplitPanelHorizontal extends ISplitPanel {
-
-    public ISplitPanelHorizontal() {
-        super(ISplitPanel.ORIENTATION_HORIZONTAL);
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ISplitPanelVertical.java b/src/com/vaadin/terminal/gwt/client/ui/ISplitPanelVertical.java
deleted file mode 100644 (file)
index eff00e8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-public class ISplitPanelVertical extends ISplitPanel {
-
-    public ISplitPanelVertical() {
-        super(ISplitPanel.ORIENTATION_VERTICAL);
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITablePaging.java b/src/com/vaadin/terminal/gwt/client/ui/ITablePaging.java
deleted file mode 100644 (file)
index 224c549..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Vector;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.Grid;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.HorizontalPanel;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-/**
- * TODO make this work (just an early prototype). We may want to have paging
- * style table which will be much lighter than IScrollTable is.
- */
-public class ITablePaging extends Composite implements Table, Paintable,
-        ClickListener {
-
-    private final Grid tBody = new Grid();
-    private final Button nextPage = new Button("&gt;");
-    private final Button prevPage = new Button("&lt;");
-    private final Button firstPage = new Button("&lt;&lt;");
-    private final Button lastPage = new Button("&gt;&gt;");
-
-    private int pageLength = 15;
-
-    private boolean rowHeaders = false;
-
-    private ApplicationConnection client;
-    private String id;
-
-    private boolean immediate = false;
-
-    private int selectMode = Table.SELECT_MODE_NONE;
-
-    private final Vector selectedRowKeys = new Vector();
-
-    private int totalRows;
-
-    private final HashMap visibleColumns = new HashMap();
-
-    private int rows;
-
-    private int firstRow;
-    private boolean sortAscending = true;
-    private final HorizontalPanel pager;
-
-    public HashMap rowKeysToTableRows = new HashMap();
-
-    public ITablePaging() {
-
-        tBody.setStyleName("itable-tbody");
-
-        final VerticalPanel panel = new VerticalPanel();
-
-        pager = new HorizontalPanel();
-        pager.add(firstPage);
-        firstPage.addClickListener(this);
-        pager.add(prevPage);
-        prevPage.addClickListener(this);
-        pager.add(nextPage);
-        nextPage.addClickListener(this);
-        pager.add(lastPage);
-        lastPage.addClickListener(this);
-
-        panel.add(pager);
-        panel.add(tBody);
-
-        initWidget(panel);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        this.client = client;
-        id = uidl.getStringAttribute("id");
-        immediate = uidl.getBooleanAttribute("immediate");
-        totalRows = uidl.getIntAttribute("totalrows");
-        pageLength = uidl.getIntAttribute("pagelength");
-        firstRow = uidl.getIntAttribute("firstrow");
-        rows = uidl.getIntAttribute("rows");
-
-        if (uidl.hasAttribute("selectmode")) {
-            if (uidl.getStringAttribute("selectmode").equals("multi")) {
-                selectMode = Table.SELECT_MODE_MULTI;
-            } else {
-                selectMode = Table.SELECT_MODE_SINGLE;
-            }
-
-            if (uidl.hasAttribute("selected")) {
-                final Set selectedKeys = uidl
-                        .getStringArrayVariableAsSet("selected");
-                selectedRowKeys.clear();
-                for (final Iterator it = selectedKeys.iterator(); it.hasNext();) {
-                    selectedRowKeys.add(it.next());
-                }
-            }
-        }
-
-        if (uidl.hasVariable("sortascending")) {
-            sortAscending = uidl.getBooleanVariable("sortascending");
-        }
-
-        if (uidl.hasAttribute("rowheaders")) {
-            rowHeaders = true;
-        }
-
-        UIDL rowData = null;
-        UIDL visibleColumns = null;
-        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
-            final UIDL c = (UIDL) it.next();
-            if (c.getTag().equals("rows")) {
-                rowData = c;
-            } else if (c.getTag().equals("actions")) {
-                updateActionMap(c);
-            } else if (c.getTag().equals("visiblecolumns")) {
-                visibleColumns = c;
-            }
-        }
-        tBody.resize(rows + 1, uidl.getIntAttribute("cols")
-                + (rowHeaders ? 1 : 0));
-        updateHeader(visibleColumns);
-        updateBody(rowData);
-
-        updatePager();
-    }
-
-    private void updateHeader(UIDL c) {
-        final Iterator it = c.getChildIterator();
-        visibleColumns.clear();
-        int colIndex = (rowHeaders ? 1 : 0);
-        while (it.hasNext()) {
-            final UIDL col = (UIDL) it.next();
-            final String cid = col.getStringAttribute("cid");
-            if (!col.hasAttribute("collapsed")) {
-                tBody.setWidget(0, colIndex, new HeaderCell(cid, col
-                        .getStringAttribute("caption")));
-
-            }
-            colIndex++;
-        }
-    }
-
-    private void updateActionMap(UIDL c) {
-        // TODO Auto-generated method stub
-
-    }
-
-    /**
-     * Updates row data from uidl. UpdateFromUIDL delegates updating tBody to
-     * this method.
-     * 
-     * Updates may be to different part of tBody, depending on update type. It
-     * can be initial row data, scroll up, scroll down...
-     * 
-     * @param uidl
-     *            which contains row data
-     */
-    private void updateBody(UIDL uidl) {
-        final Iterator it = uidl.getChildIterator();
-
-        int curRowIndex = 1;
-        while (it.hasNext()) {
-            final UIDL rowUidl = (UIDL) it.next();
-            final TableRow row = new TableRow(curRowIndex, String
-                    .valueOf(rowUidl.getIntAttribute("key")), rowUidl
-                    .hasAttribute("selected"));
-            int colIndex = 0;
-            if (rowHeaders) {
-                tBody.setWidget(curRowIndex, colIndex, new BodyCell(row,
-                        rowUidl.getStringAttribute("caption")));
-                colIndex++;
-            }
-            final Iterator cells = rowUidl.getChildIterator();
-            while (cells.hasNext()) {
-                final Object cell = cells.next();
-                if (cell instanceof String) {
-                    tBody.setWidget(curRowIndex, colIndex, new BodyCell(row,
-                            (String) cell));
-                } else {
-                    final Paintable cellContent = client
-                            .getPaintable((UIDL) cell);
-                    final BodyCell bodyCell = new BodyCell(row);
-                    bodyCell.setWidget((Widget) cellContent);
-                    tBody.setWidget(curRowIndex, colIndex, bodyCell);
-                }
-                colIndex++;
-            }
-            curRowIndex++;
-        }
-    }
-
-    private void updatePager() {
-        if (pageLength == 0) {
-            pager.setVisible(false);
-            return;
-        }
-        if (isFirstPage()) {
-            firstPage.setEnabled(false);
-            prevPage.setEnabled(false);
-        } else {
-            firstPage.setEnabled(true);
-            prevPage.setEnabled(true);
-        }
-        if (hasNextPage()) {
-            nextPage.setEnabled(true);
-            lastPage.setEnabled(true);
-        } else {
-            nextPage.setEnabled(false);
-            lastPage.setEnabled(false);
-
-        }
-    }
-
-    private boolean hasNextPage() {
-        if (firstRow + rows + 1 > totalRows) {
-            return false;
-        }
-        return true;
-    }
-
-    private boolean isFirstPage() {
-        if (firstRow == 0) {
-            return true;
-        }
-        return false;
-    }
-
-    public void onClick(Widget sender) {
-        if (sender instanceof Button) {
-            if (sender == firstPage) {
-                client.updateVariable(id, "firstvisible", 0, true);
-            } else if (sender == nextPage) {
-                client.updateVariable(id, "firstvisible",
-                        firstRow + pageLength, true);
-            } else if (sender == prevPage) {
-                int newFirst = firstRow - pageLength;
-                if (newFirst < 0) {
-                    newFirst = 0;
-                }
-                client.updateVariable(id, "firstvisible", newFirst, true);
-            } else if (sender == lastPage) {
-                client.updateVariable(id, "firstvisible", totalRows
-                        - pageLength, true);
-            }
-        }
-        if (sender instanceof HeaderCell) {
-            final HeaderCell hCell = (HeaderCell) sender;
-            client.updateVariable(id, "sortcolumn", hCell.getCid(), false);
-            client.updateVariable(id, "sortascending", (sortAscending ? false
-                    : true), true);
-        }
-    }
-
-    private class HeaderCell extends HTML {
-
-        private String cid;
-
-        public String getCid() {
-            return cid;
-        }
-
-        public void setCid(String pid) {
-            cid = pid;
-        }
-
-        HeaderCell(String pid, String caption) {
-            super();
-            cid = pid;
-            addClickListener(ITablePaging.this);
-            setText(caption);
-            // TODO remove debug color
-            DOM.setStyleAttribute(getElement(), "color", "brown");
-            DOM.setStyleAttribute(getElement(), "font-weight", "bold");
-        }
-    }
-
-    /**
-     * Abstraction of table cell content. In needs to know on which row it is in
-     * case of context click.
-     * 
-     * @author mattitahvonen
-     */
-    public class BodyCell extends SimplePanel {
-        private final TableRow row;
-
-        public BodyCell(TableRow row) {
-            super();
-            sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT);
-            this.row = row;
-        }
-
-        public BodyCell(TableRow row2, String textContent) {
-            super();
-            sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT);
-            row = row2;
-            setWidget(new Label(textContent));
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            System.out.println("CEll event: " + event.toString());
-            switch (DOM.eventGetType(event)) {
-            case Event.BUTTON_RIGHT:
-                row.showContextMenu(event);
-                Window.alert("context menu un-implemented");
-                DOM.eventCancelBubble(event, true);
-                break;
-            case Event.BUTTON_LEFT:
-                if (selectMode > Table.SELECT_MODE_NONE) {
-                    row.toggleSelected();
-                }
-                break;
-            default:
-                break;
-            }
-            super.onBrowserEvent(event);
-        }
-    }
-
-    private class TableRow {
-
-        private final String key;
-        private final int rowIndex;
-        private boolean selected = false;
-
-        public TableRow(int rowIndex, String rowKey, boolean selected) {
-            rowKeysToTableRows.put(rowKey, this);
-            this.rowIndex = rowIndex;
-            key = rowKey;
-            setSelected(selected);
-        }
-
-        /**
-         * This method is used to set row status. Does not change value on
-         * server.
-         * 
-         * @param selected
-         */
-        public void setSelected(boolean sel) {
-            selected = sel;
-            if (selected) {
-                selectedRowKeys.add(key);
-                DOM.setStyleAttribute(tBody.getRowFormatter().getElement(
-                        rowIndex), "background", "yellow");
-
-            } else {
-                selectedRowKeys.remove(key);
-                DOM.setStyleAttribute(tBody.getRowFormatter().getElement(
-                        rowIndex), "background", "transparent");
-            }
-        }
-
-        public void setContextMenuOptions(HashMap options) {
-
-        }
-
-        /**
-         * Toggles rows select state. Also updates state to server according to
-         * tables immediate flag.
-         * 
-         */
-        public void toggleSelected() {
-            if (selected) {
-                setSelected(false);
-            } else {
-                if (selectMode == Table.SELECT_MODE_SINGLE) {
-                    deselectAll();
-                }
-                setSelected(true);
-            }
-            client.updateVariable(id, "selected", selectedRowKeys.toArray(),
-                    immediate);
-        }
-
-        /**
-         * Shows context menu for this row.
-         * 
-         * @param event
-         *            Event which triggered context menu. Correct place for
-         *            context menu can be determined with it.
-         */
-        public void showContextMenu(Event event) {
-            System.out.println("TODO: Show context menu");
-        }
-    }
-
-    public void deselectAll() {
-        final Object[] keys = selectedRowKeys.toArray();
-        for (int i = 0; i < keys.length; i++) {
-            final TableRow tableRow = (TableRow) rowKeysToTableRows
-                    .get(keys[i]);
-            if (tableRow != null) {
-                tableRow.setSelected(false);
-            }
-        }
-        // still ensure all selects are removed from
-        selectedRowKeys.clear();
-    }
-
-    public void add(Widget w) {
-        // TODO Auto-generated method stub
-
-    }
-
-    public void clear() {
-        // TODO Auto-generated method stub
-
-    }
-
-    public Iterator iterator() {
-        // TODO Auto-generated method stub
-        return null;
-    }
-
-    public boolean remove(Widget w) {
-        // TODO Auto-generated method stub
-        return false;
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/ITabsheet.java
deleted file mode 100644 (file)
index 52f5a41..0000000
+++ /dev/null
@@ -1,841 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.ICaption;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderInformation;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-public class ITabsheet extends ITabsheetBase {
-
-    private class TabSheetCaption extends ICaption {
-        TabSheetCaption() {
-            super(null, client);
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            super.onBrowserEvent(event);
-            if (event.getTypeInt() == Event.ONLOAD) {
-                // icon onloads may change total width of tabsheet
-                if (isDynamicWidth()) {
-                    updateDynamicWidth();
-                }
-                updateTabScroller();
-            }
-        }
-
-        @Override
-        public void setWidth(String width) {
-            super.setWidth(width);
-            if (BrowserInfo.get().isIE7()) {
-                /*
-                 * IE7 apparently has problems with calculating width for
-                 * floated elements inside a DIV with padding. Set the width
-                 * explicitly for the caption.
-                 */
-                fixTextWidth();
-            }
-        }
-
-        private void fixTextWidth() {
-            Element captionText = getTextElement();
-            int captionWidth = Util.getRequiredWidth(captionText);
-            int scrollWidth = captionText.getScrollWidth();
-            if (scrollWidth > captionWidth) {
-                captionWidth = scrollWidth;
-            }
-            captionText.getStyle().setPropertyPx("width", captionWidth);
-        }
-
-    }
-
-    class TabBar extends ComplexPanel implements ClickListener {
-
-        private Element tr = DOM.createTR();
-
-        private Element spacerTd = DOM.createTD();
-
-        TabBar() {
-            Element el = DOM.createTable();
-            Element tbody = DOM.createTBody();
-            DOM.appendChild(el, tbody);
-            DOM.appendChild(tbody, tr);
-            setStyleName(spacerTd, CLASSNAME + "-spacertd");
-            DOM.appendChild(tr, spacerTd);
-            DOM.appendChild(spacerTd, DOM.createDiv());
-            setElement(el);
-        }
-
-        protected Element getContainerElement() {
-            return tr;
-        }
-
-        private Widget oldSelected;
-
-        public int getTabCount() {
-            return getWidgetCount();
-        }
-
-        public void addTab(ICaption c) {
-            Element td = DOM.createTD();
-            setStyleName(td, CLASSNAME + "-tabitemcell");
-
-            if (getWidgetCount() == 0) {
-                setStyleName(td, CLASSNAME + "-tabitemcell-first", true);
-            }
-
-            Element div = DOM.createDiv();
-            setStyleName(div, CLASSNAME + "-tabitem");
-            DOM.appendChild(td, div);
-            DOM.insertBefore(tr, td, spacerTd);
-            c.addClickListener(this);
-            add(c, div);
-        }
-
-        public void onClick(Widget sender) {
-            int index = getWidgetIndex(sender);
-            onTabSelected(index);
-        }
-
-        public void selectTab(int index) {
-            Widget newSelected = getWidget(index);
-            Widget.setStyleName(DOM.getParent(newSelected.getElement()),
-                    CLASSNAME + "-tabitem-selected", true);
-            if (oldSelected != null && oldSelected != newSelected) {
-                Widget.setStyleName(DOM.getParent(oldSelected.getElement()),
-                        CLASSNAME + "-tabitem-selected", false);
-            }
-            oldSelected = newSelected;
-        }
-
-        public void removeTab(int i) {
-            Widget w = getWidget(i);
-            if (w == null) {
-                return;
-            }
-
-            Element caption = w.getElement();
-            Element div = DOM.getParent(caption);
-            Element td = DOM.getParent(div);
-            Element tr = DOM.getParent(td);
-            remove(w);
-
-            /*
-             * Widget is the Caption but we want to remove everything up to and
-             * including the parent TD
-             */
-
-            DOM.removeChild(tr, td);
-
-            /*
-             * If this widget was selected we need to unmark it as the last
-             * selected
-             */
-            if (w == oldSelected) {
-                oldSelected = null;
-            }
-        }
-
-        @Override
-        public boolean remove(Widget w) {
-            ((ICaption) w).removeClickListener(this);
-            return super.remove(w);
-        }
-
-        public TabSheetCaption getTab(int index) {
-            if (index >= getWidgetCount()) {
-                return null;
-            }
-            return (TabSheetCaption) getWidget(index);
-        }
-
-        public void setVisible(int index, boolean visible) {
-            Element e = DOM.getParent(getTab(index).getElement());
-            if (visible) {
-                DOM.setStyleAttribute(e, "display", "");
-            } else {
-                DOM.setStyleAttribute(e, "display", "none");
-            }
-        }
-
-        public void updateCaptionSize(int index) {
-            ICaption c = getTab(index);
-            c.setWidth(c.getRequiredWidth() + "px");
-
-        }
-
-    }
-
-    public static final String CLASSNAME = "i-tabsheet";
-
-    public static final String TABS_CLASSNAME = "i-tabsheet-tabcontainer";
-    public static final String SCROLLER_CLASSNAME = "i-tabsheet-scroller";
-    private final Element tabs; // tabbar and 'scroller' container
-    private final Element scroller; // tab-scroller element
-    private final Element scrollerNext; // tab-scroller next button element
-    private final Element scrollerPrev; // tab-scroller prev button element
-    private int scrollerIndex = 0;
-
-    private final TabBar tb = new TabBar();
-    private final ITabsheetPanel tp = new ITabsheetPanel();
-    private final Element contentNode, deco;
-
-    private final HashMap<String, ICaption> captions = new HashMap<String, ICaption>();
-
-    private String height;
-    private String width;
-
-    private boolean waitingForResponse;
-
-    private RenderInformation renderInformation = new RenderInformation();
-
-    /**
-     * Previous visible widget is set invisible with CSS (not display: none, but
-     * visibility: hidden), to avoid flickering during render process. Normal
-     * visibility must be returned later when new widget is rendered.
-     */
-    private Widget previousVisibleWidget;
-
-    private boolean rendering = false;
-
-    private void onTabSelected(final int tabIndex) {
-        if (disabled || waitingForResponse) {
-            return;
-        }
-        final Object tabKey = tabKeys.get(tabIndex);
-        if (disabledTabKeys.contains(tabKey)) {
-            return;
-        }
-        if (client != null && activeTabIndex != tabIndex) {
-            tb.selectTab(tabIndex);
-            addStyleDependentName("loading");
-            // run updating variables in deferred command to bypass some FF
-            // optimization issues
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    previousVisibleWidget = tp.getWidget(tp.getVisibleWidget());
-                    DOM.setStyleAttribute(DOM.getParent(previousVisibleWidget
-                            .getElement()), "visibility", "hidden");
-                    client.updateVariable(id, "selected", tabKeys.get(tabIndex)
-                            .toString(), true);
-                }
-            });
-            waitingForResponse = true;
-        }
-    }
-
-    private boolean isDynamicWidth() {
-        return width == null || width.equals("");
-    }
-
-    private boolean isDynamicHeight() {
-        return height == null || height.equals("");
-    }
-
-    public ITabsheet() {
-        super(CLASSNAME);
-
-        // Tab scrolling
-        DOM.setStyleAttribute(getElement(), "overflow", "hidden");
-        tabs = DOM.createDiv();
-        DOM.setElementProperty(tabs, "className", TABS_CLASSNAME);
-        scroller = DOM.createDiv();
-
-        DOM.setElementProperty(scroller, "className", SCROLLER_CLASSNAME);
-        scrollerPrev = DOM.createButton();
-        DOM.setElementProperty(scrollerPrev, "className", SCROLLER_CLASSNAME
-                + "Prev");
-        DOM.sinkEvents(scrollerPrev, Event.ONCLICK);
-        scrollerNext = DOM.createButton();
-        DOM.setElementProperty(scrollerNext, "className", SCROLLER_CLASSNAME
-                + "Next");
-        DOM.sinkEvents(scrollerNext, Event.ONCLICK);
-        DOM.appendChild(getElement(), tabs);
-
-        // Tabs
-        tp.setStyleName(CLASSNAME + "-tabsheetpanel");
-        contentNode = DOM.createDiv();
-
-        deco = DOM.createDiv();
-
-        addStyleDependentName("loading"); // Indicate initial progress
-        tb.setStyleName(CLASSNAME + "-tabs");
-        DOM
-                .setElementProperty(contentNode, "className", CLASSNAME
-                        + "-content");
-        DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
-
-        add(tb, tabs);
-        DOM.appendChild(scroller, scrollerPrev);
-        DOM.appendChild(scroller, scrollerNext);
-
-        DOM.appendChild(getElement(), contentNode);
-        add(tp, contentNode);
-        DOM.appendChild(getElement(), deco);
-
-        DOM.appendChild(tabs, scroller);
-
-        // TODO Use for Safari only. Fix annoying 1px first cell in TabBar.
-        // DOM.setStyleAttribute(DOM.getFirstChild(DOM.getFirstChild(DOM
-        // .getFirstChild(tb.getElement()))), "display", "none");
-
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-
-        // Tab scrolling
-        if (isScrolledTabs() && DOM.eventGetTarget(event) == scrollerPrev) {
-            if (scrollerIndex > 0) {
-                scrollerIndex--;
-                DOM.setStyleAttribute(DOM.getChild(DOM.getFirstChild(DOM
-                        .getFirstChild(tb.getElement())), scrollerIndex),
-                        "display", "");
-                tb.updateCaptionSize(scrollerIndex);
-                updateTabScroller();
-            }
-        } else if (isClippedTabs() && DOM.eventGetTarget(event) == scrollerNext) {
-            int tabs = tb.getTabCount();
-            if (scrollerIndex + 1 <= tabs) {
-                DOM.setStyleAttribute(DOM.getChild(DOM.getFirstChild(DOM
-                        .getFirstChild(tb.getElement())), scrollerIndex),
-                        "display", "none");
-                tb.updateCaptionSize(scrollerIndex);
-                scrollerIndex++;
-                updateTabScroller();
-            }
-        } else {
-            super.onBrowserEvent(event);
-        }
-    }
-
-    @Override
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-
-        super.updateFromUIDL(uidl, client);
-        if (cachedUpdate) {
-            return;
-        }
-
-        // Add proper stylenames for all elements (easier to prevent unwanted
-        // style inheritance)
-        if (uidl.hasAttribute("style")) {
-            final String[] styles = uidl.getStringAttribute("style").split(" ");
-            final String contentBaseClass = CLASSNAME + "-content";
-            String contentClass = contentBaseClass;
-            final String decoBaseClass = CLASSNAME + "-deco";
-            String decoClass = decoBaseClass;
-            for (int i = 0; i < styles.length; i++) {
-                tb.addStyleDependentName(styles[i]);
-                contentClass += " " + contentBaseClass + "-" + styles[i];
-                decoClass += " " + decoBaseClass + "-" + styles[i];
-            }
-            DOM.setElementProperty(contentNode, "className", contentClass);
-            DOM.setElementProperty(deco, "className", decoClass);
-        } else {
-            tb.setStyleName(CLASSNAME + "-tabs");
-            DOM.setElementProperty(contentNode, "className", CLASSNAME
-                    + "-content");
-            DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
-        }
-
-        if (uidl.hasAttribute("hidetabs")) {
-            tb.setVisible(false);
-            addStyleName(CLASSNAME + "-hidetabs");
-        } else {
-            tb.setVisible(true);
-            removeStyleName(CLASSNAME + "-hidetabs");
-        }
-
-        // tabs; push or not
-        if (!isDynamicWidth()) {
-            // FIXME: This makes tab sheet tabs go to 1px width on every update
-            // and then back to original width
-            // update width later, in updateTabScroller();
-            DOM.setStyleAttribute(tabs, "width", "1px");
-            DOM.setStyleAttribute(tabs, "overflow", "hidden");
-        } else {
-            showAllTabs();
-            DOM.setStyleAttribute(tabs, "width", "");
-            DOM.setStyleAttribute(tabs, "overflow", "visible");
-            updateDynamicWidth();
-        }
-
-        if (!isDynamicHeight()) {
-            // Must update height after the styles have been set
-            updateContentNodeHeight();
-            updateOpenTabSize();
-        }
-
-        iLayout();
-
-        // Re run relative size update to ensure optimal scrollbars
-        // TODO isolate to situation that visible tab has undefined height
-        try {
-            client.handleComponentRelativeSize(tp.getWidget(tp
-                    .getVisibleWidget()));
-        } catch (Exception e) {
-            // Ignore, most likely empty tabsheet
-        }
-
-        renderInformation.updateSize(getElement());
-
-        waitingForResponse = false;
-        rendering = false;
-    }
-
-    private void updateDynamicWidth() {
-        // Find tab width
-        int tabsWidth = 0;
-
-        int count = tb.getTabCount();
-        for (int i = 0; i < count; i++) {
-            Element tabTd = tb.getTab(i).getElement().getParentElement().cast();
-            tabsWidth += tabTd.getOffsetWidth();
-        }
-
-        // Find content width
-        Style style = tp.getElement().getStyle();
-        String overflow = style.getProperty("overflow");
-        style.setProperty("overflow", "hidden");
-        style.setPropertyPx("width", tabsWidth);
-        Style wrapperstyle = tp.getWidget(tp.getVisibleWidget()).getElement()
-                .getParentElement().getStyle();
-        wrapperstyle.setPropertyPx("width", tabsWidth);
-        // Get content width from actual widget
-
-        int contentWidth = 0;
-        if (tp.getWidgetCount() > 0) {
-            contentWidth = tp.getWidget(tp.getVisibleWidget()).getOffsetWidth();
-        }
-        style.setProperty("overflow", overflow);
-
-        // Set widths to max(tabs,content)
-        if (tabsWidth < contentWidth) {
-            tabsWidth = contentWidth;
-        }
-
-        int outerWidth = tabsWidth + getContentAreaBorderWidth();
-
-        tabs.getStyle().setPropertyPx("width", outerWidth);
-        style.setPropertyPx("width", tabsWidth);
-        wrapperstyle.setPropertyPx("width", tabsWidth);
-
-        contentNode.getStyle().setPropertyPx("width", tabsWidth);
-        super.setWidth(outerWidth + "px");
-        updateOpenTabSize();
-    }
-
-    @Override
-    protected void renderTab(final UIDL tabUidl, int index, boolean selected,
-            boolean hidden) {
-        TabSheetCaption c = tb.getTab(index);
-        if (c == null) {
-            c = new TabSheetCaption();
-            tb.addTab(c);
-        }
-        c.updateCaption(tabUidl);
-
-        tb.setVisible(index, !hidden);
-
-        /*
-         * Force the width of the caption container so the content will not wrap
-         * and tabs won't be too narrow in certain browsers
-         */
-        c.setWidth(c.getRequiredWidth() + "px");
-        captions.put("" + index, c);
-
-        UIDL tabContentUIDL = null;
-        Paintable tabContent = null;
-        if (tabUidl.getChildCount() > 0) {
-            tabContentUIDL = tabUidl.getChildUIDL(0);
-            tabContent = client.getPaintable(tabContentUIDL);
-        }
-
-        if (tabContent != null) {
-            /* This is a tab with content information */
-
-            int oldIndex = tp.getWidgetIndex((Widget) tabContent);
-            if (oldIndex != -1 && oldIndex != index) {
-                /*
-                 * The tab has previously been rendered in another position so
-                 * we must move the cached content to correct position
-                 */
-                tp.insert((Widget) tabContent, index);
-            }
-        } else {
-            /* A tab whose content has not yet been loaded */
-
-            /*
-             * Make sure there is a corresponding empty tab in tp. The same
-             * operation as the moving above but for not-loaded tabs.
-             */
-            if (index < tp.getWidgetCount()) {
-                Widget oldWidget = tp.getWidget(index);
-                if (!(oldWidget instanceof PlaceHolder)) {
-                    tp.insert(new PlaceHolder(), index);
-                }
-            }
-
-        }
-
-        if (selected) {
-            renderContent(tabContentUIDL);
-            tb.selectTab(index);
-        } else {
-            if (tabContentUIDL != null) {
-                // updating a drawn child on hidden tab
-                if (tp.getWidgetIndex((Widget) tabContent) < 0) {
-                    tp.insert((Widget) tabContent, index);
-                }
-                tabContent.updateFromUIDL(tabContentUIDL, client);
-            } else if (tp.getWidgetCount() <= index) {
-                tp.add(new PlaceHolder());
-            }
-        }
-    }
-
-    public class PlaceHolder extends ILabel {
-        public PlaceHolder() {
-            super("");
-        }
-    }
-
-    @Override
-    protected void selectTab(int index, final UIDL contentUidl) {
-        if (index != activeTabIndex) {
-            activeTabIndex = index;
-            tb.selectTab(activeTabIndex);
-        }
-        renderContent(contentUidl);
-    }
-
-    private void renderContent(final UIDL contentUIDL) {
-        final Paintable content = client.getPaintable(contentUIDL);
-        if (tp.getWidgetCount() > activeTabIndex) {
-            Widget old = tp.getWidget(activeTabIndex);
-            if (old != content) {
-                tp.remove(activeTabIndex);
-                if (old instanceof Paintable) {
-                    client.unregisterPaintable((Paintable) old);
-                }
-                tp.insert((Widget) content, activeTabIndex);
-            }
-        } else {
-            tp.add((Widget) content);
-        }
-
-        tp.showWidget(activeTabIndex);
-
-        ITabsheet.this.iLayout();
-        (content).updateFromUIDL(contentUIDL, client);
-        /*
-         * The size of a cached, relative sized component must be updated to
-         * report correct size to updateOpenTabSize().
-         */
-        if (contentUIDL.getBooleanAttribute("cached")) {
-            client.handleComponentRelativeSize((Widget) content);
-        }
-        updateOpenTabSize();
-        ITabsheet.this.removeStyleDependentName("loading");
-        if (previousVisibleWidget != null) {
-            DOM.setStyleAttribute(previousVisibleWidget.getElement(),
-                    "visibility", "");
-            previousVisibleWidget = null;
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        this.height = height;
-        updateContentNodeHeight();
-
-        if (!rendering) {
-            updateOpenTabSize();
-            iLayout();
-            // TODO Check if this is needed
-            client.runDescendentsLayout(this);
-        }
-    }
-
-    private void updateContentNodeHeight() {
-        if (height != null && !"".equals(height)) {
-            int contentHeight = getOffsetHeight();
-            contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight");
-            contentHeight -= tb.getOffsetHeight();
-            if (contentHeight < 0) {
-                contentHeight = 0;
-            }
-
-            // Set proper values for content element
-            DOM.setStyleAttribute(contentNode, "height", contentHeight + "px");
-            renderSpace.setHeight(contentHeight);
-        } else {
-            DOM.setStyleAttribute(contentNode, "height", "");
-            renderSpace.setHeight(0);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if ((this.width == null && width.equals(""))
-                || (this.width != null && this.width.equals(width))) {
-            return;
-        }
-
-        super.setWidth(width);
-        if (width.equals("")) {
-            width = null;
-        }
-        this.width = width;
-        if (width == null) {
-            renderSpace.setWidth(0);
-            contentNode.getStyle().setProperty("width", "");
-        } else {
-            int contentWidth = getOffsetWidth() - getContentAreaBorderWidth();
-            if (contentWidth < 0) {
-                contentWidth = 0;
-            }
-            contentNode.getStyle().setProperty("width", contentWidth + "px");
-            renderSpace.setWidth(contentWidth);
-        }
-
-        if (!rendering) {
-            if (isDynamicHeight()) {
-                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, tp,
-                        this);
-            }
-
-            updateOpenTabSize();
-            iLayout();
-            // TODO Check if this is needed
-            client.runDescendentsLayout(this);
-
-        }
-
-    }
-
-    public void iLayout() {
-        updateTabScroller();
-        tp.runWebkitOverflowAutoFix();
-    }
-
-    /**
-     * Sets the size of the visible tab (component). As the tab is set to
-     * position: absolute (to work around a firefox flickering bug) we must keep
-     * this up-to-date by hand.
-     */
-    private void updateOpenTabSize() {
-        /*
-         * The overflow=auto element must have a height specified, otherwise it
-         * will be just as high as the contents and no scrollbars will appear
-         */
-        int height = -1;
-        int width = -1;
-        int minWidth = 0;
-
-        if (!isDynamicHeight()) {
-            height = renderSpace.getHeight();
-        }
-        if (!isDynamicWidth()) {
-            width = renderSpace.getWidth();
-        } else {
-            /*
-             * If the tabbar is wider than the content we need to use the tabbar
-             * width as minimum width so scrollbars get placed correctly (at the
-             * right edge).
-             */
-            minWidth = tb.getOffsetWidth() - getContentAreaBorderWidth();
-        }
-        tp.fixVisibleTabSize(width, height, minWidth);
-
-    }
-
-    /**
-     * Layouts the tab-scroller elements, and applies styles.
-     */
-    private void updateTabScroller() {
-        if (width != null) {
-            DOM.setStyleAttribute(tabs, "width", width);
-        }
-        if (scrollerIndex > tb.getTabCount()) {
-            scrollerIndex = 0;
-        }
-        boolean scrolled = isScrolledTabs();
-        boolean clipped = isClippedTabs();
-        if (tb.isVisible() && (scrolled || clipped)) {
-            DOM.setStyleAttribute(scroller, "display", "");
-            DOM.setElementProperty(scrollerPrev, "className",
-                    SCROLLER_CLASSNAME + (scrolled ? "Prev" : "Prev-disabled"));
-            DOM.setElementProperty(scrollerNext, "className",
-                    SCROLLER_CLASSNAME + (clipped ? "Next" : "Next-disabled"));
-        } else {
-            DOM.setStyleAttribute(scroller, "display", "none");
-        }
-
-        if (BrowserInfo.get().isSafari()) {
-            // fix tab height for safari, bugs sometimes if tabs contain icons
-            String property = tabs.getStyle().getProperty("height");
-            if (property == null || property.equals("")) {
-                tabs.getStyle().setPropertyPx("height", tb.getOffsetHeight());
-            }
-            /*
-             * another hack for webkits. tabscroller sometimes drops without
-             * "shaking it" reproducable in
-             * com.vaadin.tests.components.tabsheet.TabSheetIcons
-             */
-            final Style style = scroller.getStyle();
-            style.setProperty("whiteSpace", "normal");
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    style.setProperty("whiteSpace", "");
-                }
-            });
-        }
-
-    }
-
-    private void showAllTabs() {
-        scrollerIndex = 0;
-        Element tr = DOM.getFirstChild(DOM.getFirstChild(tb.getElement()));
-        for (int i = 0; i < tb.getTabCount(); i++) {
-            DOM.setStyleAttribute(DOM.getChild(tr, i), "display", "");
-        }
-    }
-
-    private boolean isScrolledTabs() {
-        return scrollerIndex > 0;
-    }
-
-    private boolean isClippedTabs() {
-        return tb.getOffsetWidth() > getOffsetWidth();
-    }
-
-    @Override
-    protected void clearPaintables() {
-
-        int i = tb.getTabCount();
-        while (i > 0) {
-            tb.removeTab(--i);
-        }
-        tp.clear();
-
-    }
-
-    @Override
-    protected Iterator getPaintableIterator() {
-        return tp.iterator();
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (tp.getWidgetIndex(component) < 0) {
-            return false;
-        } else {
-            return true;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        tp.replaceComponent(oldComponent, newComponent);
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        /* Tabsheet does not render its children's captions */
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        if (!isDynamicHeight() && !isDynamicWidth()) {
-            /*
-             * If the height and width has been specified for this container the
-             * child components cannot make the size of the layout change
-             */
-
-            return true;
-        }
-
-        updateOpenTabSize();
-
-        if (renderInformation.updateSize(getElement())) {
-            /*
-             * Size has changed so we let the child components know about the
-             * new size.
-             */
-            iLayout();
-            client.runDescendentsLayout(this);
-
-            return false;
-        } else {
-            /*
-             * Size has not changed so we do not need to propagate the event
-             * further
-             */
-            return true;
-        }
-
-    }
-
-    private int borderW = -1;
-
-    private int getContentAreaBorderWidth() {
-        if (borderW < 0) {
-            borderW = Util.measureHorizontalBorder(contentNode);
-        }
-        return borderW;
-    }
-
-    private RenderSpace renderSpace = new RenderSpace(0, 0, true);
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        // All tabs have equal amount of space allocated
-        return renderSpace;
-    }
-
-    @Override
-    protected int getTabCount() {
-        return tb.getWidgetCount();
-    }
-
-    @Override
-    protected Paintable getTab(int index) {
-        if (tp.getWidgetCount() > index) {
-            return (Paintable) tp.getWidget(index);
-        }
-        return null;
-    }
-
-    @Override
-    protected void removeTab(int index) {
-        tb.removeTab(index);
-        /*
-         * This must be checked because renderTab automatically removes the
-         * active tab content when it changes
-         */
-        if (tp.getWidgetCount() > index) {
-            tp.remove(index);
-        }
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITabsheetBase.java b/src/com/vaadin/terminal/gwt/client/ui/ITabsheetBase.java
deleted file mode 100644 (file)
index 081f597..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.ui.ComplexPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-abstract class ITabsheetBase extends ComplexPanel implements Container {
-
-    String id;
-    ApplicationConnection client;
-
-    protected final ArrayList tabKeys = new ArrayList();
-    protected int activeTabIndex = 0;
-    protected boolean disabled;
-    protected boolean readonly;
-    protected Set disabledTabKeys = new HashSet();
-    protected boolean cachedUpdate = false;
-
-    public ITabsheetBase(String classname) {
-        setElement(DOM.createDiv());
-        setStylePrimaryName(classname);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-
-        // Ensure correct implementation
-        cachedUpdate = client.updateComponent(this, uidl, true);
-        if (cachedUpdate) {
-            return;
-        }
-
-        // Update member references
-        id = uidl.getId();
-        disabled = uidl.hasAttribute("disabled");
-
-        // Render content
-        final UIDL tabs = uidl.getChildUIDL(0);
-
-        // Paintables in the TabSheet before update
-        ArrayList oldPaintables = new ArrayList();
-        for (Iterator iterator = getPaintableIterator(); iterator.hasNext();) {
-            oldPaintables.add(iterator.next());
-        }
-
-        // Clear previous values
-        tabKeys.clear();
-        disabledTabKeys.clear();
-
-        int index = 0;
-        for (final Iterator it = tabs.getChildIterator(); it.hasNext();) {
-            final UIDL tab = (UIDL) it.next();
-            final String key = tab.getStringAttribute("key");
-            final boolean selected = tab.getBooleanAttribute("selected");
-            final boolean hidden = tab.getBooleanAttribute("hidden");
-
-            if (tab.getBooleanAttribute("disabled")) {
-                disabledTabKeys.add(key);
-            }
-
-            tabKeys.add(key);
-
-            if (selected) {
-                activeTabIndex = index;
-            }
-            renderTab(tab, index, selected, hidden);
-            index++;
-        }
-
-        int tabCount = getTabCount();
-        while (tabCount-- > index) {
-            removeTab(index);
-        }
-
-        for (int i = 0; i < getTabCount(); i++) {
-            Paintable p = getTab(i);
-            oldPaintables.remove(p);
-        }
-
-        // Perform unregister for any paintables removed during update
-        for (Iterator iterator = oldPaintables.iterator(); iterator.hasNext();) {
-            Object oldPaintable = iterator.next();
-            if (oldPaintable instanceof Paintable) {
-                Widget w = (Widget) oldPaintable;
-                if (w.isAttached()) {
-                    w.removeFromParent();
-                }
-                client.unregisterPaintable((Paintable) oldPaintable);
-            }
-        }
-
-    }
-
-    /**
-     * @return a list of currently shown Paintables
-     */
-    abstract protected Iterator getPaintableIterator();
-
-    /**
-     * Clears current tabs and contents
-     */
-    abstract protected void clearPaintables();
-
-    /**
-     * Implement in extending classes. This method should render needed elements
-     * and set the visibility of the tab according to the 'selected' parameter.
-     */
-    protected abstract void renderTab(final UIDL tabUidl, int index,
-            boolean selected, boolean hidden);
-
-    /**
-     * Implement in extending classes. This method should render any previously
-     * non-cached content and set the activeTabIndex property to the specified
-     * index.
-     */
-    protected abstract void selectTab(int index, final UIDL contentUidl);
-
-    /**
-     * Implement in extending classes. This method should return the number of
-     * tabs currently rendered.
-     */
-    protected abstract int getTabCount();
-
-    /**
-     * Implement in extending classes. This method should return the Paintable
-     * corresponding to the given index.
-     */
-    protected abstract Paintable getTab(int index);
-
-    /**
-     * Implement in extending classes. This method should remove the rendered
-     * tab with the specified index.
-     */
-    protected abstract void removeTab(int index);
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITabsheetPanel.java b/src/com/vaadin/terminal/gwt/client/ui/ITabsheetPanel.java
deleted file mode 100644 (file)
index 776e06b..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.Element;\r
-import com.google.gwt.user.client.ui.ComplexPanel;\r
-import com.google.gwt.user.client.ui.Widget;\r
-import com.vaadin.terminal.gwt.client.Util;\r
-\r
-/**\r
- * A panel that displays all of its child widgets in a 'deck', where only one\r
- * can be visible at a time. It is used by\r
- * {@link com.vaadin.terminal.gwt.client.ui.ITabsheet}.\r
- * \r
- * This class has the same basic functionality as the GWT DeckPanel\r
- * {@link com.google.gwt.user.client.ui.DeckPanel}, with the exception that it\r
- * doesn't manipulate the child widgets' width and height attributes.\r
- */\r
-public class ITabsheetPanel extends ComplexPanel {\r
-\r
-    private Widget visibleWidget;\r
-\r
-    /**\r
-     * Creates an empty tabsheet panel.\r
-     */\r
-    public ITabsheetPanel() {\r
-        setElement(DOM.createDiv());\r
-    }\r
-\r
-    /**\r
-     * Adds the specified widget to the deck.\r
-     * \r
-     * @param w\r
-     *            the widget to be added\r
-     */\r
-    @Override\r
-    public void add(Widget w) {\r
-        Element el = createContainerElement();\r
-        DOM.appendChild(getElement(), el);\r
-        super.add(w, el);\r
-    }\r
-\r
-    private Element createContainerElement() {\r
-        Element el = DOM.createDiv();\r
-        DOM.setStyleAttribute(el, "position", "absolute");\r
-        DOM.setStyleAttribute(el, "overflow", "auto");\r
-        hide(el);\r
-        return el;\r
-    }\r
-\r
-    /**\r
-     * Gets the index of the currently-visible widget.\r
-     * \r
-     * @return the visible widget's index\r
-     */\r
-    public int getVisibleWidget() {\r
-        return getWidgetIndex(visibleWidget);\r
-    }\r
-\r
-    /**\r
-     * Inserts a widget before the specified index.\r
-     * \r
-     * @param w\r
-     *            the widget to be inserted\r
-     * @param beforeIndex\r
-     *            the index before which it will be inserted\r
-     * @throws IndexOutOfBoundsException\r
-     *             if <code>beforeIndex</code> is out of range\r
-     */\r
-    public void insert(Widget w, int beforeIndex) {\r
-        Element el = createContainerElement();\r
-        DOM.insertChild(getElement(), el, beforeIndex);\r
-        super.insert(w, el, beforeIndex, false);\r
-    }\r
-\r
-    @Override\r
-    public boolean remove(Widget w) {\r
-        Element child = w.getElement();\r
-        Element parent = null;\r
-        if (child != null) {\r
-            parent = DOM.getParent(child);\r
-        }\r
-        final boolean removed = super.remove(w);\r
-        if (removed) {\r
-            if (visibleWidget == w) {\r
-                visibleWidget = null;\r
-            }\r
-            if (parent != null) {\r
-                DOM.removeChild(getElement(), parent);\r
-            }\r
-        }\r
-        return removed;\r
-    }\r
-\r
-    /**\r
-     * Shows the widget at the specified index. This causes the currently-\r
-     * visible widget to be hidden.\r
-     * \r
-     * @param index\r
-     *            the index of the widget to be shown\r
-     */\r
-    public void showWidget(int index) {\r
-        checkIndexBoundsForAccess(index);\r
-        Widget newVisible = getWidget(index);\r
-        if (visibleWidget != newVisible) {\r
-            if (visibleWidget != null) {\r
-                hide(DOM.getParent(visibleWidget.getElement()));\r
-            }\r
-            visibleWidget = newVisible;\r
-            unHide(DOM.getParent(visibleWidget.getElement()));\r
-        }\r
-    }\r
-\r
-    private void hide(Element e) {\r
-        DOM.setStyleAttribute(e, "visibility", "hidden");\r
-        DOM.setStyleAttribute(e, "top", "-100000px");\r
-        DOM.setStyleAttribute(e, "left", "-100000px");\r
-    }\r
-\r
-    private void unHide(Element e) {\r
-        DOM.setStyleAttribute(e, "top", "0px");\r
-        DOM.setStyleAttribute(e, "left", "0px");\r
-        DOM.setStyleAttribute(e, "visibility", "");\r
-    }\r
-\r
-    public void fixVisibleTabSize(int width, int height, int minWidth) {\r
-        if (visibleWidget == null) {\r
-            return;\r
-        }\r
-\r
-        boolean dynamicHeight = false;\r
-\r
-        if (height < 0) {\r
-            height = visibleWidget.getOffsetHeight();\r
-            dynamicHeight = true;\r
-        }\r
-        if (width < 0) {\r
-            width = visibleWidget.getOffsetWidth();\r
-        }\r
-        if (width < minWidth) {\r
-            width = minWidth;\r
-        }\r
-\r
-        Element wrapperDiv = (Element) visibleWidget.getElement()\r
-                .getParentElement();\r
-\r
-        // width first\r
-        getElement().getStyle().setPropertyPx("width", width);\r
-        wrapperDiv.getStyle().setPropertyPx("width", width);\r
-\r
-        if (dynamicHeight) {\r
-            // height of widget might have changed due wrapping\r
-            height = visibleWidget.getOffsetHeight();\r
-        }\r
-        // i-tabsheet-tabsheetpanel height\r
-        getElement().getStyle().setPropertyPx("height", height);\r
-\r
-        // widget wrapper height\r
-        wrapperDiv.getStyle().setPropertyPx("height", height);\r
-        runWebkitOverflowAutoFix();\r
-    }\r
-\r
-    public void runWebkitOverflowAutoFix() {\r
-        if (visibleWidget != null) {\r
-            Util.runWebkitOverflowAutoFix(DOM.getParent(visibleWidget\r
-                    .getElement()));\r
-        }\r
-\r
-    }\r
-\r
-    public void replaceComponent(Widget oldComponent, Widget newComponent) {\r
-        boolean isVisible = (visibleWidget == oldComponent);\r
-        int widgetIndex = getWidgetIndex(oldComponent);\r
-        remove(oldComponent);\r
-        insert(newComponent, widgetIndex);\r
-        if (isVisible) {\r
-            showWidget(widgetIndex);\r
-        }\r
-    }\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITextArea.java b/src/com/vaadin/terminal/gwt/client/ui/ITextArea.java
deleted file mode 100644 (file)
index 7a03f85..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import com.google.gwt.user.client.Command;\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.DeferredCommand;\r
-import com.google.gwt.user.client.Element;\r
-import com.google.gwt.user.client.Event;\r
-import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-/**\r
- * This class represents a multiline textfield (textarea).\r
- * \r
- * TODO consider replacing this with a RichTextArea based implementation. IE\r
- * does not support CSS height for textareas in Strict mode :-(\r
- * \r
- * @author IT Mill Ltd.\r
- * \r
- */\r
-public class ITextArea extends ITextField {\r
-    public static final String CLASSNAME = "i-textarea";\r
-\r
-    public ITextArea() {\r
-        super(DOM.createTextArea());\r
-        setStyleName(CLASSNAME);\r
-    }\r
-\r
-    @Override\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-        // Call parent renderer explicitly\r
-        super.updateFromUIDL(uidl, client);\r
-\r
-        if (uidl.hasAttribute("rows")) {\r
-            setRows(new Integer(uidl.getStringAttribute("rows")).intValue());\r
-        }\r
-\r
-        if (getMaxLength() >= 0) {\r
-            sinkEvents(Event.ONKEYPRESS);\r
-        }\r
-    }\r
-\r
-    public void setRows(int rows) {\r
-        setRows(getElement(), rows);\r
-    }\r
-\r
-    private native void setRows(Element e, int r)\r
-    /*-{\r
-    try {\r
-        if(e.tagName.toLowerCase() == "textarea")\r
-                e.rows = r;\r
-    } catch (e) {}\r
-    }-*/;\r
-\r
-    @Override\r
-    public void onBrowserEvent(Event event) {\r
-        if (getMaxLength() >= 0 && event.getTypeInt() == Event.ONKEYPRESS) {\r
-            DeferredCommand.addCommand(new Command() {\r
-                public void execute() {\r
-                    if (getText().length() > getMaxLength()) {\r
-                        setText(getText().substring(0, getMaxLength()));\r
-                    }\r
-                }\r
-            });\r
-        }\r
-        super.onBrowserEvent(event);\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITextField.java b/src/com/vaadin/terminal/gwt/client/ui/ITextField.java
deleted file mode 100644 (file)
index 74cd1cf..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.ChangeListener;
-import com.google.gwt.user.client.ui.FocusListener;
-import com.google.gwt.user.client.ui.TextBoxBase;
-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.ITooltip;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-/**
- * This class represents a basic text input field with one row.
- * 
- * @author IT Mill Ltd.
- * 
- */
-public class ITextField extends TextBoxBase implements Paintable, Field,
-        ChangeListener, FocusListener {
-
-    /**
-     * The input node CSS classname.
-     */
-    public static final String CLASSNAME = "i-textfield";
-    /**
-     * This CSS classname is added to the input node on hover.
-     */
-    public static final String CLASSNAME_FOCUS = "focus";
-
-    protected String id;
-
-    protected ApplicationConnection client;
-
-    private String valueBeforeEdit = null;
-
-    private boolean immediate = false;
-    private int extraHorizontalPixels = -1;
-    private int extraVerticalPixels = -1;
-    private int maxLength = -1;
-
-    private static final String CLASSNAME_PROMPT = "prompt";
-    private static final String ATTR_INPUTPROMPT = "prompt";
-    private String inputPrompt = null;
-    private boolean prompting = false;
-
-    public ITextField() {
-        this(DOM.createInputText());
-    }
-
-    protected ITextField(Element node) {
-        super(node);
-        if (BrowserInfo.get().isIE()) {
-            // Fixes IE margin problem (#2058)
-            DOM.setStyleAttribute(node, "marginTop", "-1px");
-            DOM.setStyleAttribute(node, "marginBottom", "-1px");
-        }
-        setStyleName(CLASSNAME);
-        addChangeListener(this);
-        addFocusListener(this);
-        sinkEvents(ITooltip.TOOLTIP_EVENTS);
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        if (client != null) {
-            client.handleTooltipEvent(event, this);
-        }
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-        id = uidl.getId();
-
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        if (uidl.getBooleanAttribute("readonly")) {
-            setReadOnly(true);
-        } else {
-            setReadOnly(false);
-        }
-
-        inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
-
-        setMaxLength(uidl.hasAttribute("maxLength") ? uidl
-                .getIntAttribute("maxLength") : -1);
-
-        immediate = uidl.getBooleanAttribute("immediate");
-
-        if (uidl.hasAttribute("cols")) {
-            setColumns(new Integer(uidl.getStringAttribute("cols")).intValue());
-        }
-
-        String text = uidl.getStringVariable("text");
-        prompting = inputPrompt != null && (text == null || text.equals(""));
-        if (prompting) {
-            setText(inputPrompt);
-            addStyleDependentName(CLASSNAME_PROMPT);
-        } else {
-            setText(text);
-            removeStyleDependentName(CLASSNAME_PROMPT);
-        }
-        valueBeforeEdit = uidl.getStringVariable("text");
-    }
-
-    private void setMaxLength(int newMaxLength) {
-        if (newMaxLength > 0) {
-            maxLength = newMaxLength;
-            if (getElement().getTagName().toLowerCase().equals("textarea")) {
-                // NOP no maxlength property for textarea
-            } else {
-                getElement().setPropertyInt("maxLength", maxLength);
-            }
-        } else if (maxLength != -1) {
-            if (getElement().getTagName().toLowerCase().equals("textarea")) {
-                // NOP no maxlength property for textarea
-            } else {
-                getElement().setAttribute("maxlength", "");
-            }
-            maxLength = -1;
-        }
-
-    }
-
-    protected int getMaxLength() {
-        return maxLength;
-    }
-
-    public void onChange(Widget sender) {
-        if (client != null && id != null) {
-            String newText = getText();
-            if (!prompting && newText != null
-                    && !newText.equals(valueBeforeEdit)) {
-                client.updateVariable(id, "text", getText(), immediate);
-                valueBeforeEdit = newText;
-            }
-        }
-    }
-
-    private static ITextField focusedTextField;
-
-    public static void flushChangesFromFocusedTextField() {
-        if (focusedTextField != null) {
-            focusedTextField.onChange(null);
-        }
-    }
-
-    public void onFocus(Widget sender) {
-        addStyleDependentName(CLASSNAME_FOCUS);
-        if (prompting) {
-            setText("");
-            removeStyleDependentName(CLASSNAME_PROMPT);
-        }
-        focusedTextField = this;
-    }
-
-    public void onLostFocus(Widget sender) {
-        removeStyleDependentName(CLASSNAME_FOCUS);
-        focusedTextField = null;
-        String text = getText();
-        prompting = inputPrompt != null && (text == null || "".equals(text));
-        if (prompting) {
-            setText(inputPrompt);
-            addStyleDependentName(CLASSNAME_PROMPT);
-        }
-        onChange(sender);
-    }
-
-    public void setColumns(int columns) {
-        setColumns(getElement(), columns);
-    }
-
-    private native void setColumns(Element e, int c)
-    /*-{
-    try {
-       switch(e.tagName.toLowerCase()) {
-               case "input":
-                       //e.size = c;
-                       e.style.width = c+"em";
-                       break;
-               case "textarea":
-                       //e.cols = c;
-                       e.style.width = c+"em";
-                       break;
-               default:;
-       }
-    } catch (e) {}
-    }-*/;
-
-    /**
-     * @return space used by components paddings and borders
-     */
-    private int getExtraHorizontalPixels() {
-        if (extraHorizontalPixels < 0) {
-            detectExtraSizes();
-        }
-        return extraHorizontalPixels;
-    }
-
-    /**
-     * @return space used by components paddings and borders
-     */
-    private int getExtraVerticalPixels() {
-        if (extraVerticalPixels < 0) {
-            detectExtraSizes();
-        }
-        return extraVerticalPixels;
-    }
-
-    /**
-     * Detects space used by components paddings and borders. Used when
-     * relational size are used.
-     */
-    private void detectExtraSizes() {
-        Element clone = Util.cloneNode(getElement(), false);
-        DOM.setElementAttribute(clone, "id", "");
-        DOM.setStyleAttribute(clone, "visibility", "hidden");
-        DOM.setStyleAttribute(clone, "position", "absolute");
-        // due FF3 bug set size to 10px and later subtract it from extra pixels
-        DOM.setStyleAttribute(clone, "width", "10px");
-        DOM.setStyleAttribute(clone, "height", "10px");
-        DOM.appendChild(DOM.getParent(getElement()), clone);
-        extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10;
-        extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10;
-
-        DOM.removeChild(DOM.getParent(getElement()), clone);
-    }
-
-    @Override
-    public void setHeight(String height) {
-        if (height.endsWith("px")) {
-            int h = Integer.parseInt(height.substring(0, height.length() - 2));
-            h -= getExtraVerticalPixels();
-            if (h < 0) {
-                h = 0;
-            }
-
-            super.setHeight(h + "px");
-        } else {
-            super.setHeight(height);
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (width.endsWith("px")) {
-            int w = Integer.parseInt(width.substring(0, width.length() - 2));
-            w -= getExtraHorizontalPixels();
-            if (w < 0) {
-                w = 0;
-            }
-
-            super.setWidth(w + "px");
-        } else {
-            super.setWidth(width);
-        }
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITextualDate.java b/src/com/vaadin/terminal/gwt/client/ui/ITextualDate.java
deleted file mode 100644 (file)
index 311390c..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Date;\r
-\r
-import com.google.gwt.i18n.client.DateTimeFormat;\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.ui.ChangeListener;\r
-import com.google.gwt.user.client.ui.TextBox;\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.ClientExceptionHandler;\r
-import com.vaadin.terminal.gwt.client.ContainerResizedListener;\r
-import com.vaadin.terminal.gwt.client.Focusable;\r
-import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;\r
-import com.vaadin.terminal.gwt.client.LocaleService;\r
-import com.vaadin.terminal.gwt.client.Paintable;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class ITextualDate extends IDateField implements Paintable, Field,\r
-        ChangeListener, ContainerResizedListener, Focusable {\r
-\r
-    private static final String PARSE_ERROR_CLASSNAME = CLASSNAME\r
-            + "-parseerror";\r
-\r
-    private final TextBox text;\r
-\r
-    private String formatStr;\r
-\r
-    private String width;\r
-\r
-    private boolean needLayout;\r
-\r
-    protected int fieldExtraWidth = -1;\r
-\r
-    public ITextualDate() {\r
-        super();\r
-        text = new TextBox();\r
-        // use normal textfield styles as a basis\r
-        text.setStyleName(ITextField.CLASSNAME);\r
-        // add datefield spesific style name also\r
-        text.addStyleName(CLASSNAME + "-textfield");\r
-        text.addChangeListener(this);\r
-        add(text);\r
-    }\r
-\r
-    @Override\r
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-\r
-        int origRes = currentResolution;\r
-        super.updateFromUIDL(uidl, client);\r
-        if (origRes != currentResolution) {\r
-            // force recreating format string\r
-            formatStr = null;\r
-        }\r
-        if (uidl.hasAttribute("format")) {\r
-            formatStr = uidl.getStringAttribute("format");\r
-        }\r
-\r
-        buildDate();\r
-        // not a FocusWidget -> needs own tabindex handling\r
-        if (uidl.hasAttribute("tabindex")) {\r
-            text.setTabIndex(uidl.getIntAttribute("tabindex"));\r
-        }\r
-    }\r
-\r
-    protected String getFormatString() {\r
-        if (formatStr == null) {\r
-            if (currentResolution == RESOLUTION_YEAR) {\r
-                formatStr = "yyyy"; // force full year\r
-            } else {\r
-\r
-                try {\r
-                    String frmString = LocaleService\r
-                            .getDateFormat(currentLocale);\r
-                    frmString = cleanFormat(frmString);\r
-                    String delim = LocaleService\r
-                            .getClockDelimiter(currentLocale);\r
-\r
-                    if (currentResolution >= RESOLUTION_HOUR) {\r
-                        if (dts.isTwelveHourClock()) {\r
-                            frmString += " hh";\r
-                        } else {\r
-                            frmString += " HH";\r
-                        }\r
-                        if (currentResolution >= RESOLUTION_MIN) {\r
-                            frmString += ":mm";\r
-                            if (currentResolution >= RESOLUTION_SEC) {\r
-                                frmString += ":ss";\r
-                                if (currentResolution >= RESOLUTION_MSEC) {\r
-                                    frmString += ".SSS";\r
-                                }\r
-                            }\r
-                        }\r
-                        if (dts.isTwelveHourClock()) {\r
-                            frmString += " aaa";\r
-                        }\r
-\r
-                    }\r
-\r
-                    formatStr = frmString;\r
-                } catch (LocaleNotLoadedException e) {\r
-                    ClientExceptionHandler.displayError(e);\r
-                }\r
-            }\r
-        }\r
-        return formatStr;\r
-    }\r
-\r
-    /**\r
-     * \r
-     */\r
-    protected void buildDate() {\r
-        removeStyleName(PARSE_ERROR_CLASSNAME);\r
-        // Create the initial text for the textfield\r
-        String dateText;\r
-        if (date != null) {\r
-            dateText = DateTimeFormat.getFormat(getFormatString()).format(date);\r
-        } else {\r
-            dateText = "";\r
-        }\r
-\r
-        text.setText(dateText);\r
-        text.setEnabled(enabled && !readonly);\r
-\r
-        if (readonly) {\r
-            text.addStyleName("i-readonly");\r
-        } else {\r
-            text.removeStyleName("i-readonly");\r
-        }\r
-\r
-    }\r
-\r
-    public void onChange(Widget sender) {\r
-        if (sender == text) {\r
-            if (!text.getText().equals("")) {\r
-                try {\r
-                    DateTimeFormat format = DateTimeFormat\r
-                            .getFormat(getFormatString());\r
-                    date = format.parse(text.getText());\r
-                    long stamp = date.getTime();\r
-                    if (stamp == 0) {\r
-                        // If date parsing fails in firefox the stamp will be 0\r
-                        date = null;\r
-                        addStyleName(PARSE_ERROR_CLASSNAME);\r
-                    } else {\r
-                        // remove possibly added invalid value indication\r
-                        removeStyleName(PARSE_ERROR_CLASSNAME);\r
-                    }\r
-                } catch (final Exception e) {\r
-                    ClientExceptionHandler.displayError(e.getMessage());\r
-\r
-                    addStyleName(PARSE_ERROR_CLASSNAME);\r
-                    // this is a hack that may eventually be removed\r
-                    client.updateVariable(id, "lastInvalidDateString", text\r
-                            .getText(), false);\r
-                    date = null;\r
-                }\r
-            } else {\r
-                date = null;\r
-                // remove possibly added invalid value indication\r
-                removeStyleName(PARSE_ERROR_CLASSNAME);\r
-            }\r
-            // always send the date string\r
-            client.updateVariable(id, "dateString", text.getText(), false);\r
-\r
-            if (date != null) {\r
-                showingDate = new Date(date.getTime());\r
-            }\r
-\r
-            // Update variables\r
-            // (only the smallest defining resolution needs to be\r
-            // immediate)\r
-            client.updateVariable(id, "year",\r
-                    date != null ? date.getYear() + 1900 : -1,\r
-                    currentResolution == IDateField.RESOLUTION_YEAR\r
-                            && immediate);\r
-            if (currentResolution >= IDateField.RESOLUTION_MONTH) {\r
-                client.updateVariable(id, "month", date != null ? date\r
-                        .getMonth() + 1 : -1,\r
-                        currentResolution == IDateField.RESOLUTION_MONTH\r
-                                && immediate);\r
-            }\r
-            if (currentResolution >= IDateField.RESOLUTION_DAY) {\r
-                client.updateVariable(id, "day", date != null ? date.getDate()\r
-                        : -1, currentResolution == IDateField.RESOLUTION_DAY\r
-                        && immediate);\r
-            }\r
-            if (currentResolution >= IDateField.RESOLUTION_HOUR) {\r
-                client.updateVariable(id, "hour", date != null ? date\r
-                        .getHours() : -1,\r
-                        currentResolution == IDateField.RESOLUTION_HOUR\r
-                                && immediate);\r
-            }\r
-            if (currentResolution >= IDateField.RESOLUTION_MIN) {\r
-                client.updateVariable(id, "min", date != null ? date\r
-                        .getMinutes() : -1,\r
-                        currentResolution == IDateField.RESOLUTION_MIN\r
-                                && immediate);\r
-            }\r
-            if (currentResolution >= IDateField.RESOLUTION_SEC) {\r
-                client.updateVariable(id, "sec", date != null ? date\r
-                        .getSeconds() : -1,\r
-                        currentResolution == IDateField.RESOLUTION_SEC\r
-                                && immediate);\r
-            }\r
-            if (currentResolution == IDateField.RESOLUTION_MSEC) {\r
-                client.updateVariable(id, "msec",\r
-                        date != null ? getMilliseconds() : -1, immediate);\r
-            }\r
-\r
-        }\r
-    }\r
-\r
-    private String cleanFormat(String format) {\r
-        // Remove unnecessary d & M if resolution is too low\r
-        if (currentResolution < IDateField.RESOLUTION_DAY) {\r
-            format = format.replaceAll("d", "");\r
-        }\r
-        if (currentResolution < IDateField.RESOLUTION_MONTH) {\r
-            format = format.replaceAll("M", "");\r
-        }\r
-\r
-        // Remove unsupported patterns\r
-        // TODO support for 'G', era designator (used at least in Japan)\r
-        format = format.replaceAll("[GzZwWkK]", "");\r
-\r
-        // Remove extra delimiters ('/' and '.')\r
-        while (format.startsWith("/") || format.startsWith(".")\r
-                || format.startsWith("-")) {\r
-            format = format.substring(1);\r
-        }\r
-        while (format.endsWith("/") || format.endsWith(".")\r
-                || format.endsWith("-")) {\r
-            format = format.substring(0, format.length() - 1);\r
-        }\r
-\r
-        // Remove duplicate delimiters\r
-        format = format.replaceAll("//", "/");\r
-        format = format.replaceAll("\\.\\.", ".");\r
-        format = format.replaceAll("--", "-");\r
-\r
-        return format.trim();\r
-    }\r
-\r
-    @Override\r
-    public void setWidth(String newWidth) {\r
-        if (!"".equals(newWidth) && (width == null || !newWidth.equals(width))) {\r
-            if (BrowserInfo.get().isIE6()) {\r
-                // in IE6 cols ~ min-width\r
-                DOM.setElementProperty(text.getElement(), "size", "1");\r
-            }\r
-            needLayout = true;\r
-            width = newWidth;\r
-            super.setWidth(width);\r
-            iLayout();\r
-            if (newWidth.indexOf("%") < 0) {\r
-                needLayout = false;\r
-            }\r
-        } else {\r
-            if ("".equals(newWidth) && width != null && !"".equals(width)) {\r
-                if (BrowserInfo.get().isIE6()) {\r
-                    // revert IE6 hack\r
-                    DOM.setElementProperty(text.getElement(), "size", "");\r
-                }\r
-                super.setWidth("");\r
-                needLayout = true;\r
-                iLayout();\r
-                needLayout = false;\r
-                width = null;\r
-            }\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Returns pixels in x-axis reserved for other than textfield content.\r
-     * \r
-     * @return extra width in pixels\r
-     */\r
-    protected int getFieldExtraWidth() {\r
-        if (fieldExtraWidth < 0) {\r
-            text.setWidth("0px");\r
-            fieldExtraWidth = text.getOffsetWidth();\r
-        }\r
-        return fieldExtraWidth;\r
-    }\r
-\r
-    public void iLayout() {\r
-        if (needLayout) {\r
-            text.setWidth((getOffsetWidth() - getFieldExtraWidth()) + "px");\r
-        }\r
-    }\r
-\r
-    public void focus() {\r
-        text.setFocus(true);\r
-    }\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITime.java b/src/com/vaadin/terminal/gwt/client/ui/ITime.java
deleted file mode 100644 (file)
index 43c1f9f..0000000
+++ /dev/null
@@ -1,317 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Date;\r
-\r
-import com.google.gwt.user.client.ui.ChangeListener;\r
-import com.google.gwt.user.client.ui.FlowPanel;\r
-import com.google.gwt.user.client.ui.ListBox;\r
-import com.google.gwt.user.client.ui.Widget;\r
-\r
-public class ITime extends FlowPanel implements ChangeListener {\r
-\r
-    private final IDateField datefield;\r
-\r
-    private ListBox hours;\r
-\r
-    private ListBox mins;\r
-\r
-    private ListBox sec;\r
-\r
-    private ListBox msec;\r
-\r
-    private ListBox ampm;\r
-\r
-    private int resolution = IDateField.RESOLUTION_HOUR;\r
-\r
-    private boolean readonly;\r
-\r
-    public ITime(IDateField parent) {\r
-        super();\r
-        datefield = parent;\r
-        setStyleName(IDateField.CLASSNAME + "-time");\r
-    }\r
-\r
-    private void buildTime(boolean redraw) {\r
-        final boolean thc = datefield.getDateTimeService().isTwelveHourClock();\r
-        if (redraw) {\r
-            clear();\r
-            final int numHours = thc ? 12 : 24;\r
-            hours = new ListBox();\r
-            hours.setStyleName(INativeSelect.CLASSNAME);\r
-            for (int i = 0; i < numHours; i++) {\r
-                hours.addItem((i < 10) ? "0" + i : "" + i);\r
-            }\r
-            hours.addChangeListener(this);\r
-            if (thc) {\r
-                ampm = new ListBox();\r
-                ampm.setStyleName(INativeSelect.CLASSNAME);\r
-                final String[] ampmText = datefield.getDateTimeService()\r
-                        .getAmPmStrings();\r
-                ampm.addItem(ampmText[0]);\r
-                ampm.addItem(ampmText[1]);\r
-                ampm.addChangeListener(this);\r
-            }\r
-\r
-            if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_MIN) {\r
-                mins = new ListBox();\r
-                mins.setStyleName(INativeSelect.CLASSNAME);\r
-                for (int i = 0; i < 60; i++) {\r
-                    mins.addItem((i < 10) ? "0" + i : "" + i);\r
-                }\r
-                mins.addChangeListener(this);\r
-            }\r
-            if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_SEC) {\r
-                sec = new ListBox();\r
-                sec.setStyleName(INativeSelect.CLASSNAME);\r
-                for (int i = 0; i < 60; i++) {\r
-                    sec.addItem((i < 10) ? "0" + i : "" + i);\r
-                }\r
-                sec.addChangeListener(this);\r
-            }\r
-            if (datefield.getCurrentResolution() == IDateField.RESOLUTION_MSEC) {\r
-                msec = new ListBox();\r
-                msec.setStyleName(INativeSelect.CLASSNAME);\r
-                for (int i = 0; i < 1000; i++) {\r
-                    if (i < 10) {\r
-                        msec.addItem("00" + i);\r
-                    } else if (i < 100) {\r
-                        msec.addItem("0" + i);\r
-                    } else {\r
-                        msec.addItem("" + i);\r
-                    }\r
-                }\r
-                msec.addChangeListener(this);\r
-            }\r
-\r
-            final String delimiter = datefield.getDateTimeService()\r
-                    .getClockDelimeter();\r
-            final boolean ro = datefield.isReadonly();\r
-\r
-            if (ro) {\r
-                int h = 0;\r
-                if (datefield.getCurrentDate() != null) {\r
-                    h = datefield.getCurrentDate().getHours();\r
-                }\r
-                if (thc) {\r
-                    h -= h < 12 ? 0 : 12;\r
-                }\r
-                add(new ILabel(h < 10 ? "0" + h : "" + h));\r
-            } else {\r
-                add(hours);\r
-            }\r
-\r
-            if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_MIN) {\r
-                add(new ILabel(delimiter));\r
-                if (ro) {\r
-                    final int m = mins.getSelectedIndex();\r
-                    add(new ILabel(m < 10 ? "0" + m : "" + m));\r
-                } else {\r
-                    add(mins);\r
-                }\r
-            }\r
-            if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_SEC) {\r
-                add(new ILabel(delimiter));\r
-                if (ro) {\r
-                    final int s = sec.getSelectedIndex();\r
-                    add(new ILabel(s < 10 ? "0" + s : "" + s));\r
-                } else {\r
-                    add(sec);\r
-                }\r
-            }\r
-            if (datefield.getCurrentResolution() == IDateField.RESOLUTION_MSEC) {\r
-                add(new ILabel("."));\r
-                if (ro) {\r
-                    final int m = datefield.getMilliseconds();\r
-                    final String ms = m < 100 ? "0" + m : "" + m;\r
-                    add(new ILabel(m < 10 ? "0" + ms : ms));\r
-                } else {\r
-                    add(msec);\r
-                }\r
-            }\r
-            if (datefield.getCurrentResolution() == IDateField.RESOLUTION_HOUR) {\r
-                add(new ILabel(delimiter + "00")); // o'clock\r
-            }\r
-            if (thc) {\r
-                add(new ILabel("&nbsp;"));\r
-                if (ro) {\r
-                    add(new ILabel(ampm.getItemText(datefield.getCurrentDate()\r
-                            .getHours() < 12 ? 0 : 1)));\r
-                } else {\r
-                    add(ampm);\r
-                }\r
-            }\r
-\r
-            if (ro) {\r
-                return;\r
-            }\r
-        }\r
-\r
-        // Update times\r
-        Date cdate = datefield.getCurrentDate();\r
-        boolean selected = true;\r
-        if (cdate == null) {\r
-            cdate = new Date();\r
-            selected = false;\r
-        }\r
-        if (thc) {\r
-            int h = cdate.getHours();\r
-            ampm.setSelectedIndex(h < 12 ? 0 : 1);\r
-            h -= ampm.getSelectedIndex() * 12;\r
-            hours.setSelectedIndex(h);\r
-        } else {\r
-            hours.setSelectedIndex(cdate.getHours());\r
-        }\r
-        if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_MIN) {\r
-            mins.setSelectedIndex(cdate.getMinutes());\r
-        }\r
-        if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_SEC) {\r
-            sec.setSelectedIndex(cdate.getSeconds());\r
-        }\r
-        if (datefield.getCurrentResolution() == IDateField.RESOLUTION_MSEC) {\r
-            if (selected) {\r
-                msec.setSelectedIndex(datefield.getMilliseconds());\r
-            } else {\r
-                msec.setSelectedIndex(0);\r
-            }\r
-        }\r
-        if (thc) {\r
-            ampm.setSelectedIndex(cdate.getHours() < 12 ? 0 : 1);\r
-        }\r
-\r
-        if (datefield.isReadonly() && !redraw) {\r
-            // Do complete redraw when in read-only status\r
-            clear();\r
-            final String delimiter = datefield.getDateTimeService()\r
-                    .getClockDelimeter();\r
-\r
-            int h = cdate.getHours();\r
-            if (thc) {\r
-                h -= h < 12 ? 0 : 12;\r
-            }\r
-            add(new ILabel(h < 10 ? "0" + h : "" + h));\r
-\r
-            if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_MIN) {\r
-                add(new ILabel(delimiter));\r
-                final int m = mins.getSelectedIndex();\r
-                add(new ILabel(m < 10 ? "0" + m : "" + m));\r
-            }\r
-            if (datefield.getCurrentResolution() >= IDateField.RESOLUTION_SEC) {\r
-                add(new ILabel(delimiter));\r
-                final int s = sec.getSelectedIndex();\r
-                add(new ILabel(s < 10 ? "0" + s : "" + s));\r
-            }\r
-            if (datefield.getCurrentResolution() == IDateField.RESOLUTION_MSEC) {\r
-                add(new ILabel("."));\r
-                final int m = datefield.getMilliseconds();\r
-                final String ms = m < 100 ? "0" + m : "" + m;\r
-                add(new ILabel(m < 10 ? "0" + ms : ms));\r
-            }\r
-            if (datefield.getCurrentResolution() == IDateField.RESOLUTION_HOUR) {\r
-                add(new ILabel(delimiter + "00")); // o'clock\r
-            }\r
-            if (thc) {\r
-                add(new ILabel("&nbsp;"));\r
-                add(new ILabel(ampm.getItemText(cdate.getHours() < 12 ? 0 : 1)));\r
-            }\r
-        }\r
-\r
-        final boolean enabled = datefield.isEnabled();\r
-        hours.setEnabled(enabled);\r
-        if (mins != null) {\r
-            mins.setEnabled(enabled);\r
-        }\r
-        if (sec != null) {\r
-            sec.setEnabled(enabled);\r
-        }\r
-        if (msec != null) {\r
-            msec.setEnabled(enabled);\r
-        }\r
-        if (ampm != null) {\r
-            ampm.setEnabled(enabled);\r
-        }\r
-\r
-    }\r
-\r
-    public void updateTime(boolean redraw) {\r
-        buildTime(redraw || resolution != datefield.getCurrentResolution()\r
-                || readonly != datefield.isReadonly());\r
-        if (datefield instanceof ITextualDate) {\r
-            ((ITextualDate) datefield).buildDate();\r
-        }\r
-        resolution = datefield.getCurrentResolution();\r
-        readonly = datefield.isReadonly();\r
-    }\r
-\r
-    public void onChange(Widget sender) {\r
-        if (datefield.getCurrentDate() == null) {\r
-            // was null on server, need to set\r
-            Date now = datefield.getShowingDate();\r
-            if (now == null) {\r
-                now = new Date();\r
-                datefield.setShowingDate(now);\r
-            }\r
-            datefield.setCurrentDate(new Date(now.getTime()));\r
-\r
-            // Init variables with current time\r
-            datefield.getClient().updateVariable(datefield.getId(), "year",\r
-                    now.getYear() + 1900, false);\r
-            datefield.getClient().updateVariable(datefield.getId(), "month",\r
-                    now.getMonth() + 1, false);\r
-            datefield.getClient().updateVariable(datefield.getId(), "day",\r
-                    now.getDate(), false);\r
-            datefield.getClient().updateVariable(datefield.getId(), "hour",\r
-                    now.getHours(), false);\r
-            datefield.getClient().updateVariable(datefield.getId(), "min",\r
-                    now.getMinutes(), false);\r
-            datefield.getClient().updateVariable(datefield.getId(), "sec",\r
-                    now.getSeconds(), false);\r
-            datefield.getClient().updateVariable(datefield.getId(), "msec",\r
-                    datefield.getMilliseconds(), false);\r
-        }\r
-        if (sender == hours) {\r
-            int h = hours.getSelectedIndex();\r
-            if (datefield.getDateTimeService().isTwelveHourClock()) {\r
-                h = h + ampm.getSelectedIndex() * 12;\r
-            }\r
-            datefield.getCurrentDate().setHours(h);\r
-            datefield.getShowingDate().setHours(h);\r
-            datefield.getClient().updateVariable(datefield.getId(), "hour", h,\r
-                    datefield.isImmediate());\r
-            updateTime(false);\r
-        } else if (sender == mins) {\r
-            final int m = mins.getSelectedIndex();\r
-            datefield.getCurrentDate().setMinutes(m);\r
-            datefield.getShowingDate().setMinutes(m);\r
-            datefield.getClient().updateVariable(datefield.getId(), "min", m,\r
-                    datefield.isImmediate());\r
-            updateTime(false);\r
-        } else if (sender == sec) {\r
-            final int s = sec.getSelectedIndex();\r
-            datefield.getCurrentDate().setSeconds(s);\r
-            datefield.getShowingDate().setSeconds(s);\r
-            datefield.getClient().updateVariable(datefield.getId(), "sec", s,\r
-                    datefield.isImmediate());\r
-            updateTime(false);\r
-        } else if (sender == msec) {\r
-            final int ms = msec.getSelectedIndex();\r
-            datefield.setMilliseconds(ms);\r
-            datefield.setShowingMilliseconds(ms);\r
-            datefield.getClient().updateVariable(datefield.getId(), "msec", ms,\r
-                    datefield.isImmediate());\r
-            updateTime(false);\r
-        } else if (sender == ampm) {\r
-            final int h = hours.getSelectedIndex() + ampm.getSelectedIndex()\r
-                    * 12;\r
-            datefield.getCurrentDate().setHours(h);\r
-            datefield.getShowingDate().setHours(h);\r
-            datefield.getClient().updateVariable(datefield.getId(), "hour", h,\r
-                    datefield.isImmediate());\r
-            updateTime(false);\r
-        }\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IToolkitOverlay.java b/src/com/vaadin/terminal/gwt/client/ui/IToolkitOverlay.java
deleted file mode 100644 (file)
index 8399544..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.animation.client.Animation;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.PopupListener;
-import com.google.gwt.user.client.ui.PopupPanel;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-
-/**
- * In Toolkit UI this Overlay should always be used for all elements that
- * temporary float over other components like context menus etc. This is to deal
- * stacking order correctly with IWindow objects.
- */
-public class IToolkitOverlay extends PopupPanel {
-
-    /*
-     * The z-index value from where all overlays live. This can be overridden in
-     * any extending class.
-     */
-    protected static int Z_INDEX = 20000;
-
-    /*
-     * Shadow element style. If an extending class wishes to use a different
-     * style of shadow, it can use setShadowStyle(String) to give the shadow
-     * element a new style name.
-     */
-    public static final String CLASSNAME_SHADOW = "i-shadow";
-
-    /*
-     * The shadow element for this overlay.
-     */
-    private Element shadow;
-
-    /**
-     * The HTML snippet that is used to render the actual shadow. In consists of
-     * nine different DIV-elements with the following class names:
-     * 
-     * <pre>
-     *   .i-shadow[-stylename]
-     *   ----------------------------------------------
-     *   | .top-left     |   .top    |     .top-right |
-     *   |---------------|-----------|----------------|
-     *   |               |           |                |
-     *   | .left         |  .center  |         .right |
-     *   |               |           |                |
-     *   |---------------|-----------|----------------|
-     *   | .bottom-left  |  .bottom  |  .bottom-right |
-     *   ----------------------------------------------
-     * </pre>
-     * 
-     * See default theme 'shadow.css' for implementation example.
-     */
-    private static final String SHADOW_HTML = "<div class=\"top-left\"></div><div class=\"top\"></div><div class=\"top-right\"></div><div class=\"left\"></div><div class=\"center\"></div><div class=\"right\"></div><div class=\"bottom-left\"></div><div class=\"bottom\"></div><div class=\"bottom-right\"></div>";
-
-    public IToolkitOverlay() {
-        super();
-        adjustZIndex();
-    }
-
-    public IToolkitOverlay(boolean autoHide) {
-        super(autoHide);
-        adjustZIndex();
-    }
-
-    public IToolkitOverlay(boolean autoHide, boolean modal) {
-        super(autoHide, modal);
-        adjustZIndex();
-    }
-
-    public IToolkitOverlay(boolean autoHide, boolean modal, boolean showShadow) {
-        super(autoHide, modal);
-        if (showShadow) {
-            shadow = DOM.createDiv();
-            shadow.setClassName(CLASSNAME_SHADOW);
-            shadow.setInnerHTML(SHADOW_HTML);
-            DOM.setStyleAttribute(shadow, "position", "absolute");
-
-            addPopupListener(new PopupListener() {
-                public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
-                    if (shadow.getParentElement() != null) {
-                        shadow.getParentElement().removeChild(shadow);
-                    }
-                }
-            });
-        }
-        adjustZIndex();
-    }
-
-    private void adjustZIndex() {
-        setZIndex(Z_INDEX);
-    }
-
-    /**
-     * Set the z-index (visual stack position) for this overlay.
-     * 
-     * @param zIndex
-     *            The new z-index
-     */
-    protected void setZIndex(int zIndex) {
-        DOM.setStyleAttribute(getElement(), "zIndex", "" + zIndex);
-        if (shadow != null) {
-            DOM.setStyleAttribute(shadow, "zIndex", "" + zIndex);
-        }
-        if (BrowserInfo.get().isIE6()) {
-            adjustIE6Frame(getElement(), zIndex - 1);
-        }
-    }
-
-    /**
-     * Get the z-index (visual stack position) of this overlay.
-     * 
-     * @return The z-index for this overlay.
-     */
-    private int getZIndex() {
-        return Integer.parseInt(DOM.getStyleAttribute(getElement(), "zIndex"));
-    }
-
-    @Override
-    public void setPopupPosition(int left, int top) {
-        super.setPopupPosition(left, top);
-        if (shadow != null) {
-            updateShadowSizeAndPosition(isAnimationEnabled() ? 0 : 1);
-        }
-    }
-
-    @Override
-    public void show() {
-        super.show();
-        if (shadow != null) {
-            if (isAnimationEnabled()) {
-                ShadowAnimation sa = new ShadowAnimation();
-                sa.run(200);
-            } else {
-                updateShadowSizeAndPosition(1.0);
-            }
-        }
-        if (BrowserInfo.get().isIE6()) {
-            adjustIE6Frame(getElement(), getZIndex());
-        }
-    }
-
-    @Override
-    public void setVisible(boolean visible) {
-        super.setVisible(visible);
-        if (shadow != null) {
-            shadow.getStyle().setProperty("visibility",
-                    visible ? "visible" : "hidden");
-        }
-    }
-
-    /*
-     * Needed to position overlays on top of native SELECT elements in IE6. See
-     * bug #2004
-     */
-    private native void adjustIE6Frame(Element popup, int zindex)
-    /*-{
-        // relies on PopupImplIE6
-        if(popup.__frame) 
-            popup.__frame.style.zIndex = zindex;
-    }-*/;
-
-    @Override
-    public void setWidth(String width) {
-        super.setWidth(width);
-        if (shadow != null) {
-            updateShadowSizeAndPosition(1.0);
-        }
-    }
-
-    @Override
-    public void setHeight(String height) {
-        super.setHeight(height);
-        if (shadow != null) {
-            updateShadowSizeAndPosition(1.0);
-        }
-    }
-
-    /**
-     * Sets the shadow style for this overlay. Will override any previous style
-     * for the shadow. The default style name is defined by CLASSNAME_SHADOW.
-     * The given style will be prefixed with CLASSNAME_SHADOW.
-     * 
-     * @param style
-     *            The new style name for the shadow element. Will be prefixed by
-     *            CLASSNAME_SHADOW, e.g. style=='foobar' -> actual style
-     *            name=='i-shadow-foobar'.
-     */
-    protected void setShadowStyle(String style) {
-        if (shadow != null) {
-            shadow.setClassName(CLASSNAME_SHADOW + "-" + style);
-        }
-    }
-
-    /*
-     * Extending classes should always call this method after they change the
-     * size of overlay without using normal 'setWidth(String)' and
-     * 'setHeight(String)' methods (if not calling super.setWidth/Height).
-     */
-    protected void updateShadowSizeAndPosition() {
-        updateShadowSizeAndPosition(1.0);
-    }
-
-    /**
-     * Recalculates proper position and dimensions for the shadow element. Can
-     * be used to animate the shadow, using the 'progress' parameter (used to
-     * animate the shadow in sync with GWT PopupPanel's default animation
-     * 'PopupPanel.AnimationType.CENTER').
-     * 
-     * @param progress
-     *            A value between 0.0 and 1.0, indicating the progress of the
-     *            animation (0=start, 1=end).
-     */
-    private void updateShadowSizeAndPosition(final double progress) {
-        // Don't do anything if overlay element is not attached
-        if (!isAttached()) {
-            return;
-        }
-        // Calculate proper z-index
-        String zIndex = null;
-        try {
-            // Odd behaviour with Windows Hosted Mode forces us to use
-            // this redundant try/catch block (See dev.itmill.com #2011)
-            zIndex = DOM.getStyleAttribute(getElement(), "zIndex");
-        } catch (Exception ignore) {
-            // Ignored, will cause no harm
-        }
-        if (zIndex == null) {
-            zIndex = "" + Z_INDEX;
-        }
-        // Calculate position and size
-        if (BrowserInfo.get().isIE()) {
-            // Shake IE
-            getOffsetHeight();
-            getOffsetWidth();
-        }
-
-        int x = getAbsoluteLeft();
-        int y = getAbsoluteTop();
-
-        /* This is needed for IE7 at least */
-        // Account for the difference between absolute position and the
-        // body's positioning context.
-        x -= Document.get().getBodyOffsetLeft();
-        y -= Document.get().getBodyOffsetTop();
-
-        int width = getOffsetWidth();
-        int height = getOffsetHeight();
-
-        if (width < 0) {
-            width = 0;
-        }
-        if (height < 0) {
-            height = 0;
-        }
-
-        // Animate the shadow size
-        x += (int) (width * (1.0 - progress) / 2.0);
-        y += (int) (height * (1.0 - progress) / 2.0);
-        width = (int) (width * progress);
-        height = (int) (height * progress);
-
-        // Opera needs some shaking to get parts of the shadow showing
-        // properly
-        // (ticket #2704)
-        if (BrowserInfo.get().isOpera()) {
-            // Clear the height of all middle elements
-            DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto");
-            DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto");
-            DOM.getChild(shadow, 5).getStyle().setProperty("height", "auto");
-        }
-
-        // Update correct values
-        DOM.setStyleAttribute(shadow, "zIndex", zIndex);
-        DOM.setStyleAttribute(shadow, "width", width + "px");
-        DOM.setStyleAttribute(shadow, "height", height + "px");
-        DOM.setStyleAttribute(shadow, "top", y + "px");
-        DOM.setStyleAttribute(shadow, "left", x + "px");
-        DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" : "");
-
-        // Opera fix, part 2 (ticket #2704)
-        if (BrowserInfo.get().isOpera()) {
-            // We'll fix the height of all the middle elements
-            DOM.getChild(shadow, 3).getStyle().setPropertyPx("height",
-                    DOM.getChild(shadow, 3).getOffsetHeight());
-            DOM.getChild(shadow, 4).getStyle().setPropertyPx("height",
-                    DOM.getChild(shadow, 4).getOffsetHeight());
-            DOM.getChild(shadow, 5).getStyle().setPropertyPx("height",
-                    DOM.getChild(shadow, 5).getOffsetHeight());
-        }
-
-        // Attach to dom if not there already
-        if (shadow.getParentElement() == null) {
-            RootPanel.get().getElement().insertBefore(shadow, getElement());
-        }
-
-    }
-
-    protected class ShadowAnimation extends Animation {
-        @Override
-        protected void onUpdate(double progress) {
-            if (shadow != null) {
-                updateShadowSizeAndPosition(progress);
-            }
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITree.java b/src/com/vaadin/terminal/gwt/client/ui/ITree.java
deleted file mode 100644 (file)
index b322293..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-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.FlowPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.MouseEventDetails;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-/**
- * 
- */
-public class ITree extends FlowPanel implements Paintable {
-
-    public static final String CLASSNAME = "i-tree";
-
-    private Set<String> selectedIds = new HashSet<String>();
-    private ApplicationConnection client;
-    private String paintableId;
-    private boolean selectable;
-    private boolean isMultiselect;
-
-    private final HashMap<String, TreeNode> keyToNode = new HashMap<String, TreeNode>();
-
-    /**
-     * This map contains captions and icon urls for actions like: * "33_c" ->
-     * "Edit" * "33_i" -> "http://dom.com/edit.png"
-     */
-    private final HashMap<String, String> actionMap = new HashMap<String, String>();
-
-    private boolean immediate;
-
-    private boolean isNullSelectionAllowed = true;
-
-    private boolean disabled = false;
-
-    private boolean readonly;
-
-    private boolean emitClickEvents;
-
-    private boolean rendering;
-
-    public ITree() {
-        super();
-        setStyleName(CLASSNAME);
-    }
-
-    private void updateActionMap(UIDL c) {
-        final Iterator it = c.getChildIterator();
-        while (it.hasNext()) {
-            final UIDL action = (UIDL) it.next();
-            final String key = action.getStringAttribute("key");
-            final String caption = action.getStringAttribute("caption");
-            actionMap.put(key + "_c", caption);
-            if (action.hasAttribute("icon")) {
-                // TODO need some uri handling ??
-                actionMap.put(key + "_i", client.translateToolkitUri(action
-                        .getStringAttribute("icon")));
-            }
-        }
-
-    }
-
-    public String getActionCaption(String actionKey) {
-        return actionMap.get(actionKey + "_c");
-    }
-
-    public String getActionIcon(String actionKey) {
-        return actionMap.get(actionKey + "_i");
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        // Ensure correct implementation and let container manage caption
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        rendering = true;
-
-        this.client = client;
-
-        if (uidl.hasAttribute("partialUpdate")) {
-            handleUpdate(uidl);
-            rendering = false;
-            return;
-        }
-
-        paintableId = uidl.getId();
-
-        immediate = uidl.hasAttribute("immediate");
-
-        disabled = uidl.getBooleanAttribute("disabled");
-        readonly = uidl.getBooleanAttribute("readonly");
-        emitClickEvents = uidl.getBooleanAttribute("listenClicks");
-
-        isNullSelectionAllowed = uidl.getBooleanAttribute("nullselect");
-
-        clear();
-        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
-            final UIDL childUidl = (UIDL) i.next();
-            if ("actions".equals(childUidl.getTag())) {
-                updateActionMap(childUidl);
-                continue;
-            }
-            final TreeNode childTree = new TreeNode();
-            this.add(childTree);
-            childTree.updateFromUIDL(childUidl, client);
-        }
-        final String selectMode = uidl.getStringAttribute("selectmode");
-        selectable = !"none".equals(selectMode);
-        isMultiselect = "multi".equals(selectMode);
-
-        selectedIds = uidl.getStringArrayVariableAsSet("selected");
-
-        rendering = false;
-
-    }
-
-    private void handleUpdate(UIDL uidl) {
-        final TreeNode rootNode = keyToNode.get(uidl
-                .getStringAttribute("rootKey"));
-        if (rootNode != null) {
-            if (!rootNode.getState()) {
-                // expanding node happened server side
-                rootNode.setState(true, false);
-            }
-            rootNode.renderChildNodes(uidl.getChildIterator());
-        }
-
-        if (uidl.hasVariable("selected")) {
-            // update selection in case selected nodes were not visible
-            selectedIds = uidl.getStringArrayVariableAsSet("selected");
-        }
-
-    }
-
-    public void setSelected(TreeNode treeNode, boolean selected) {
-        if (selected) {
-            if (!isMultiselect) {
-                while (selectedIds.size() > 0) {
-                    final String id = selectedIds.iterator().next();
-                    final TreeNode oldSelection = keyToNode.get(id);
-                    if (oldSelection != null) {
-                        // can be null if the node is not visible (parent
-                        // collapsed)
-                        oldSelection.setSelected(false);
-                    }
-                    selectedIds.remove(id);
-                }
-            }
-            treeNode.setSelected(true);
-            selectedIds.add(treeNode.key);
-        } else {
-            if (!isNullSelectionAllowed) {
-                if (!isMultiselect || selectedIds.size() == 1) {
-                    return;
-                }
-            }
-            selectedIds.remove(treeNode.key);
-            treeNode.setSelected(false);
-        }
-        client.updateVariable(paintableId, "selected", selectedIds.toArray(),
-                immediate);
-    }
-
-    public boolean isSelected(TreeNode treeNode) {
-        return selectedIds.contains(treeNode.key);
-    }
-
-    protected class TreeNode extends SimplePanel implements ActionOwner {
-
-        public static final String CLASSNAME = "i-tree-node";
-
-        String key;
-
-        private String[] actionKeys = null;
-
-        private boolean childrenLoaded;
-
-        private Element nodeCaptionDiv;
-
-        protected Element nodeCaptionSpan;
-
-        private FlowPanel childNodeContainer;
-
-        private boolean open;
-
-        private Icon icon;
-
-        private Element ie6compatnode;
-
-        public TreeNode() {
-            constructDom();
-            sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.ONMOUSEUP
-                    | Event.ONCONTEXTMENU);
-        }
-
-        @Override
-        public void onBrowserEvent(Event event) {
-            super.onBrowserEvent(event);
-            if (disabled) {
-                return;
-            }
-            final int type = DOM.eventGetType(event);
-            final Element target = DOM.eventGetTarget(event);
-            if (emitClickEvents && target == nodeCaptionSpan
-                    && (type == Event.ONDBLCLICK || type == Event.ONMOUSEUP)) {
-                fireClick(event);
-            }
-            if (type == Event.ONCLICK) {
-                if (getElement() == target || ie6compatnode == target) {
-                    // state change
-                    toggleState();
-                } else if (!readonly && target == nodeCaptionSpan) {
-                    // caption click = selection change && possible click event
-                    toggleSelection();
-                }
-                DOM.eventCancelBubble(event, true);
-            } else if (type == Event.ONCONTEXTMENU) {
-                showContextMenu(event);
-            }
-        }
-
-        private void fireClick(Event evt) {
-            // non-immediate iff an immediate select event is going to happen
-            boolean imm = !immediate
-                    || !selectable
-                    || (!isNullSelectionAllowed && isSelected() && selectedIds
-                            .size() == 1);
-            MouseEventDetails details = new MouseEventDetails(evt);
-            client.updateVariable(paintableId, "clickedKey", key, false);
-            client.updateVariable(paintableId, "clickEvent",
-                    details.toString(), imm);
-        }
-
-        private void toggleSelection() {
-            if (selectable) {
-                ITree.this.setSelected(this, !isSelected());
-            }
-        }
-
-        private void toggleState() {
-            setState(!getState(), true);
-        }
-
-        protected void constructDom() {
-            // workaround for a very weird IE6 issue #1245
-            ie6compatnode = DOM.createDiv();
-            setStyleName(ie6compatnode, CLASSNAME + "-ie6compatnode");
-            DOM.setInnerText(ie6compatnode, " ");
-            DOM.appendChild(getElement(), ie6compatnode);
-
-            DOM.sinkEvents(ie6compatnode, Event.ONCLICK);
-
-            nodeCaptionDiv = DOM.createDiv();
-            DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME
-                    + "-caption");
-            Element wrapper = DOM.createDiv();
-            nodeCaptionSpan = DOM.createSpan();
-            DOM.appendChild(getElement(), nodeCaptionDiv);
-            DOM.appendChild(nodeCaptionDiv, wrapper);
-            DOM.appendChild(wrapper, nodeCaptionSpan);
-
-            childNodeContainer = new FlowPanel();
-            childNodeContainer.setStylePrimaryName(CLASSNAME + "-children");
-            setWidget(childNodeContainer);
-        }
-
-        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-            setText(uidl.getStringAttribute("caption"));
-            key = uidl.getStringAttribute("key");
-
-            keyToNode.put(key, this);
-
-            if (uidl.hasAttribute("al")) {
-                actionKeys = uidl.getStringArrayAttribute("al");
-            }
-
-            if (uidl.getTag().equals("node")) {
-                if (uidl.getChildCount() == 0) {
-                    childNodeContainer.setVisible(false);
-                } else {
-                    renderChildNodes(uidl.getChildIterator());
-                    childrenLoaded = true;
-                }
-            } else {
-                addStyleName(CLASSNAME + "-leaf");
-            }
-            addStyleName(CLASSNAME);
-
-            if (uidl.getBooleanAttribute("expanded") && !getState()) {
-                setState(true, false);
-            }
-
-            if (uidl.getBooleanAttribute("selected")) {
-                setSelected(true);
-            }
-
-            if (uidl.hasAttribute("icon")) {
-                if (icon == null) {
-                    icon = new Icon(client);
-                    DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv), icon
-                            .getElement(), nodeCaptionSpan);
-                }
-                icon.setUri(uidl.getStringAttribute("icon"));
-            } else {
-                if (icon != null) {
-                    DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv), icon
-                            .getElement());
-                    icon = null;
-                }
-            }
-
-            if (BrowserInfo.get().isIE6() && isAttached()) {
-                fixWidth();
-            }
-        }
-
-        private void setState(boolean state, boolean notifyServer) {
-            if (open == state) {
-                return;
-            }
-            if (state) {
-                if (!childrenLoaded && notifyServer) {
-                    client.updateVariable(paintableId, "requestChildTree",
-                            true, false);
-                }
-                if (notifyServer) {
-                    client.updateVariable(paintableId, "expand",
-                            new String[] { key }, true);
-                }
-                addStyleName(CLASSNAME + "-expanded");
-                childNodeContainer.setVisible(true);
-
-            } else {
-                removeStyleName(CLASSNAME + "-expanded");
-                childNodeContainer.setVisible(false);
-                if (notifyServer) {
-                    client.updateVariable(paintableId, "collapse",
-                            new String[] { key }, true);
-                }
-            }
-            open = state;
-
-            if (!rendering) {
-                Util.notifyParentOfSizeChange(ITree.this, false);
-            }
-        }
-
-        private boolean getState() {
-            return open;
-        }
-
-        private void setText(String text) {
-            DOM.setInnerText(nodeCaptionSpan, text);
-        }
-
-        private void renderChildNodes(Iterator i) {
-            childNodeContainer.clear();
-            childNodeContainer.setVisible(true);
-            while (i.hasNext()) {
-                final UIDL childUidl = (UIDL) i.next();
-                // actions are in bit weird place, don't mix them with children,
-                // but current node's actions
-                if ("actions".equals(childUidl.getTag())) {
-                    updateActionMap(childUidl);
-                    continue;
-                }
-                final TreeNode childTree = new TreeNode();
-                childNodeContainer.add(childTree);
-                childTree.updateFromUIDL(childUidl, client);
-            }
-            childrenLoaded = true;
-        }
-
-        public boolean isChildrenLoaded() {
-            return childrenLoaded;
-        }
-
-        public Action[] getActions() {
-            if (actionKeys == null) {
-                return new Action[] {};
-            }
-            final Action[] actions = new Action[actionKeys.length];
-            for (int i = 0; i < actions.length; i++) {
-                final String actionKey = actionKeys[i];
-                final TreeAction a = new TreeAction(this, String.valueOf(key),
-                        actionKey);
-                a.setCaption(getActionCaption(actionKey));
-                a.setIconUrl(getActionIcon(actionKey));
-                actions[i] = a;
-            }
-            return actions;
-        }
-
-        public ApplicationConnection getClient() {
-            return client;
-        }
-
-        public String getPaintableId() {
-            return paintableId;
-        }
-
-        /**
-         * Adds/removes IT Mill Toolkit specific style name. This method ought
-         * to be called only from ITree.
-         * 
-         * @param selected
-         */
-        protected void setSelected(boolean selected) {
-            // add style name to caption dom structure only, not to subtree
-            setStyleName(nodeCaptionDiv, "i-tree-node-selected", selected);
-        }
-
-        protected boolean isSelected() {
-            return ITree.this.isSelected(this);
-        }
-
-        public void showContextMenu(Event event) {
-            if (!readonly && !disabled) {
-                if (actionKeys != null) {
-                    int left = event.getClientX();
-                    int top = event.getClientY();
-                    top += Window.getScrollTop();
-                    left += Window.getScrollLeft();
-                    client.getContextMenu().showAt(this, left, top);
-                }
-                event.cancelBubble(true);
-                event.preventDefault();
-            }
-        }
-
-        /*
-         * We need to fix the width of TreeNodes so that the float in
-         * ie6compatNode does not wrap (see ticket #1245)
-         */
-        private void fixWidth() {
-            nodeCaptionDiv.getStyle().setProperty("styleFloat", "left");
-            nodeCaptionDiv.getStyle().setProperty("display", "inline");
-            nodeCaptionDiv.getStyle().setProperty("marginLeft", "0");
-            final int captionWidth = ie6compatnode.getOffsetWidth()
-                    + nodeCaptionDiv.getOffsetWidth();
-            setWidth(captionWidth + "px");
-        }
-
-        @Override
-        public void onAttach() {
-            super.onAttach();
-            if (BrowserInfo.get().isIE6()) {
-                fixWidth();
-            }
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ITwinColSelect.java b/src/com/vaadin/terminal/gwt/client/ui/ITwinColSelect.java
deleted file mode 100644 (file)
index c29f520..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/* \r
-@ITMillApache2LicenseForJavaFiles@\r
- */\r
-\r
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-import java.util.Iterator;\r
-import java.util.Vector;\r
-\r
-import com.google.gwt.user.client.DOM;\r
-import com.google.gwt.user.client.ui.FlowPanel;\r
-import com.google.gwt.user.client.ui.HTML;\r
-import com.google.gwt.user.client.ui.ListBox;\r
-import com.google.gwt.user.client.ui.Panel;\r
-import com.google.gwt.user.client.ui.Widget;\r
-import com.vaadin.terminal.gwt.client.UIDL;\r
-\r
-public class ITwinColSelect extends IOptionGroupBase {\r
-\r
-    private static final String CLASSNAME = "i-select-twincol";\r
-\r
-    private static final int VISIBLE_COUNT = 10;\r
-\r
-    private static final int DEFAULT_COLUMN_COUNT = 10;\r
-\r
-    private final ListBox options;\r
-\r
-    private final ListBox selections;\r
-\r
-    private final IButton add;\r
-\r
-    private final IButton remove;\r
-\r
-    private FlowPanel buttons;\r
-\r
-    private Panel panel;\r
-\r
-    private boolean widthSet = false;\r
-\r
-    public ITwinColSelect() {\r
-        super(CLASSNAME);\r
-        options = new ListBox();\r
-        options.addClickListener(this);\r
-        selections = new ListBox();\r
-        selections.addClickListener(this);\r
-        options.setVisibleItemCount(VISIBLE_COUNT);\r
-        selections.setVisibleItemCount(VISIBLE_COUNT);\r
-        options.setStyleName(CLASSNAME + "-options");\r
-        selections.setStyleName(CLASSNAME + "-selections");\r
-        buttons = new FlowPanel();\r
-        buttons.setStyleName(CLASSNAME + "-buttons");\r
-        add = new IButton();\r
-        add.setText(">>");\r
-        add.addClickListener(this);\r
-        remove = new IButton();\r
-        remove.setText("<<");\r
-        remove.addClickListener(this);\r
-        panel = ((Panel) optionsContainer);\r
-        panel.add(options);\r
-        buttons.add(add);\r
-        final HTML br = new HTML("<span/>");\r
-        br.setStyleName(CLASSNAME + "-deco");\r
-        buttons.add(br);\r
-        buttons.add(remove);\r
-        panel.add(buttons);\r
-        panel.add(selections);\r
-    }\r
-\r
-    @Override\r
-    protected void buildOptions(UIDL uidl) {\r
-        final boolean enabled = !isDisabled() && !isReadonly();\r
-        options.setMultipleSelect(isMultiselect());\r
-        selections.setMultipleSelect(isMultiselect());\r
-        options.setEnabled(enabled);\r
-        selections.setEnabled(enabled);\r
-        add.setEnabled(enabled);\r
-        remove.setEnabled(enabled);\r
-        options.clear();\r
-        selections.clear();\r
-        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {\r
-            final UIDL optionUidl = (UIDL) i.next();\r
-            if (optionUidl.hasAttribute("selected")) {\r
-                selections.addItem(optionUidl.getStringAttribute("caption"),\r
-                        optionUidl.getStringAttribute("key"));\r
-            } else {\r
-                options.addItem(optionUidl.getStringAttribute("caption"),\r
-                        optionUidl.getStringAttribute("key"));\r
-            }\r
-        }\r
-\r
-        int cols = -1;\r
-        if (getColumns() > 0) {\r
-            cols = getColumns();\r
-        } else if (!widthSet) {\r
-            cols = DEFAULT_COLUMN_COUNT;\r
-        }\r
-\r
-        if (cols >= 0) {\r
-            options.setWidth(cols + "em");\r
-            selections.setWidth(cols + "em");\r
-            buttons.setWidth("3.5em");\r
-            optionsContainer.setWidth((2 * cols + 4) + "em");\r
-        }\r
-        if (getRows() > 0) {\r
-            options.setVisibleItemCount(getRows());\r
-            selections.setVisibleItemCount(getRows());\r
-\r
-        }\r
-\r
-    }\r
-\r
-    @Override\r
-    protected Object[] getSelectedItems() {\r
-        final Vector selectedItemKeys = new Vector();\r
-        for (int i = 0; i < selections.getItemCount(); i++) {\r
-            selectedItemKeys.add(selections.getValue(i));\r
-        }\r
-        return selectedItemKeys.toArray();\r
-    }\r
-\r
-    private boolean[] getItemsToAdd() {\r
-        final boolean[] selectedIndexes = new boolean[options.getItemCount()];\r
-        for (int i = 0; i < options.getItemCount(); i++) {\r
-            if (options.isItemSelected(i)) {\r
-                selectedIndexes[i] = true;\r
-            } else {\r
-                selectedIndexes[i] = false;\r
-            }\r
-        }\r
-        return selectedIndexes;\r
-    }\r
-\r
-    private boolean[] getItemsToRemove() {\r
-        final boolean[] selectedIndexes = new boolean[selections.getItemCount()];\r
-        for (int i = 0; i < selections.getItemCount(); i++) {\r
-            if (selections.isItemSelected(i)) {\r
-                selectedIndexes[i] = true;\r
-            } else {\r
-                selectedIndexes[i] = false;\r
-            }\r
-        }\r
-        return selectedIndexes;\r
-    }\r
-\r
-    @Override\r
-    public void onClick(Widget sender) {\r
-        super.onClick(sender);\r
-        if (sender == add) {\r
-            final boolean[] sel = getItemsToAdd();\r
-            for (int i = 0; i < sel.length; i++) {\r
-                if (sel[i]) {\r
-                    final int optionIndex = i\r
-                            - (sel.length - options.getItemCount());\r
-                    selectedKeys.add(options.getValue(optionIndex));\r
-\r
-                    // Move selection to another column\r
-                    final String text = options.getItemText(optionIndex);\r
-                    final String value = options.getValue(optionIndex);\r
-                    selections.addItem(text, value);\r
-                    selections.setItemSelected(selections.getItemCount() - 1,\r
-                            true);\r
-                    options.removeItem(optionIndex);\r
-                }\r
-            }\r
-            client.updateVariable(id, "selected", selectedKeys.toArray(),\r
-                    isImmediate());\r
-\r
-        } else if (sender == remove) {\r
-            final boolean[] sel = getItemsToRemove();\r
-            for (int i = 0; i < sel.length; i++) {\r
-                if (sel[i]) {\r
-                    final int selectionIndex = i\r
-                            - (sel.length - selections.getItemCount());\r
-                    selectedKeys.remove(selections.getValue(selectionIndex));\r
-\r
-                    // Move selection to another column\r
-                    final String text = selections.getItemText(selectionIndex);\r
-                    final String value = selections.getValue(selectionIndex);\r
-                    options.addItem(text, value);\r
-                    options.setItemSelected(options.getItemCount() - 1, true);\r
-                    selections.removeItem(selectionIndex);\r
-                }\r
-            }\r
-            client.updateVariable(id, "selected", selectedKeys.toArray(),\r
-                    isImmediate());\r
-        } else if (sender == options) {\r
-            // unselect all in other list, to avoid mistakes (i.e wrong button)\r
-            final int c = selections.getItemCount();\r
-            for (int i = 0; i < c; i++) {\r
-                selections.setItemSelected(i, false);\r
-            }\r
-        } else if (sender == selections) {\r
-            // unselect all in other list, to avoid mistakes (i.e wrong button)\r
-            final int c = options.getItemCount();\r
-            for (int i = 0; i < c; i++) {\r
-                options.setItemSelected(i, false);\r
-            }\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public void setHeight(String height) {\r
-        super.setHeight(height);\r
-        if ("".equals(height)) {\r
-            options.setHeight("");\r
-            selections.setHeight("");\r
-        } else {\r
-            setFullHeightInternals();\r
-        }\r
-    }\r
-\r
-    private void setFullHeightInternals() {\r
-        options.setHeight("100%");\r
-        selections.setHeight("100%");\r
-    }\r
-\r
-    @Override\r
-    public void setWidth(String width) {\r
-        super.setWidth(width);\r
-        if (!"".equals(width) && width != null) {\r
-            setRelativeInternalWidths();\r
-        }\r
-    }\r
-\r
-    private void setRelativeInternalWidths() {\r
-        DOM.setStyleAttribute(getElement(), "position", "relative");\r
-        buttons.setWidth("15%");\r
-        options.setWidth("42%");\r
-        selections.setWidth("42%");\r
-        widthSet = true;\r
-    }\r
-\r
-    @Override\r
-    protected void setTabIndex(int tabIndex) {\r
-        options.setTabIndex(tabIndex);\r
-        selections.setTabIndex(tabIndex);\r
-        add.setTabIndex(tabIndex);\r
-        remove.setTabIndex(tabIndex);\r
-    }\r
-\r
-    public void focus() {\r
-        options.setFocus(true);\r
-    }\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IUnknownComponent.java b/src/com/vaadin/terminal/gwt/client/ui/IUnknownComponent.java
deleted file mode 100644 (file)
index 5715ab0..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.Tree;
-import com.google.gwt.user.client.ui.VerticalPanel;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IUnknownComponent extends Composite implements Paintable {
-
-    com.google.gwt.user.client.ui.Label caption = new com.google.gwt.user.client.ui.Label();;
-    Tree uidlTree = new Tree();
-
-    public IUnknownComponent() {
-        final VerticalPanel panel = new VerticalPanel();
-        panel.add(caption);
-        panel.add(uidlTree);
-        initWidget(panel);
-        setStyleName("itmill-unknown");
-        caption.setStyleName("itmill-unknown-caption");
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-        setCaption("Client faced an unknown component type. Unrendered UIDL:");
-        uidlTree.clear();
-        uidlTree.addItem(uidl.dir());
-    }
-
-    public void setCaption(String c) {
-        caption.setText(c);
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IUpload.java b/src/com/vaadin/terminal/gwt/client/ui/IUpload.java
deleted file mode 100644 (file)
index a03beed..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.user.client.Timer;
-import com.google.gwt.user.client.ui.Button;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.FileUpload;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.FormHandler;
-import com.google.gwt.user.client.ui.FormPanel;
-import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
-import com.google.gwt.user.client.ui.FormSubmitEvent;
-import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-public class IUpload extends FormPanel implements Paintable, ClickListener,
-        FormHandler {
-
-    public static final String CLASSNAME = "i-upload";
-
-    /**
-     * FileUpload component that opens native OS dialog to select file.
-     */
-    FileUpload fu = new FileUpload();
-
-    Panel panel = new FlowPanel();
-
-    ApplicationConnection client;
-
-    private String paintableId;
-
-    /**
-     * Button that initiates uploading
-     */
-    private final Button submitButton;
-
-    /**
-     * When expecting big files, programmer may initiate some UI changes when
-     * uploading the file starts. Bit after submitting file we'll visit the
-     * server to check possible changes.
-     */
-    private Timer t;
-
-    /**
-     * some browsers tries to send form twice if submit is called in button
-     * click handler, some don't submit at all without it, so we need to track
-     * if form is already being submitted
-     */
-    private boolean submitted = false;
-
-    private boolean enabled = true;
-
-    public IUpload() {
-        super();
-        setEncoding(FormPanel.ENCODING_MULTIPART);
-        setMethod(FormPanel.METHOD_POST);
-
-        setWidget(panel);
-        panel.add(fu);
-        submitButton = new Button();
-        submitButton.addClickListener(this);
-        panel.add(submitButton);
-
-        addFormHandler(this);
-
-        setStyleName(CLASSNAME);
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-        this.client = client;
-        paintableId = uidl.getId();
-        setAction(client.getAppUri());
-        submitButton.setText(uidl.getStringAttribute("buttoncaption"));
-        fu.setName(paintableId + "_file");
-
-        if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) {
-            disableUpload();
-        } else if (uidl.getBooleanAttribute("state")) {
-            enableUploaod();
-        }
-
-    }
-
-    public void onClick(Widget sender) {
-        submit();
-    }
-
-    public void onSubmit(FormSubmitEvent event) {
-        if (fu.getFilename().length() == 0 || submitted || !enabled) {
-            event.setCancelled(true);
-            ApplicationConnection
-                    .getConsole()
-                    .log(
-                            "Submit cancelled (disabled, no file or already submitted)");
-            return;
-        }
-        // flush possibly pending variable changes, so they will be handled
-        // before upload
-        client.sendPendingVariableChanges();
-
-        submitted = true;
-        ApplicationConnection.getConsole().log("Submitted form");
-
-        disableUpload();
-
-        /*
-         * Visit server a moment after upload has started to see possible
-         * changes from UploadStarted event. Will be cleared on complete.
-         */
-        t = new Timer() {
-            @Override
-            public void run() {
-                client.sendPendingVariableChanges();
-            }
-        };
-        t.schedule(800);
-    }
-
-    protected void disableUpload() {
-        submitButton.setEnabled(false);
-        fu.setVisible(false);
-        enabled = false;
-    }
-
-    protected void enableUploaod() {
-        submitButton.setEnabled(true);
-        fu.setVisible(true);
-        enabled = true;
-    }
-
-    public void onSubmitComplete(FormSubmitCompleteEvent event) {
-        if (client != null) {
-            if (t != null) {
-                t.cancel();
-            }
-            ApplicationConnection.getConsole().log("Submit complete");
-            client.sendPendingVariableChanges();
-        }
-        submitted = false;
-        enableUploaod();
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IUriFragmentUtility.java b/src/com/vaadin/terminal/gwt/client/ui/IUriFragmentUtility.java
deleted file mode 100644 (file)
index d2237c5..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.History;
-import com.google.gwt.user.client.HistoryListener;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-
-/**
- * Client side implementation for UriFragmentUtility. Uses GWT's History object
- * as an implementation.
- * 
- */
-public class IUriFragmentUtility extends Widget implements Paintable,
-        HistoryListener {
-
-    private String fragment;
-    private ApplicationConnection client;
-    private String paintableId;
-    private boolean immediate;
-
-    public IUriFragmentUtility() {
-        setElement(Document.get().createDivElement());
-        if (BrowserInfo.get().isIE6()) {
-            getElement().getStyle().setProperty("overflow", "hidden");
-            getElement().getStyle().setProperty("height", "0");
-        }
-        History.addHistoryListener(this);
-        History.fireCurrentHistoryState();
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-        String uidlFragment = uidl.getStringVariable("fragment");
-        immediate = uidl.getBooleanAttribute("immediate");
-        if (this.client == null) {
-            // initial paint has some special logic
-            this.client = client;
-            paintableId = uidl.getId();
-            if (!fragment.equals(uidlFragment)) {
-                // initial server side fragment (from link/bookmark/typed) does
-                // not equal the one on
-                // server, send initial fragment to server
-                History.fireCurrentHistoryState();
-            }
-        } else {
-            if (uidlFragment != null && !uidlFragment.equals(fragment)) {
-                fragment = uidlFragment;
-                // normal fragment change from server, add new history item
-                History.newItem(uidlFragment, false);
-            }
-        }
-    }
-
-    public void onHistoryChanged(String historyToken) {
-        fragment = historyToken;
-        if (client != null) {
-            client.updateVariable(paintableId, "fragment", fragment, immediate);
-        }
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IVerticalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/IVerticalLayout.java
deleted file mode 100644 (file)
index 9adeb81..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.vaadin.terminal.gwt.client.ui;\r
-\r
-public class IVerticalLayout extends IOrderedLayout {\r
-\r
-    public static final String CLASSNAME = "i-verticallayout";\r
-\r
-    public IVerticalLayout() {\r
-        super(CLASSNAME, ORIENTATION_VERTICAL);\r
-    }\r
-\r
-}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IView.java b/src/com/vaadin/terminal/gwt/client/ui/IView.java
deleted file mode 100644 (file)
index 2d8ce9a..0000000
+++ /dev/null
@@ -1,575 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import com.google.gwt.dom.client.DivElement;
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-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.WindowCloseListener;
-import com.google.gwt.user.client.WindowResizeListener;
-import com.google.gwt.user.client.ui.HasFocus;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-/**
- * 
- */
-public class IView extends SimplePanel implements Container,
-        WindowResizeListener, WindowCloseListener {
-
-    private static final String CLASSNAME = "i-view";
-
-    private String theme;
-
-    private Paintable layout;
-
-    private final LinkedHashSet<IWindow> subWindows = new LinkedHashSet<IWindow>();
-
-    private String id;
-
-    private ShortcutActionHandler actionHandler;
-
-    /** stored width for IE resize optimization */
-    private int width;
-
-    /** stored height for IE resize optimization */
-    private int height;
-
-    private ApplicationConnection connection;
-
-    /**
-     * We are postponing resize process with IE. IE bugs with scrollbars in some
-     * situations, that causes false onWindowResized calls. With Timer we will
-     * give IE some time to decide if it really wants to keep current size
-     * (scrollbars).
-     */
-    private Timer resizeTimer;
-
-    private int scrollTop;
-
-    private int scrollLeft;
-
-    private boolean rendering;
-
-    private boolean scrollable;
-
-    private boolean immediate;
-
-    public IView(String elementId) {
-        super();
-        setStyleName(CLASSNAME);
-
-        DOM.sinkEvents(getElement(), Event.ONKEYDOWN | Event.ONSCROLL);
-
-        // iview is focused when created so element needs tabIndex
-        // 1 due 0 is at the end of natural tabbing order
-        DOM.setElementProperty(getElement(), "tabIndex", "1");
-
-        RootPanel root = RootPanel.get(elementId);
-        root.add(this);
-        root.removeStyleName("i-app-loading");
-
-        BrowserInfo browser = BrowserInfo.get();
-
-        // set focus to iview element by default to listen possible keyboard
-        // shortcuts
-        if (browser.isOpera() || browser.isSafari()
-                && browser.getWebkitVersion() < 526) {
-            // old webkits don't support focusing div elements
-            Element fElem = DOM.createInputCheck();
-            DOM.setStyleAttribute(fElem, "margin", "0");
-            DOM.setStyleAttribute(fElem, "padding", "0");
-            DOM.setStyleAttribute(fElem, "border", "0");
-            DOM.setStyleAttribute(fElem, "outline", "0");
-            DOM.setStyleAttribute(fElem, "width", "1px");
-            DOM.setStyleAttribute(fElem, "height", "1px");
-            DOM.setStyleAttribute(fElem, "position", "absolute");
-            DOM.setStyleAttribute(fElem, "opacity", "0.1");
-            DOM.appendChild(getElement(), fElem);
-            focus(fElem);
-        } else {
-            focus(getElement());
-        }
-
-    }
-
-    private static native void focus(Element el)
-    /*-{
-        try {
-            el.focus();
-        } catch (e) {
-        
-        }
-    }-*/;
-
-    public String getTheme() {
-        return theme;
-    }
-
-    /**
-     * Used to reload host page on theme changes.
-     */
-    private static native void reloadHostPage()
-    /*-{
-         $wnd.location.reload(); 
-     }-*/;
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-
-        id = uidl.getId();
-        boolean firstPaint = connection == null;
-        connection = client;
-
-        immediate = uidl.hasAttribute("immediate");
-
-        String newTheme = uidl.getStringAttribute("theme");
-        if (theme != null && !newTheme.equals(theme)) {
-            // Complete page refresh is needed due css can affect layout
-            // calculations etc
-            reloadHostPage();
-        } else {
-            theme = newTheme;
-        }
-        if (uidl.hasAttribute("style")) {
-            addStyleName(uidl.getStringAttribute("style"));
-        }
-
-        if (uidl.hasAttribute("name")) {
-            client.setWindowName(uidl.getStringAttribute("name"));
-        }
-
-        com.google.gwt.user.client.Window.setTitle(uidl
-                .getStringAttribute("caption"));
-
-        // Process children
-        int childIndex = 0;
-
-        // Open URL:s
-        boolean isClosed = false; // was this window closed?
-        while (childIndex < uidl.getChildCount()
-                && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
-            final UIDL open = uidl.getChildUIDL(childIndex);
-            final String url = open.getStringAttribute("src");
-            final String target = open.getStringAttribute("name");
-            if (target == null) {
-                // This window is closing. Send close event before
-                // going to the new url
-                isClosed = true;
-                onWindowClosed();
-                goTo(url);
-            } else {
-                String options;
-                if (open.hasAttribute("border")) {
-                    if (open.getStringAttribute("border").equals("minimal")) {
-                        options = "menubar=yes,location=no,status=no";
-                    } else {
-                        options = "menubar=no,location=no,status=no";
-                    }
-
-                } else {
-                    options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
-                }
-
-                if (open.hasAttribute("width")) {
-                    int w = open.getIntAttribute("width");
-                    options += ",width=" + w;
-                }
-                if (open.hasAttribute("height")) {
-                    int h = open.getIntAttribute("height");
-                    options += ",height=" + h;
-                }
-
-                Window.open(url, target, options);
-            }
-            childIndex++;
-        }
-        if (isClosed) {
-            // don't render the content
-            rendering = false;
-            return;
-        }
-
-        // Draw this application level window
-        UIDL childUidl = uidl.getChildUIDL(childIndex);
-        final Paintable lo = client.getPaintable(childUidl);
-
-        if (layout != null) {
-            if (layout != lo) {
-                // remove old
-                client.unregisterPaintable(layout);
-                // add new
-                setWidget((Widget) lo);
-                layout = lo;
-            }
-        } else {
-            setWidget((Widget) lo);
-            layout = lo;
-        }
-
-        layout.updateFromUIDL(childUidl, client);
-
-        // Update subwindows
-        final HashSet<IWindow> removedSubWindows = new HashSet<IWindow>(
-                subWindows);
-
-        // Open new windows
-        while ((childUidl = uidl.getChildUIDL(childIndex++)) != null) {
-            if ("window".equals(childUidl.getTag())) {
-                final Paintable w = client.getPaintable(childUidl);
-                if (subWindows.contains(w)) {
-                    removedSubWindows.remove(w);
-                } else {
-                    subWindows.add((IWindow) w);
-                }
-                w.updateFromUIDL(childUidl, client);
-            } else if ("actions".equals(childUidl.getTag())) {
-                if (actionHandler == null) {
-                    actionHandler = new ShortcutActionHandler(id, client);
-                }
-                actionHandler.updateActionMap(childUidl);
-            } else if (childUidl.getTag().equals("notifications")) {
-                for (final Iterator it = childUidl.getChildIterator(); it
-                        .hasNext();) {
-                    final UIDL notification = (UIDL) it.next();
-                    String html = "";
-                    if (notification.hasAttribute("icon")) {
-                        final String parsedUri = client
-                                .translateToolkitUri(notification
-                                        .getStringAttribute("icon"));
-                        html += "<IMG src=\"" + parsedUri + "\" />";
-                    }
-                    if (notification.hasAttribute("caption")) {
-                        html += "<H1>"
-                                + notification.getStringAttribute("caption")
-                                + "</H1>";
-                    }
-                    if (notification.hasAttribute("message")) {
-                        html += "<p>"
-                                + notification.getStringAttribute("message")
-                                + "</p>";
-                    }
-
-                    final String style = notification.hasAttribute("style") ? notification
-                            .getStringAttribute("style")
-                            : null;
-                    final int position = notification
-                            .getIntAttribute("position");
-                    final int delay = notification.getIntAttribute("delay");
-                    new INotification(delay).show(html, position, style);
-                }
-            }
-        }
-
-        // Close old windows
-        for (final Iterator<IWindow> rem = removedSubWindows.iterator(); rem
-                .hasNext();) {
-            final IWindow w = rem.next();
-            client.unregisterPaintable(w);
-            subWindows.remove(w);
-            w.hide();
-        }
-
-        if (uidl.hasAttribute("focused")) {
-            final String focusPid = uidl.getStringAttribute("focused");
-            // set focused component when render phase is finished
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    final Paintable toBeFocused = connection
-                            .getPaintable(focusPid);
-
-                    /*
-                     * Two types of Widgets can be focused, either implementing
-                     * GWT HasFocus of a thinner Toolkit specific Focusable
-                     * interface.
-                     */
-                    if (toBeFocused instanceof HasFocus) {
-                        final HasFocus toBeFocusedWidget = (HasFocus) toBeFocused;
-                        toBeFocusedWidget.setFocus(true);
-                    } else if (toBeFocused instanceof Focusable) {
-                        ((Focusable) toBeFocused).focus();
-                    } else {
-                        ApplicationConnection.getConsole().log(
-                                "Could not focus component");
-                    }
-                }
-            });
-        }
-
-        // Add window listeners on first paint, to prevent premature
-        // variablechanges
-        if (firstPaint) {
-            Window.addWindowCloseListener(this);
-            Window.addWindowResizeListener(this);
-        }
-
-        onWindowResized(Window.getClientWidth(), Window.getClientHeight());
-
-        if (BrowserInfo.get().isSafari()) {
-            Util.runWebkitOverflowAutoFix(getElement());
-        }
-
-        // finally set scroll position from UIDL
-        if (uidl.hasVariable("scrollTop")) {
-            scrollable = true;
-            scrollTop = uidl.getIntVariable("scrollTop");
-            DOM.setElementPropertyInt(getElement(), "scrollTop", scrollTop);
-            scrollLeft = uidl.getIntVariable("scrollLeft");
-            DOM.setElementPropertyInt(getElement(), "scrollLeft", scrollLeft);
-        } else {
-            scrollable = false;
-        }
-
-        rendering = false;
-    }
-
-    @Override
-    public void onBrowserEvent(Event event) {
-        super.onBrowserEvent(event);
-        int type = DOM.eventGetType(event);
-        if (type == Event.ONKEYDOWN && actionHandler != null) {
-            actionHandler.handleKeyboardEvent(event);
-            return;
-        } else if (scrollable && type == Event.ONSCROLL) {
-            updateScrollPosition();
-        }
-    }
-
-    /**
-     * Updates scroll position from DOM and saves variables to server.
-     */
-    private void updateScrollPosition() {
-        int oldTop = scrollTop;
-        int oldLeft = scrollLeft;
-        scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
-        scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
-        if (connection != null && !rendering) {
-            if (oldTop != scrollTop) {
-                connection.updateVariable(id, "scrollTop", scrollTop, false);
-            }
-            if (oldLeft != scrollLeft) {
-                connection.updateVariable(id, "scrollLeft", scrollLeft, false);
-            }
-        }
-    }
-
-    public void onWindowResized(int width, int height) {
-        if (BrowserInfo.get().isIE()) {
-            /*
-             * IE will give us some false resized events due bugs with
-             * scrollbars. Postponing layout phase to see if size was really
-             * changed.
-             */
-            if (resizeTimer == null) {
-                resizeTimer = new Timer() {
-                    @Override
-                    public void run() {
-                        boolean changed = false;
-                        if (IView.this.width != getOffsetWidth()) {
-                            IView.this.width = getOffsetWidth();
-                            changed = true;
-                            ApplicationConnection.getConsole().log(
-                                    "window w" + IView.this.width);
-                        }
-                        if (IView.this.height != getOffsetHeight()) {
-                            IView.this.height = getOffsetHeight();
-                            changed = true;
-                            ApplicationConnection.getConsole().log(
-                                    "window h" + IView.this.height);
-                        }
-                        if (changed) {
-                            ApplicationConnection
-                                    .getConsole()
-                                    .log(
-                                            "Running layout functions due window resize");
-                            connection.runDescendentsLayout(IView.this);
-
-                            sendClientResized();
-                        }
-                    }
-                };
-            } else {
-                resizeTimer.cancel();
-            }
-            resizeTimer.schedule(200);
-        } else {
-            if (width == IView.this.width && height == IView.this.height) {
-                // No point in doing resize operations if window size has not
-                // changed
-                return;
-            }
-
-            IView.this.width = Window.getClientWidth();
-            IView.this.height = Window.getClientHeight();
-
-            ApplicationConnection.getConsole().log(
-                    "Running layout functions due window resize");
-
-            connection.runDescendentsLayout(this);
-            Util.runWebkitOverflowAutoFix(getElement());
-
-            sendClientResized();
-        }
-
-    }
-
-    /**
-     * Send new dimensions to the server.
-     */
-    private void sendClientResized() {
-        connection.updateVariable(id, "height", height, false);
-        connection.updateVariable(id, "width", width, immediate);
-    }
-
-    public native static void goTo(String url)
-    /*-{
-       $wnd.location = url;
-     }-*/;
-
-    public void onWindowClosed() {
-        // Change focus on this window in order to ensure that all state is
-        // collected from textfields
-        ITextField.flushChangesFromFocusedTextField();
-
-        // Send the closing state to server
-        connection.updateVariable(id, "close", true, false);
-        connection.sendPendingVariableChangesSync();
-    }
-
-    public String onWindowClosing() {
-        return null;
-    }
-
-    private final RenderSpace myRenderSpace = new RenderSpace() {
-        private int excessHeight = -1;
-        private int excessWidth = -1;
-
-        @Override
-        public int getHeight() {
-            return getElement().getOffsetHeight() - getExcessHeight();
-        }
-
-        private int getExcessHeight() {
-            if (excessHeight < 0) {
-                detectExcessSize();
-            }
-            return excessHeight;
-        }
-
-        private void detectExcessSize() {
-            // TODO define that iview cannot be themed and decorations should
-            // get to parent element, then get rid of this expensive and error
-            // prone function
-            final String overflow = getElement().getStyle().getProperty(
-                    "overflow");
-            getElement().getStyle().setProperty("overflow", "hidden");
-            if (BrowserInfo.get().isIE()
-                    && getElement().getPropertyInt("clientWidth") == 0) {
-                // can't detect possibly themed border/padding width in some
-                // situations (with some layout configurations), use empty div
-                // to measure width properly
-                DivElement div = Document.get().createDivElement();
-                div.setInnerHTML("&nbsp;");
-                div.getStyle().setProperty("overflow", "hidden");
-                div.getStyle().setProperty("height", "1px");
-                getElement().appendChild(div);
-                excessWidth = getElement().getOffsetWidth()
-                        - div.getOffsetWidth();
-                getElement().removeChild(div);
-            } else {
-                excessWidth = getElement().getOffsetWidth()
-                        - getElement().getPropertyInt("clientWidth");
-            }
-            excessHeight = getElement().getOffsetHeight()
-                    - getElement().getPropertyInt("clientHeight");
-
-            getElement().getStyle().setProperty("overflow", overflow);
-        }
-
-        @Override
-        public int getWidth() {
-            return getElement().getOffsetWidth() - getExcessWidth();
-        }
-
-        private int getExcessWidth() {
-            if (excessWidth < 0) {
-                detectExcessSize();
-            }
-            return excessWidth;
-        }
-
-        @Override
-        public int getScrollbarSize() {
-            return Util.getNativeScrollbarSize();
-        }
-    };
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        return myRenderSpace;
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        return (component != null && component == layout);
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        // TODO This is untested as no layouts require this
-        if (oldComponent != layout) {
-            return;
-        }
-
-        setWidget(newComponent);
-        layout = (Paintable) newComponent;
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        /*
-         * Can never propagate further and we do not want need to re-layout the
-         * layout which has caused this request.
-         */
-        return true;
-
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        // NOP Subwindows never draw caption for their first child (layout)
-    }
-
-    /**
-     * Return an iterator for current subwindows. This method is meant for
-     * testing purposes only.
-     * 
-     * @return
-     */
-    public ArrayList<IWindow> getSubWindowList() {
-        ArrayList<IWindow> windows = new ArrayList<IWindow>(subWindows.size());
-        for (IWindow widget : subWindows) {
-            windows.add(widget);
-        }
-        return windows;
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/IWindow.java b/src/com/vaadin/terminal/gwt/client/ui/IWindow.java
deleted file mode 100644 (file)
index eaa1c99..0000000
+++ /dev/null
@@ -1,1001 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui;
-
-import java.util.Iterator;
-import java.util.Set;
-import java.util.Vector;
-
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.Frame;
-import com.google.gwt.user.client.ui.HasWidgets;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.ScrollListener;
-import com.google.gwt.user.client.ui.ScrollPanel;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.RenderSpace;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-
-/**
- * "Sub window" component.
- * 
- * TODO update position / scroll position / size to client
- * 
- * @author IT Mill Ltd
- */
-public class IWindow extends IToolkitOverlay implements Container,
-        ScrollListener {
-
-    private static final int MIN_HEIGHT = 100;
-
-    private static final int MIN_WIDTH = 150;
-
-    private static Vector<IWindow> windowOrder = new Vector<IWindow>();
-
-    public static final String CLASSNAME = "i-window";
-
-    /**
-     * Pixels used by inner borders and paddings horizontally (calculated only
-     * once)
-     */
-    private int borderWidth = -1;
-
-    /**
-     * Pixels used by inner borders and paddings vertically (calculated only
-     * once)
-     */
-    private int borderHeight = -1;
-
-    private static final int STACKING_OFFSET_PIXELS = 15;
-
-    public static final int Z_INDEX = 10000;
-
-    private Paintable layout;
-
-    private Element contents;
-
-    private Element header;
-
-    private Element footer;
-
-    private Element resizeBox;
-
-    private final ScrollPanel contentPanel = new ScrollPanel();
-
-    private boolean dragging;
-
-    private int startX;
-
-    private int startY;
-
-    private int origX;
-
-    private int origY;
-
-    private boolean resizing;
-
-    private int origW;
-
-    private int origH;
-
-    private Element closeBox;
-
-    protected ApplicationConnection client;
-
-    private String id;
-
-    ShortcutActionHandler shortcutHandler;
-
-    /** Last known positionx read from UIDL or updated to application connection */
-    private int uidlPositionX = -1;
-
-    /** Last known positiony read from UIDL or updated to application connection */
-    private int uidlPositionY = -1;
-
-    private boolean vaadinModality = false;
-
-    private boolean resizable = true;
-
-    private Element modalityCurtain;
-    private Element draggingCurtain;
-
-    private Element headerText;
-
-    private boolean readonly;
-
-    boolean dynamicWidth = false;
-    boolean dynamicHeight = false;
-    boolean layoutRelativeWidth = false;
-    boolean layoutRelativeHeight = false;
-
-    // If centered (via UIDL), the window should stay in the centered -mode
-    // until a position is received from the server, or the user moves or
-    // resizes the window.
-    boolean centered = false;
-
-    private RenderSpace renderSpace = new RenderSpace(MIN_WIDTH, MIN_HEIGHT,
-            true);
-
-    private String width;
-
-    private String height;
-
-    private boolean immediate;
-
-    public IWindow() {
-        super(false, false, true); // no autohide, not modal, shadow
-        // Different style of shadow for windows
-        setShadowStyle("window");
-
-        final int order = windowOrder.size();
-        setWindowOrder(order);
-        windowOrder.add(this);
-        constructDOM();
-        setPopupPosition(order * STACKING_OFFSET_PIXELS, order
-                * STACKING_OFFSET_PIXELS);
-        contentPanel.addScrollListener(this);
-    }
-
-    private void bringToFront() {
-        int curIndex = windowOrder.indexOf(this);
-        if (curIndex + 1 < windowOrder.size()) {
-            windowOrder.remove(this);
-            windowOrder.add(this);
-            for (; curIndex < windowOrder.size(); curIndex++) {
-                windowOrder.get(curIndex).setWindowOrder(curIndex);
-            }
-        }
-    }
-
-    /**
-     * Returns true if window is the topmost window
-     * 
-     * @return
-     */
-    private boolean isActive() {
-        return windowOrder.lastElement().equals(this);
-    }
-
-    public void setWindowOrder(int order) {
-        setZIndex(order + Z_INDEX);
-    }
-
-    @Override
-    protected void setZIndex(int zIndex) {
-        super.setZIndex(zIndex);
-        if (vaadinModality) {
-            DOM.setStyleAttribute(modalityCurtain, "zIndex", "" + zIndex);
-        }
-    }
-
-    protected void constructDOM() {
-        setStyleName(CLASSNAME);
-
-        header = DOM.createDiv();
-        DOM.setElementProperty(header, "className", CLASSNAME + "-outerheader");
-        headerText = DOM.createDiv();
-        DOM.setElementProperty(headerText, "className", CLASSNAME + "-header");
-        contents = DOM.createDiv();
-        DOM.setElementProperty(contents, "className", CLASSNAME + "-contents");
-        footer = DOM.createDiv();
-        DOM.setElementProperty(footer, "className", CLASSNAME + "-footer");
-        resizeBox = DOM.createDiv();
-        DOM
-                .setElementProperty(resizeBox, "className", CLASSNAME
-                        + "-resizebox");
-        closeBox = DOM.createDiv();
-        DOM.setElementProperty(closeBox, "className", CLASSNAME + "-closebox");
-        DOM.appendChild(footer, resizeBox);
-
-        DOM.sinkEvents(getElement(), Event.ONLOSECAPTURE);
-        DOM.sinkEvents(closeBox, Event.ONCLICK);
-        DOM.sinkEvents(contents, Event.ONCLICK);
-
-        final Element wrapper = DOM.createDiv();
-        DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap");
-
-        final Element wrapper2 = DOM.createDiv();
-        DOM.setElementProperty(wrapper2, "className", CLASSNAME + "-wrap2");
-
-        DOM.sinkEvents(wrapper, Event.ONKEYDOWN);
-
-        DOM.appendChild(wrapper2, closeBox);
-        DOM.appendChild(wrapper2, header);
-        DOM.appendChild(header, headerText);
-        DOM.appendChild(wrapper2, contents);
-        DOM.appendChild(wrapper2, footer);
-        DOM.appendChild(wrapper, wrapper2);
-        DOM.appendChild(super.getContainerElement(), wrapper);
-
-        sinkEvents(Event.MOUSEEVENTS);
-
-        setWidget(contentPanel);
-
-    }
-
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        id = uidl.getId();
-        this.client = client;
-
-        // Workaround needed for Testing Tools (GWT generates window DOM
-        // slightly different in different browsers).
-        DOM.setElementProperty(closeBox, "id", id + "_window_close");
-
-        if (uidl.hasAttribute("invisible")) {
-            hide();
-            return;
-        }
-
-        if (!uidl.hasAttribute("cached")) {
-            if (uidl.getBooleanAttribute("modal") != vaadinModality) {
-                setVaadinModality(!vaadinModality);
-            }
-            if (!isAttached()) {
-                show();
-            }
-        }
-
-        if (client.updateComponent(this, uidl, false)) {
-            return;
-        }
-
-        immediate = uidl.hasAttribute("immediate");
-
-        if (uidl.getBooleanAttribute("resizable") != resizable) {
-            setResizable(!resizable);
-        }
-
-        if (isReadOnly() != uidl.getBooleanAttribute("readonly")) {
-            setReadOnly(!isReadOnly());
-        }
-
-        // Initialize the position form UIDL
-        try {
-            final int positionx = uidl.getIntVariable("positionx");
-            final int positiony = uidl.getIntVariable("positiony");
-            if (positionx >= 0 && positiony >= 0) {
-                setPopupPosition(positionx, positiony);
-            }
-        } catch (final IllegalArgumentException e) {
-            // Silently ignored as positionx and positiony are not required
-            // parameters
-        }
-
-        if (uidl.hasAttribute("caption")) {
-            setCaption(uidl.getStringAttribute("caption"), uidl
-                    .getStringAttribute("icon"));
-        }
-
-        boolean showingUrl = false;
-        int childIndex = 0;
-        UIDL childUidl = uidl.getChildUIDL(childIndex++);
-        while ("open".equals(childUidl.getTag())) {
-            // TODO multiple opens with the same target will in practice just
-            // open the last one - should we fix that somehow?
-            final String parsedUri = client.translateToolkitUri(childUidl
-                    .getStringAttribute("src"));
-            if (!childUidl.hasAttribute("name")) {
-                final Frame frame = new Frame();
-                DOM.setStyleAttribute(frame.getElement(), "width", "100%");
-                DOM.setStyleAttribute(frame.getElement(), "height", "100%");
-                DOM.setStyleAttribute(frame.getElement(), "border", "0px");
-                frame.setUrl(parsedUri);
-                contentPanel.setWidget(frame);
-                showingUrl = true;
-            } else {
-                final String target = childUidl.getStringAttribute("name");
-                Window.open(parsedUri, target, "");
-            }
-            childUidl = uidl.getChildUIDL(childIndex++);
-        }
-
-        final Paintable lo = client.getPaintable(childUidl);
-        if (layout != null) {
-            if (layout != lo) {
-                // remove old
-                client.unregisterPaintable(layout);
-                contentPanel.remove((Widget) layout);
-                // add new
-                if (!showingUrl) {
-                    contentPanel.setWidget((Widget) lo);
-                }
-                layout = lo;
-            }
-        } else if (!showingUrl) {
-            contentPanel.setWidget((Widget) lo);
-            layout = lo;
-        }
-
-        dynamicWidth = !uidl.hasAttribute("width");
-        dynamicHeight = !uidl.hasAttribute("height");
-
-        layoutRelativeWidth = uidl.hasAttribute("layoutRelativeWidth");
-        layoutRelativeHeight = uidl.hasAttribute("layoutRelativeHeight");
-
-        if (dynamicWidth && layoutRelativeWidth) {
-            /*
-             * Relative layout width, fix window width before rendering (width
-             * according to caption)
-             */
-            setNaturalWidth();
-        }
-
-        layout.updateFromUIDL(childUidl, client);
-        if (!dynamicHeight && layoutRelativeWidth) {
-            /*
-             * Relative layout width, and fixed height. Must update the size to
-             * be able to take scrollbars into account (layout gets narrower
-             * space if it is higher than the window) -> only vertical scrollbar
-             */
-            client.runDescendentsLayout(this);
-        }
-
-        /*
-         * No explicit width is set and the layout does not have relative width
-         * so fix the size according to the layout.
-         */
-        if (dynamicWidth && !layoutRelativeWidth) {
-            setNaturalWidth();
-        }
-
-        if (dynamicHeight && layoutRelativeHeight) {
-            // Prevent resizing until height has been fixed
-            resizable = false;
-        }
-
-        // we may have actions and notifications
-        if (uidl.getChildCount() > 1) {
-            final int cnt = uidl.getChildCount();
-            for (int i = 1; i < cnt; i++) {
-                childUidl = uidl.getChildUIDL(i);
-                if (childUidl.getTag().equals("actions")) {
-                    if (shortcutHandler == null) {
-                        shortcutHandler = new ShortcutActionHandler(id, client);
-                    }
-                    shortcutHandler.updateActionMap(childUidl);
-                } else if (childUidl.getTag().equals("notifications")) {
-                    // TODO needed? move ->
-                    for (final Iterator it = childUidl.getChildIterator(); it
-                            .hasNext();) {
-                        final UIDL notification = (UIDL) it.next();
-                        String html = "";
-                        if (notification.hasAttribute("icon")) {
-                            final String parsedUri = client
-                                    .translateToolkitUri(notification
-                                            .getStringAttribute("icon"));
-                            html += "<img src=\"" + parsedUri + "\" />";
-                        }
-                        if (notification.hasAttribute("caption")) {
-                            html += "<h1>"
-                                    + notification
-                                            .getStringAttribute("caption")
-                                    + "</h1>";
-                        }
-                        if (notification.hasAttribute("message")) {
-                            html += "<p>"
-                                    + notification
-                                            .getStringAttribute("message")
-                                    + "</p>";
-                        }
-
-                        final String style = notification.hasAttribute("style") ? notification
-                                .getStringAttribute("style")
-                                : null;
-                        final int position = notification
-                                .getIntAttribute("position");
-                        final int delay = notification.getIntAttribute("delay");
-                        new INotification(delay).show(html, position, style);
-                    }
-                }
-            }
-
-        }
-
-        // setting scrollposition must happen after children is rendered
-        contentPanel.setScrollPosition(uidl.getIntVariable("scrollTop"));
-        contentPanel.setHorizontalScrollPosition(uidl
-                .getIntVariable("scrollLeft"));
-
-        // Center this window on screen if requested
-        // This has to be here because we might not know the content size before
-        // everything is painted into the window
-        if (uidl.getBooleanAttribute("center")) {
-            // mark as centered - this is unset on move/resize
-            centered = true;
-            center();
-        } else {
-            // don't try to center the window anymore
-            centered = false;
-        }
-
-        updateShadowSizeAndPosition();
-
-        // ensure window is not larger than browser window
-        if (getOffsetWidth() > Window.getClientWidth()) {
-            setWidth(Window.getClientWidth() + "px");
-        }
-        if (getOffsetHeight() > Window.getClientHeight()) {
-            setHeight(Window.getClientHeight() + "px");
-        }
-
-        if (dynamicHeight && layoutRelativeHeight) {
-            /*
-             * Window height is undefined, layout is 100% high so the layout
-             * should define the initial window height but on resize the layout
-             * should be as high as the window. We fix the height to deal with
-             * this.
-             */
-
-            int h = contents.getOffsetHeight() + getExtraHeight();
-            int w = contents.getOffsetWidth();
-
-            client.updateVariable(id, "height", h, false);
-            client.updateVariable(id, "width", w, true);
-        }
-
-    }
-
-    private void setNaturalWidth() {
-        /*
-         * For some reason IE6 has title DIV set to width 100% which messes this
-         * up. Also IE6 has a 0 wide element so we use the container element.
-         */
-        int naturalWidth;
-        if (BrowserInfo.get().isIE6()) {
-            String headerW = headerText.getStyle().getProperty("width");
-            headerText.getStyle().setProperty("width", "auto");
-            naturalWidth = getElement().getOffsetWidth();
-            headerText.getStyle().setProperty("width", headerW);
-        } else {
-            // use max(layout width, window width)
-            // i.e layout content width or caption width
-            int lowidth = contentPanel.getElement().getScrollWidth()
-                    + borderWidth; // layout does not know about border
-            int elwidth = getElement().getOffsetWidth();
-            naturalWidth = (lowidth > elwidth ? lowidth : elwidth);
-        }
-
-        setWidth(naturalWidth + "px");
-    }
-
-    private void setReadOnly(boolean readonly) {
-        this.readonly = readonly;
-        if (readonly) {
-            DOM.setStyleAttribute(closeBox, "display", "none");
-        } else {
-            DOM.setStyleAttribute(closeBox, "display", "");
-        }
-    }
-
-    private boolean isReadOnly() {
-        return readonly;
-    }
-
-    @Override
-    public void show() {
-        if (vaadinModality) {
-            showModalityCurtain();
-        }
-        super.show();
-
-        setFF2CaretFixEnabled(true);
-        fixFF3OverflowBug();
-    }
-
-    /** Disable overflow auto with FF3 to fix #1837. */
-    private void fixFF3OverflowBug() {
-        if (BrowserInfo.get().isFF3()) {
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    DOM.setStyleAttribute(getElement(), "overflow", "");
-                }
-            });
-        }
-    }
-
-    /**
-     * Fix "missing cursor" browser bug workaround for FF2 in Windows and Linux.
-     * 
-     * Calling this method has no effect on other browsers than the ones based
-     * on Gecko 1.8
-     * 
-     * @param enable
-     */
-    private void setFF2CaretFixEnabled(boolean enable) {
-        if (BrowserInfo.get().isFF2()) {
-            if (enable) {
-                DeferredCommand.addCommand(new Command() {
-                    public void execute() {
-                        DOM.setStyleAttribute(getElement(), "overflow", "auto");
-                    }
-                });
-            } else {
-                DOM.setStyleAttribute(getElement(), "overflow", "");
-            }
-        }
-    }
-
-    @Override
-    public void hide() {
-        if (vaadinModality) {
-            hideModalityCurtain();
-        }
-        super.hide();
-    }
-
-    private void setVaadinModality(boolean modality) {
-        vaadinModality = modality;
-        if (vaadinModality) {
-            modalityCurtain = DOM.createDiv();
-            DOM.setElementProperty(modalityCurtain, "className", CLASSNAME
-                    + "-modalitycurtain");
-            if (isAttached()) {
-                showModalityCurtain();
-                bringToFront();
-            } else {
-                DeferredCommand.addCommand(new Command() {
-                    public void execute() {
-                        // vaadinModality window must on top of others
-                        bringToFront();
-                    }
-                });
-            }
-        } else {
-            if (modalityCurtain != null) {
-                if (isAttached()) {
-                    hideModalityCurtain();
-                }
-                modalityCurtain = null;
-            }
-        }
-    }
-
-    private void showModalityCurtain() {
-        if (BrowserInfo.get().isFF2()) {
-            DOM.setStyleAttribute(modalityCurtain, "height", DOM
-                    .getElementPropertyInt(RootPanel.getBodyElement(),
-                            "offsetHeight")
-                    + "px");
-            DOM.setStyleAttribute(modalityCurtain, "position", "absolute");
-        }
-        DOM.setStyleAttribute(modalityCurtain, "zIndex", ""
-                + (windowOrder.indexOf(this) + Z_INDEX));
-        DOM.appendChild(RootPanel.getBodyElement(), modalityCurtain);
-    }
-
-    private void hideModalityCurtain() {
-        DOM.removeChild(RootPanel.getBodyElement(), modalityCurtain);
-    }
-
-    /*
-     * 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.
-     */
-    private void showDraggingCurtain(boolean show) {
-        if (show && draggingCurtain == null) {
-
-            setFF2CaretFixEnabled(false); // makes FF2 slow
-
-            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", ""
-                    + IToolkitOverlay.Z_INDEX);
-
-            DOM.appendChild(RootPanel.getBodyElement(), draggingCurtain);
-        } else if (!show && draggingCurtain != null) {
-
-            setFF2CaretFixEnabled(true); // makes FF2 slow
-
-            DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain);
-            draggingCurtain = null;
-        }
-
-    }
-
-    private void setResizable(boolean resizability) {
-        resizable = resizability;
-        if (resizability) {
-            DOM.setElementProperty(resizeBox, "className", CLASSNAME
-                    + "-resizebox");
-        } else {
-            DOM.setElementProperty(resizeBox, "className", CLASSNAME
-                    + "-resizebox " + CLASSNAME + "-resizebox-disabled");
-        }
-    }
-
-    @Override
-    public void setPopupPosition(int left, int top) {
-        super.setPopupPosition(left, top);
-        if (left != uidlPositionX && client != null) {
-            client.updateVariable(id, "positionx", left, false);
-            uidlPositionX = left;
-        }
-        if (top != uidlPositionY && client != null) {
-            client.updateVariable(id, "positiony", top, false);
-            uidlPositionY = top;
-        }
-    }
-
-    public void setCaption(String c) {
-        setCaption(c, null);
-    }
-
-    public void setCaption(String c, String icon) {
-        String html = Util.escapeHTML(c);
-        if (icon != null) {
-            icon = client.translateToolkitUri(icon);
-            html = "<img src=\"" + icon + "\" class=\"i-icon\" />" + html;
-        }
-        DOM.setInnerHTML(headerText, html);
-    }
-
-    @Override
-    protected Element getContainerElement() {
-        // in GWT 1.5 this method is used in PopupPanel constructor
-        if (contents == null) {
-            return super.getContainerElement();
-        }
-        return contents;
-    }
-
-    @Override
-    public void onBrowserEvent(final Event event) {
-        if (event != null) {
-            final int type = event.getTypeInt();
-
-            if (type == Event.ONKEYDOWN && shortcutHandler != null) {
-                shortcutHandler.handleKeyboardEvent(event);
-                return;
-            }
-
-            final Element target = DOM.eventGetTarget(event);
-
-            // Handle window caption tooltips
-            if (client != null && DOM.isOrHasChild(header, target)) {
-                client.handleTooltipEvent(event, this);
-            }
-
-            if (resizing || resizeBox == target) {
-                onResizeEvent(event);
-                event.cancelBubble(true);
-            } else if (target == closeBox) {
-                if (type == Event.ONCLICK) {
-                    onCloseClick();
-                    event.cancelBubble(true);
-                }
-            } else if (dragging || !DOM.isOrHasChild(contents, target)) {
-                onDragEvent(event);
-                event.cancelBubble(true);
-            } else if (type == Event.ONCLICK) {
-                // clicked inside window, ensure to be on top
-                if (!isActive()) {
-                    bringToFront();
-                }
-            }
-        }
-    }
-
-    private void onCloseClick() {
-        client.updateVariable(id, "close", true, true);
-    }
-
-    private void onResizeEvent(Event event) {
-        if (resizable) {
-            switch (event.getTypeInt()) {
-            case Event.ONMOUSEDOWN:
-                if (!isActive()) {
-                    bringToFront();
-                }
-                showDraggingCurtain(true);
-                if (BrowserInfo.get().isIE()) {
-                    DOM.setStyleAttribute(resizeBox, "visibility", "hidden");
-                }
-                resizing = true;
-                startX = event.getScreenX();
-                startY = event.getScreenY();
-                origW = getElement().getOffsetWidth();
-                origH = getElement().getOffsetHeight();
-                DOM.setCapture(getElement());
-                event.preventDefault();
-                break;
-            case Event.ONMOUSEUP:
-                showDraggingCurtain(false);
-                if (BrowserInfo.get().isIE()) {
-                    DOM.setStyleAttribute(resizeBox, "visibility", "");
-                }
-                resizing = false;
-                DOM.releaseCapture(getElement());
-                setSize(event, true);
-                break;
-            case Event.ONLOSECAPTURE:
-                showDraggingCurtain(false);
-                if (BrowserInfo.get().isIE()) {
-                    DOM.setStyleAttribute(resizeBox, "visibility", "");
-                }
-                resizing = false;
-            case Event.ONMOUSEMOVE:
-                if (resizing) {
-                    centered = false;
-                    setSize(event, false);
-                    event.preventDefault();
-                }
-                break;
-            default:
-                event.preventDefault();
-                break;
-            }
-        }
-    }
-
-    private void setSize(Event event, boolean updateVariables) {
-        int w = event.getScreenX() - startX + origW;
-        if (w < MIN_WIDTH + borderWidth) {
-            w = MIN_WIDTH + borderWidth;
-        }
-
-        int h = event.getScreenY() - startY + origH;
-        if (h < MIN_HEIGHT + getExtraHeight()) {
-            h = MIN_HEIGHT + getExtraHeight();
-        }
-
-        setWidth(w + "px");
-        setHeight(h + "px");
-
-        if (updateVariables) {
-            // sending width back always as pixels, no need for unit
-            client.updateVariable(id, "width", w, false);
-            client.updateVariable(id, "height", h, immediate);
-        }
-
-        // Update child widget dimensions
-        if (client != null) {
-            client.handleComponentRelativeSize((Widget) layout);
-            client.runDescendentsLayout((HasWidgets) layout);
-        }
-
-        Util.runWebkitOverflowAutoFix(contentPanel.getElement());
-    }
-
-    @Override
-    /*
-     * Width is set to the out-most element (i-window).
-     * 
-     * This function should never be called with percentage values (it will
-     * throw an exception)
-     */
-    public void setWidth(String width) {
-        this.width = width;
-        if (!isAttached()) {
-            return;
-        }
-        if (width != null && !"".equals(width)) {
-            int pixelWidth;
-            // Convert non-pixel values to pixels
-            if (width.indexOf("px") < 0) {
-                DOM.setStyleAttribute(getElement(), "width", width);
-                pixelWidth = getElement().getOffsetWidth();
-                width = pixelWidth + "px";
-            }
-            if (BrowserInfo.get().isIE6()) {
-                getElement().getStyle().setProperty("overflow", "hidden");
-            }
-            getElement().getStyle().setProperty("width", width);
-
-            pixelWidth = getElement().getOffsetWidth() - borderWidth;
-            if (pixelWidth < MIN_WIDTH) {
-                pixelWidth = MIN_WIDTH;
-                int rootWidth = pixelWidth + borderWidth;
-                DOM.setStyleAttribute(getElement(), "width", rootWidth + "px");
-            }
-
-            renderSpace.setWidth(pixelWidth);
-
-            // IE6 needs the actual inner content width on the content element,
-            // otherwise it won't wrap the content properly (no scrollbars
-            // appear, content flows out of window)
-            if (BrowserInfo.get().isIE6()) {
-                DOM.setStyleAttribute(contentPanel.getElement(), "width",
-                        pixelWidth + "px");
-            }
-            updateShadowSizeAndPosition();
-        }
-    }
-
-    @Override
-    /*
-     * Height is set to the out-most element (i-window).
-     * 
-     * This function should never be called with percentage values (it will
-     * throw an exception)
-     */
-    public void setHeight(String height) {
-        this.height = height;
-        if (!isAttached()) {
-            return;
-        }
-        if (height != null && !"".equals(height)) {
-            DOM.setStyleAttribute(getElement(), "height", height);
-            int pixels = getElement().getOffsetHeight() - getExtraHeight();
-            if (pixels < MIN_HEIGHT) {
-                pixels = MIN_HEIGHT;
-                int rootHeight = pixels + getExtraHeight();
-                DOM.setStyleAttribute(getElement(), "height", (rootHeight)
-                        + "px");
-
-            }
-            renderSpace.setHeight(pixels);
-            height = pixels + "px";
-            contentPanel.getElement().getStyle().setProperty("height", height);
-            updateShadowSizeAndPosition();
-
-        }
-    }
-
-    private int extraH = 0;
-
-    private int getExtraHeight() {
-        extraH = header.getOffsetHeight() + footer.getOffsetHeight();
-        return extraH;
-    }
-
-    private void onDragEvent(Event event) {
-        switch (DOM.eventGetType(event)) {
-        case Event.ONMOUSEDOWN:
-            if (!isActive()) {
-                bringToFront();
-            }
-            showDraggingCurtain(true);
-            dragging = true;
-            startX = DOM.eventGetScreenX(event);
-            startY = DOM.eventGetScreenY(event);
-            origX = DOM.getAbsoluteLeft(getElement());
-            origY = DOM.getAbsoluteTop(getElement());
-            DOM.setCapture(getElement());
-            DOM.eventPreventDefault(event);
-            break;
-        case Event.ONMOUSEUP:
-            dragging = false;
-            showDraggingCurtain(false);
-            DOM.releaseCapture(getElement());
-            break;
-        case Event.ONLOSECAPTURE:
-            showDraggingCurtain(false);
-            dragging = false;
-            break;
-        case Event.ONMOUSEMOVE:
-            if (dragging) {
-                centered = false;
-                final int x = DOM.eventGetScreenX(event) - startX + origX;
-                final int y = DOM.eventGetScreenY(event) - startY + origY;
-                setPopupPosition(x, y);
-                DOM.eventPreventDefault(event);
-            }
-            break;
-        default:
-            break;
-        }
-    }
-
-    @Override
-    public boolean onEventPreview(Event event) {
-        if (dragging) {
-            onDragEvent(event);
-            return false;
-        } else if (resizing) {
-            onResizeEvent(event);
-            return false;
-        } else if (vaadinModality) {
-            // return false when modal and outside window
-            final Element target = event.getTarget().cast();
-            if (!DOM.isOrHasChild(getElement(), target)) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    public void onScroll(Widget widget, int scrollLeft, int scrollTop) {
-        client.updateVariable(id, "scrollTop", scrollTop, false);
-        client.updateVariable(id, "scrollLeft", scrollLeft, false);
-    }
-
-    @Override
-    public void addStyleDependentName(String styleSuffix) {
-        // IWindow's getStyleElement() does not return the same element as
-        // getElement(), so we need to override this.
-        setStyleName(getElement(), getStylePrimaryName() + "-" + styleSuffix,
-                true);
-    }
-
-    @Override
-    protected void onAttach() {
-        super.onAttach();
-
-        // Calculate space required by window borders, so we can accurately
-        // calculate space for content
-
-        // IE (IE6 especially) requires some magic tricks to pull the border
-        // size correctly (remember that we want to accomodate for paddings as
-        // well)
-        if (BrowserInfo.get().isIE()) {
-            DOM.setStyleAttribute(contents, "width", "7000px");
-            DOM.setStyleAttribute(contentPanel.getElement(), "width", "7000px");
-            int contentWidth = DOM.getElementPropertyInt(contentPanel
-                    .getElement(), "offsetWidth");
-            contentWidth = DOM.getElementPropertyInt(contentPanel.getElement(),
-                    "offsetWidth");
-            final int windowWidth = DOM.getElementPropertyInt(getElement(),
-                    "offsetWidth");
-            DOM.setStyleAttribute(contentPanel.getElement(), "width", "");
-            DOM.setStyleAttribute(contents, "width", "");
-
-            borderWidth = windowWidth - contentWidth;
-        }
-
-        // Standards based browsers get away with it a little easier :)
-        else {
-            final int contentWidth = DOM.getElementPropertyInt(contentPanel
-                    .getElement(), "offsetWidth");
-            final int windowWidth = DOM.getElementPropertyInt(getElement(),
-                    "offsetWidth");
-            borderWidth = windowWidth - contentWidth;
-        }
-
-        setWidth(width);
-        setHeight(height);
-
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        if (child == layout) {
-            return renderSpace;
-        } else {
-            // Exception ??
-            return null;
-        }
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (component == layout) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        contentPanel.setWidget(newComponent);
-    }
-
-    public boolean requestLayout(Set<Paintable> child) {
-        if (dynamicWidth && !layoutRelativeWidth) {
-            setNaturalWidth();
-        }
-        if (centered) {
-            center();
-        }
-        updateShadowSizeAndPosition();
-        return true;
-    }
-
-    public void updateCaption(Paintable component, UIDL uidl) {
-        // NOP, window has own caption, layout captio not rendered
-    }
-
-}
index a711864a37a0263d875fa4092f1478352a730cc8..88de95cb3853719b50779606fd3545f3bf0bdce8 100644 (file)
@@ -376,7 +376,7 @@ public class MenuBar extends Widget implements PopupListener {
         // Create a new popup for this item, and position it next to
         // the item (below if this is a horizontal menu bar, to the
         // right if it's a vertical bar).
-        popup = new IToolkitOverlay(true) {
+        popup = new VToolkitOverlay(true) {
             {
                 setWidget(item.getSubMenu());
                 item.getSubMenu().onShow();
index a77730f74965928867669b99332d3e971aa03216..641b729521fefeb301052daed9f1d12dd38675e8 100644 (file)
@@ -5,7 +5,7 @@
 package com.vaadin.terminal.gwt.client.ui;
 
 /**
- * This class is used for "row actions" in ITree and ITable
+ * This class is used for "row actions" in VTree and ITable
  */
 public class TreeAction extends Action {
 
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VAbsoluteLayout.java
new file mode 100644 (file)
index 0000000..b7b7aa1
--- /dev/null
@@ -0,0 +1,378 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VAbsoluteLayout extends ComplexPanel implements Container {
+
+    /** Tag name for widget creation */
+    public static final String TAGNAME = "absolutelayout";
+
+    /** Class name, prefix in styling */
+    public static final String CLASSNAME = "i-absolutelayout";
+
+    private DivElement marginElement;
+
+    protected final Element canvas = DOM.createDiv();
+
+    private int excessPixelsHorizontal;
+
+    private int excessPixelsVertical;
+
+    private Object previousStyleName;
+
+    private Map<String, AbsoluteWrapper> pidToComponentWrappper = new HashMap<String, AbsoluteWrapper>();
+
+    protected ApplicationConnection client;
+
+    private boolean rendering;
+
+    public VAbsoluteLayout() {
+        setElement(Document.get().createDivElement());
+        setStyleName(CLASSNAME);
+        marginElement = Document.get().createDivElement();
+        canvas.getStyle().setProperty("position", "relative");
+        marginElement.appendChild(canvas);
+        getElement().appendChild(marginElement);
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        // TODO needs some special handling for components with only on edge
+        // horizontally or vertically defined
+        AbsoluteWrapper wrapper = (AbsoluteWrapper) child.getParent();
+        int w;
+        if (wrapper.left != null && wrapper.right != null) {
+            w = wrapper.getOffsetWidth();
+        } else if (wrapper.right != null) {
+            // left == null
+            // available width == right edge == offsetleft + width
+            w = wrapper.getOffsetWidth() + wrapper.getElement().getOffsetLeft();
+        } else {
+            // left != null && right == null || left == null &&
+            // right == null
+            // available width == canvas width - offset left
+            w = canvas.getOffsetWidth() - wrapper.getElement().getOffsetLeft();
+        }
+        int h;
+        if (wrapper.top != null && wrapper.bottom != null) {
+            h = wrapper.getOffsetHeight();
+        } else if (wrapper.bottom != null) {
+            // top not defined, available space 0... bottom of wrapper
+            h = wrapper.getElement().getOffsetTop() + wrapper.getOffsetHeight();
+        } else {
+            // top defined or both undefined, available space == canvas - top
+            h = canvas.getOffsetHeight() - wrapper.getElement().getOffsetTop();
+        }
+
+        return new RenderSpace(w, h);
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        for (Iterator<Entry<String, AbsoluteWrapper>> iterator = pidToComponentWrappper
+                .entrySet().iterator(); iterator.hasNext();) {
+            if (iterator.next().getValue().paintable == component) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        for (Widget wrapper : getChildren()) {
+            AbsoluteWrapper w = (AbsoluteWrapper) wrapper;
+            if (w.getWidget() == oldComponent) {
+                w.setWidget(newComponent);
+                return;
+            }
+        }
+    }
+
+    public boolean requestLayout(Set<Paintable> children) {
+        // component inside an absolute panel never affects parent nor the
+        // layout
+        return true;
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        AbsoluteWrapper parent2 = (AbsoluteWrapper) ((Widget) component)
+                .getParent();
+        parent2.updateCaption(uidl);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+        this.client = client;
+        // TODO margin handling
+        if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
+            return;
+        }
+
+        HashSet<String> unrenderedPids = new HashSet<String>(
+                pidToComponentWrappper.keySet());
+
+        for (Iterator<UIDL> childIterator = uidl.getChildIterator(); childIterator
+                .hasNext();) {
+            UIDL cc = childIterator.next();
+            UIDL componentUIDL = cc.getChildUIDL(0);
+            unrenderedPids.remove(componentUIDL.getId());
+            getWrapper(client, componentUIDL).updateFromUIDL(cc);
+        }
+
+        for (String pid : unrenderedPids) {
+            AbsoluteWrapper absoluteWrapper = pidToComponentWrappper.get(pid);
+            pidToComponentWrappper.remove(pid);
+            absoluteWrapper.destroy();
+        }
+        rendering = false;
+    }
+
+    private AbsoluteWrapper getWrapper(ApplicationConnection client,
+            UIDL componentUIDL) {
+        AbsoluteWrapper wrapper = pidToComponentWrappper.get(componentUIDL
+                .getId());
+        if (wrapper == null) {
+            wrapper = new AbsoluteWrapper(client.getPaintable(componentUIDL));
+            pidToComponentWrappper.put(componentUIDL.getId(), wrapper);
+            add(wrapper);
+        }
+        return wrapper;
+
+    }
+
+    @Override
+    public void add(Widget child) {
+        super.add(child, canvas);
+    }
+
+    @Override
+    public void setStyleName(String style) {
+        super.setStyleName(style);
+        if (previousStyleName == null || !previousStyleName.equals(style)) {
+            excessPixelsHorizontal = -1;
+            excessPixelsVertical = -1;
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        super.setWidth(width);
+        // TODO do this so that canvas gets the sized properly (the area
+        // inside marginals)
+        canvas.getStyle().setProperty("width", width);
+
+        if (!rendering) {
+            if (BrowserInfo.get().isIE6()) {
+                relayoutWrappersForIe6();
+            }
+            relayoutRelativeChildren();
+        }
+    }
+
+    private void relayoutRelativeChildren() {
+        for (Widget widget : getChildren()) {
+            if (widget instanceof AbsoluteWrapper) {
+                AbsoluteWrapper w = (AbsoluteWrapper) widget;
+                client.handleComponentRelativeSize(w.getWidget());
+                w.updateCaptionPosition();
+            }
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        // TODO do this so that canvas gets the sized properly (the area
+        // inside marginals)
+        canvas.getStyle().setProperty("height", height);
+
+        if (!rendering) {
+            if (BrowserInfo.get().isIE6()) {
+                relayoutWrappersForIe6();
+            }
+            relayoutRelativeChildren();
+        }
+    }
+
+    private void relayoutWrappersForIe6() {
+        for (Widget wrapper : getChildren()) {
+            if (wrapper instanceof AbsoluteWrapper) {
+                ((AbsoluteWrapper) wrapper).ie6Layout();
+            }
+        }
+    }
+
+    public class AbsoluteWrapper extends SimplePanel {
+        private String css;
+        private String left;
+        private String top;
+        private String right;
+        private String bottom;
+        private String zIndex;
+
+        private Paintable paintable;
+        private VCaption caption;
+
+        public AbsoluteWrapper(Paintable paintable) {
+            this.paintable = paintable;
+            setStyleName(CLASSNAME + "-wrapper");
+        }
+
+        public void updateCaption(UIDL uidl) {
+
+            boolean captionIsNeeded = VCaption.isNeeded(uidl);
+            if (captionIsNeeded) {
+                if (caption == null) {
+                    caption = new VCaption(paintable, client);
+                    VAbsoluteLayout.this.add(caption);
+                }
+                caption.updateCaption(uidl);
+                updateCaptionPosition();
+            } else {
+                if (caption != null) {
+                    caption.removeFromParent();
+                    caption = null;
+                }
+            }
+        }
+
+        public void destroy() {
+            if (caption != null) {
+                caption.removeFromParent();
+            }
+            client.unregisterPaintable(paintable);
+            removeFromParent();
+        }
+
+        public void updateFromUIDL(UIDL componentUIDL) {
+            setPosition(componentUIDL.getStringAttribute("css"));
+            if (getWidget() != paintable) {
+                setWidget((Widget) paintable);
+            }
+            UIDL childUIDL = componentUIDL.getChildUIDL(0);
+            paintable.updateFromUIDL(childUIDL, client);
+            if (childUIDL.hasAttribute("cached")) {
+                // child may need relative size adjustment if wrapper details
+                // have changed this could be optimized (check if wrapper size
+                // has changed)
+                client.handleComponentRelativeSize((Widget) paintable);
+            }
+        }
+
+        public void setPosition(String stringAttribute) {
+            if (css == null || !css.equals(stringAttribute)) {
+                css = stringAttribute;
+                top = right = bottom = left = zIndex = null;
+                if (!css.equals("")) {
+                    String[] properties = css.split(";");
+                    for (int i = 0; i < properties.length; i++) {
+                        String[] keyValue = properties[i].split(":");
+                        if (keyValue[0].equals("left")) {
+                            left = keyValue[1];
+                        } else if (keyValue[0].equals("top")) {
+                            top = keyValue[1];
+                        } else if (keyValue[0].equals("right")) {
+                            right = keyValue[1];
+                        } else if (keyValue[0].equals("bottom")) {
+                            bottom = keyValue[1];
+                        } else if (keyValue[0].equals("z-index")) {
+                            zIndex = keyValue[1];
+                        }
+                    }
+                }
+                // ensure ne values
+                Style style = getElement().getStyle();
+                style.setProperty("zIndex", zIndex);
+                style.setProperty("top", top);
+                style.setProperty("left", left);
+                style.setProperty("right", right);
+                style.setProperty("bottom", bottom);
+
+                if (BrowserInfo.get().isIE6()) {
+                    ie6Layout();
+                }
+            }
+            updateCaptionPosition();
+        }
+
+        private void updateCaptionPosition() {
+            if (caption != null) {
+                Style style = caption.getElement().getStyle();
+                style.setProperty("position", "absolute");
+                style.setPropertyPx("left", getElement().getOffsetLeft());
+                style.setPropertyPx("top", getElement().getOffsetTop()
+                        - caption.getHeight());
+            }
+        }
+
+        private void ie6Layout() {
+            // special handling for IE6 is needed, it does not support
+            // setting both left/right or top/bottom
+            Style style = getElement().getStyle();
+            if (bottom != null && top != null) {
+                // define height for wrapper to simulate bottom property
+                int bottompixels = measureForIE6(bottom);
+                ApplicationConnection.getConsole().log("ALB" + bottompixels);
+                int height = canvas.getOffsetHeight() - bottompixels
+                        - getElement().getOffsetTop();
+                ApplicationConnection.getConsole().log("ALB" + height);
+                if (height < 0) {
+                    height = 0;
+                }
+                style.setPropertyPx("height", height);
+            } else {
+                // reset possibly existing value
+                style.setProperty("height", "");
+            }
+            if (left != null && right != null) {
+                // define width for wrapper to simulate right property
+                int rightPixels = measureForIE6(right);
+                ApplicationConnection.getConsole().log("ALR" + rightPixels);
+                int width = canvas.getOffsetWidth() - rightPixels
+                        - getElement().getOffsetWidth();
+                ApplicationConnection.getConsole().log("ALR" + width);
+                if (width < 0) {
+                    width = 0;
+                }
+                style.setPropertyPx("width", width);
+            } else {
+                // reset possibly existing value
+                style.setProperty("width", "");
+            }
+        }
+
+    }
+
+    private Element measureElement;
+
+    private int measureForIE6(String cssLength) {
+        if (measureElement == null) {
+            measureElement = DOM.createDiv();
+            measureElement.getStyle().setProperty("position", "absolute");
+            canvas.appendChild(measureElement);
+        }
+        measureElement.getStyle().setProperty("width", cssLength);
+        return measureElement.getOffsetWidth();
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java b/src/com/vaadin/terminal/gwt/client/ui/VAccordion.java
new file mode 100644 (file)
index 0000000..cda5b3a
--- /dev/null
@@ -0,0 +1,647 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderInformation;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VAccordion extends VTabsheetBase implements
+        ContainerResizedListener {
+
+    public static final String CLASSNAME = "i-accordion";
+
+    private Set<Paintable> paintables = new HashSet<Paintable>();
+
+    private String height;
+
+    private String width = "";
+
+    private HashMap<StackItem, UIDL> lazyUpdateMap = new HashMap<StackItem, UIDL>();
+
+    private RenderSpace renderSpace = new RenderSpace(0, 0, true);
+
+    private StackItem openTab = null;
+
+    private boolean rendering = false;
+
+    private int selectedUIDLItemIndex = -1;
+
+    private RenderInformation renderInformation = new RenderInformation();
+
+    public VAccordion() {
+        super(CLASSNAME);
+        // IE6 needs this to calculate offsetHeight correctly
+        if (BrowserInfo.get().isIE6()) {
+            DOM.setStyleAttribute(getElement(), "zoom", "1");
+        }
+    }
+
+    @Override
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+        selectedUIDLItemIndex = -1;
+        super.updateFromUIDL(uidl, client);
+        /*
+         * Render content after all tabs have been created and we know how large
+         * the content area is
+         */
+        if (selectedUIDLItemIndex >= 0) {
+            StackItem selectedItem = getStackItem(selectedUIDLItemIndex);
+            UIDL selectedTabUIDL = lazyUpdateMap.remove(selectedItem);
+            open(selectedUIDLItemIndex);
+
+            selectedItem.setContent(selectedTabUIDL);
+        } else if (!uidl.getBooleanAttribute("cached") && openTab != null) {
+            close(openTab);
+        }
+
+        iLayout();
+        // finally render possible hidden tabs
+        if (lazyUpdateMap.size() > 0) {
+            for (Iterator iterator = lazyUpdateMap.keySet().iterator(); iterator
+                    .hasNext();) {
+                StackItem item = (StackItem) iterator.next();
+                item.setContent(lazyUpdateMap.get(item));
+            }
+            lazyUpdateMap.clear();
+        }
+
+        renderInformation.updateSize(getElement());
+
+        rendering = false;
+    }
+
+    @Override
+    protected void renderTab(UIDL tabUidl, int index, boolean selected,
+            boolean hidden) {
+        StackItem item;
+        int itemIndex;
+        if (getWidgetCount() <= index) {
+            // Create stackItem and render caption
+            item = new StackItem(tabUidl);
+            if (getWidgetCount() == 0) {
+                item.addStyleDependentName("first");
+            }
+            itemIndex = getWidgetCount();
+            add(item, getElement());
+        } else {
+            item = getStackItem(index);
+            item = moveStackItemIfNeeded(item, index, tabUidl);
+            itemIndex = index;
+        }
+        item.updateCaption(tabUidl);
+
+        item.setVisible(!hidden);
+
+        if (selected) {
+            selectedUIDLItemIndex = itemIndex;
+        }
+
+        if (tabUidl.getChildCount() > 0) {
+            lazyUpdateMap.put(item, tabUidl.getChildUIDL(0));
+        }
+    }
+
+    /**
+     * This method tries to find out if a tab has been rendered with a different
+     * index previously. If this is the case it re-orders the children so the
+     * same StackItem is used for rendering this time. E.g. if the first tab has
+     * been removed all tabs which contain cached content must be moved 1 step
+     * up to preserve the cached content.
+     * 
+     * @param item
+     * @param newIndex
+     * @param tabUidl
+     * @return
+     */
+    private StackItem moveStackItemIfNeeded(StackItem item, int newIndex,
+            UIDL tabUidl) {
+        UIDL tabContentUIDL = null;
+        Paintable tabContent = null;
+        if (tabUidl.getChildCount() > 0) {
+            tabContentUIDL = tabUidl.getChildUIDL(0);
+            tabContent = client.getPaintable(tabContentUIDL);
+        }
+
+        Widget itemWidget = item.getComponent();
+        if (tabContent != null) {
+            if (tabContent != itemWidget) {
+                /*
+                 * This is not the same widget as before, find out if it has
+                 * been moved
+                 */
+                int oldIndex = -1;
+                StackItem oldItem = null;
+                for (int i = 0; i < getWidgetCount(); i++) {
+                    Widget w = getWidget(i);
+                    oldItem = (StackItem) w;
+                    if (tabContent == oldItem.getComponent()) {
+                        oldIndex = i;
+                        break;
+                    }
+                }
+
+                if (oldIndex != -1 && oldIndex > newIndex) {
+                    /*
+                     * The tab has previously been rendered in another position
+                     * so we must move the cached content to correct position.
+                     * We move only items with oldIndex > newIndex to prevent
+                     * moving items already rendered in this update. If for
+                     * instance tabs 1,2,3 are removed and added as 3,2,1 we
+                     * cannot re-use "1" when we get to the third tab.
+                     */
+                    insert(oldItem, getElement(), newIndex, true);
+                    return oldItem;
+                }
+            }
+        } else {
+            // Tab which has never been loaded. Must assure we use an empty
+            // StackItem
+            Widget oldWidget = item.getComponent();
+            if (oldWidget != null) {
+                item = new StackItem(tabUidl);
+                insert(item, getElement(), newIndex, true);
+            }
+        }
+        return item;
+    }
+
+    private void open(int itemIndex) {
+        StackItem item = (StackItem) getWidget(itemIndex);
+        boolean alreadyOpen = false;
+        if (openTab != null) {
+            if (openTab.isOpen()) {
+                if (openTab == item) {
+                    alreadyOpen = true;
+                } else {
+                    openTab.close();
+                }
+            }
+        }
+
+        if (!alreadyOpen) {
+            item.open();
+            activeTabIndex = itemIndex;
+            openTab = item;
+        }
+
+        // Update the size for the open tab
+        updateOpenTabSize();
+    }
+
+    private void close(StackItem item) {
+        if (!item.isOpen()) {
+            return;
+        }
+
+        item.close();
+        activeTabIndex = -1;
+        openTab = null;
+
+    }
+
+    @Override
+    protected void selectTab(final int index, final UIDL contentUidl) {
+        StackItem item = getStackItem(index);
+        if (index != activeTabIndex) {
+            open(index);
+            iLayout();
+            // TODO Check if this is needed
+            client.runDescendentsLayout(this);
+
+        }
+        item.setContent(contentUidl);
+    }
+
+    public void onSelectTab(StackItem item) {
+        final int index = getWidgetIndex(item);
+        if (index != activeTabIndex && !disabled && !readonly
+                && !disabledTabKeys.contains(tabKeys.get(index))) {
+            addStyleDependentName("loading");
+            client
+                    .updateVariable(id, "selected", "" + tabKeys.get(index),
+                            true);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (this.width.equals(width)) {
+            return;
+        }
+
+        super.setWidth(width);
+        this.width = width;
+        if (!rendering) {
+            updateOpenTabSize();
+
+            if (isDynamicHeight()) {
+                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client,
+                        openTab, this);
+                updateOpenTabSize();
+            }
+
+            if (isDynamicHeight()) {
+                openTab.setHeightFromWidget();
+            }
+            iLayout();
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        this.height = height;
+
+        if (!rendering) {
+            updateOpenTabSize();
+        }
+
+    }
+
+    /**
+     * Sets the size of the open tab
+     */
+    private void updateOpenTabSize() {
+        if (openTab == null) {
+            renderSpace.setHeight(0);
+            renderSpace.setWidth(0);
+            return;
+        }
+
+        // WIDTH
+        if (!isDynamicWidth()) {
+            int w = getOffsetWidth();
+            openTab.setWidth(w);
+            renderSpace.setWidth(w);
+        } else {
+            renderSpace.setWidth(0);
+        }
+
+        // HEIGHT
+        if (!isDynamicHeight()) {
+            int usedPixels = 0;
+            for (Widget w : getChildren()) {
+                StackItem item = (StackItem) w;
+                if (item == openTab) {
+                    usedPixels += item.getCaptionHeight();
+                } else {
+                    // This includes the captionNode borders
+                    usedPixels += item.getHeight();
+                }
+            }
+
+            int offsetHeight = getOffsetHeight();
+
+            int spaceForOpenItem = offsetHeight - usedPixels;
+
+            if (spaceForOpenItem < 0) {
+                spaceForOpenItem = 0;
+            }
+
+            renderSpace.setHeight(spaceForOpenItem);
+            openTab.setHeight(spaceForOpenItem);
+        } else {
+            renderSpace.setHeight(0);
+            openTab.setHeightFromWidget();
+
+        }
+
+    }
+
+    public void iLayout() {
+        if (openTab == null) {
+            return;
+        }
+
+        if (isDynamicWidth()) {
+            int maxWidth = 40;
+            for (Widget w : getChildren()) {
+                StackItem si = (StackItem) w;
+                int captionWidth = si.getCaptionWidth();
+                if (captionWidth > maxWidth) {
+                    maxWidth = captionWidth;
+                }
+            }
+            int widgetWidth = openTab.getWidgetWidth();
+            if (widgetWidth > maxWidth) {
+                maxWidth = widgetWidth;
+            }
+            super.setWidth(maxWidth + "px");
+            openTab.setWidth(maxWidth);
+        }
+
+        Util.runWebkitOverflowAutoFix(openTab.getContainerElement());
+
+    }
+
+    /**
+     * 
+     */
+    protected class StackItem extends ComplexPanel implements ClickListener {
+
+        public void setHeight(int height) {
+            if (height == -1) {
+                super.setHeight("");
+                DOM.setStyleAttribute(content, "height", "0px");
+            } else {
+                super.setHeight((height + getCaptionHeight()) + "px");
+                DOM.setStyleAttribute(content, "height", height + "px");
+                DOM
+                        .setStyleAttribute(content, "top", getCaptionHeight()
+                                + "px");
+
+            }
+        }
+
+        public Widget getComponent() {
+            if (getWidgetCount() < 2) {
+                return null;
+            }
+            return getWidget(1);
+        }
+
+        @Override
+        public void setVisible(boolean visible) {
+            super.setVisible(visible);
+        }
+
+        public void setHeightFromWidget() {
+            Widget paintable = getPaintable();
+            if (paintable == null) {
+                return;
+            }
+
+            int paintableHeight = (paintable).getElement().getOffsetHeight();
+            setHeight(paintableHeight);
+
+        }
+
+        /**
+         * Returns caption width including padding
+         * 
+         * @return
+         */
+        public int getCaptionWidth() {
+            if (caption == null) {
+                return 0;
+            }
+
+            int captionWidth = caption.getRequiredWidth();
+            int padding = Util.measureHorizontalPaddingAndBorder(caption
+                    .getElement(), 18);
+            return captionWidth + padding;
+        }
+
+        public void setWidth(int width) {
+            if (width == -1) {
+                super.setWidth("");
+            } else {
+                super.setWidth(width + "px");
+            }
+        }
+
+        public int getHeight() {
+            return getOffsetHeight();
+        }
+
+        public int getCaptionHeight() {
+            return captionNode.getOffsetHeight();
+        }
+
+        private VCaption caption;
+        private boolean open = false;
+        private Element content = DOM.createDiv();
+        private Element captionNode = DOM.createDiv();
+
+        public StackItem(UIDL tabUidl) {
+            setElement(DOM.createDiv());
+            caption = new VCaption(null, client);
+            caption.addClickListener(this);
+            if (BrowserInfo.get().isIE6()) {
+                DOM.setEventListener(captionNode, this);
+                DOM.sinkEvents(captionNode, Event.BUTTON_LEFT);
+            }
+            super.add(caption, captionNode);
+            DOM.appendChild(captionNode, caption.getElement());
+            DOM.appendChild(getElement(), captionNode);
+            DOM.appendChild(getElement(), content);
+            setStylePrimaryName(CLASSNAME + "-item");
+            DOM.setElementProperty(content, "className", CLASSNAME
+                    + "-item-content");
+            DOM.setElementProperty(captionNode, "className", CLASSNAME
+                    + "-item-caption");
+            close();
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            onSelectTab(this);
+        }
+
+        public Element getContainerElement() {
+            return content;
+        }
+
+        public Widget getPaintable() {
+            if (getWidgetCount() > 1) {
+                return getWidget(1);
+            } else {
+                return null;
+            }
+        }
+
+        public void replacePaintable(Paintable newPntbl) {
+            if (getWidgetCount() > 1) {
+                client.unregisterPaintable((Paintable) getWidget(1));
+                paintables.remove(getWidget(1));
+                remove(1);
+            }
+            add((Widget) newPntbl, content);
+            paintables.add(newPntbl);
+        }
+
+        public void open() {
+            open = true;
+            DOM.setStyleAttribute(content, "top", getCaptionHeight() + "px");
+            DOM.setStyleAttribute(content, "left", "0px");
+            DOM.setStyleAttribute(content, "visibility", "");
+            addStyleDependentName("open");
+        }
+
+        public void hide() {
+            DOM.setStyleAttribute(content, "visibility", "hidden");
+        }
+
+        public void close() {
+            DOM.setStyleAttribute(content, "visibility", "hidden");
+            DOM.setStyleAttribute(content, "top", "-100000px");
+            DOM.setStyleAttribute(content, "left", "-100000px");
+            removeStyleDependentName("open");
+            setHeight(-1);
+            open = false;
+        }
+
+        public boolean isOpen() {
+            return open;
+        }
+
+        public void setContent(UIDL contentUidl) {
+            final Paintable newPntbl = client.getPaintable(contentUidl);
+            if (getPaintable() == null) {
+                add((Widget) newPntbl, content);
+                paintables.add(newPntbl);
+            } else if (getPaintable() != newPntbl) {
+                replacePaintable(newPntbl);
+            }
+            newPntbl.updateFromUIDL(contentUidl, client);
+            if (contentUidl.getBooleanAttribute("cached")) {
+                /*
+                 * The size of a cached, relative sized component must be
+                 * updated to report correct size.
+                 */
+                client.handleComponentRelativeSize((Widget) newPntbl);
+            }
+            if (isOpen() && isDynamicHeight()) {
+                setHeightFromWidget();
+            }
+        }
+
+        public void onClick(Widget sender) {
+            onSelectTab(this);
+        }
+
+        public void updateCaption(UIDL uidl) {
+            caption.updateCaption(uidl);
+        }
+
+        public int getWidgetWidth() {
+            return DOM.getFirstChild(content).getOffsetWidth();
+        }
+
+        public boolean contains(Paintable p) {
+            return (getPaintable() == p);
+        }
+
+        public boolean isCaptionVisible() {
+            return caption.isVisible();
+        }
+
+    }
+
+    @Override
+    protected void clearPaintables() {
+        clear();
+    }
+
+    public boolean isDynamicHeight() {
+        return height == null || height.equals("");
+    }
+
+    public boolean isDynamicWidth() {
+        return width == null || width.equals("");
+    }
+
+    @Override
+    protected Iterator getPaintableIterator() {
+        return paintables.iterator();
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (paintables.contains(component)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        for (Widget w : getChildren()) {
+            StackItem item = (StackItem) w;
+            if (item.getPaintable() == oldComponent) {
+                item.replacePaintable((Paintable) newComponent);
+                return;
+            }
+        }
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        /* Accordion does not render its children's captions */
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        if (!isDynamicHeight() && !isDynamicWidth()) {
+            /*
+             * If the height and width has been specified for this container the
+             * child components cannot make the size of the layout change
+             */
+
+            return true;
+        }
+
+        updateOpenTabSize();
+
+        if (renderInformation.updateSize(getElement())) {
+            /*
+             * Size has changed so we let the child components know about the
+             * new size.
+             */
+            iLayout();
+            // TODO Check if this is needed
+            client.runDescendentsLayout(this);
+
+            return false;
+        } else {
+            /*
+             * Size has not changed so we do not need to propagate the event
+             * further
+             */
+            return true;
+        }
+
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        return renderSpace;
+    }
+
+    @Override
+    protected int getTabCount() {
+        return getWidgetCount();
+    }
+
+    @Override
+    protected void removeTab(int index) {
+        StackItem item = getStackItem(index);
+        remove(item);
+    }
+
+    @Override
+    protected Paintable getTab(int index) {
+        if (index < getWidgetCount()) {
+            return (Paintable) (getStackItem(index)).getPaintable();
+        }
+
+        return null;
+    }
+
+    private StackItem getStackItem(int index) {
+        return (StackItem) getWidget(index);
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VButton.java b/src/com/vaadin/terminal/gwt/client/ui/VButton.java
new file mode 100644 (file)
index 0000000..789a0f3
--- /dev/null
@@ -0,0 +1,190 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+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.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VButton extends Button implements Paintable {
+
+    private String width = null;
+
+    public static final String CLASSNAME = "i-button";
+    
+    // Used only for IE, because it doesn't support :active CSS selector
+    private static final String CLASSNAME_DOWN = "i-pressed";
+
+    String id;
+
+    ApplicationConnection client;
+
+    private Element errorIndicatorElement;
+
+    private final Element captionElement = DOM.createSpan();
+
+    private Icon icon;
+
+    /**
+     * Helper flat to handle special-case where the button is moved from under
+     * mouse while clicking it. In this case mouse leaves the button without
+     * moving.
+     */
+    private boolean clickPending;
+
+    public VButton() {
+        setStyleName(CLASSNAME);
+
+        DOM.appendChild(getElement(), captionElement);
+
+        addClickListener(new ClickListener() {
+            public void onClick(Widget sender) {
+                if (id == null || client == null) {
+                    return;
+                }
+                /*
+                 * TODO isolate workaround. Safari don't always seem to fire
+                 * onblur previously focused component before button is clicked.
+                 */
+                VButton.this.setFocus(true);
+                client.updateVariable(id, "state", true, true);
+                clickPending = false;
+            }
+        });
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+        sinkEvents(Event.ONMOUSEDOWN);
+        sinkEvents(Event.ONMOUSEUP);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+        // Ensure correct implementation,
+        // but don't let container manage caption etc.
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        // Save details
+        this.client = client;
+        id = uidl.getId();
+
+        // Set text
+        setText(uidl.getStringAttribute("caption"));
+
+        // handle error
+        if (uidl.hasAttribute("error")) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = DOM.createDiv();
+                DOM.setElementProperty(errorIndicatorElement, "className",
+                        "i-errorindicator");
+            }
+            DOM.insertChild(getElement(), errorIndicatorElement, 0);
+
+            // Fix for IE6, IE7
+            if (BrowserInfo.get().isIE()) {
+                DOM.setInnerText(errorIndicatorElement, " ");
+            }
+
+        } else if (errorIndicatorElement != null) {
+            DOM.removeChild(getElement(), errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+
+        if (uidl.hasAttribute("readonly")) {
+            setEnabled(false);
+        }
+
+        if (uidl.hasAttribute("icon")) {
+            if (icon == null) {
+                icon = new Icon(client);
+                DOM.insertChild(getElement(), icon.getElement(), 0);
+            }
+            icon.setUri(uidl.getStringAttribute("icon"));
+        } else {
+            if (icon != null) {
+                DOM.removeChild(getElement(), icon.getElement());
+                icon = null;
+            }
+        }
+        if (BrowserInfo.get().isIE7()) {
+            if (width.equals("")) {
+                setWidth(getOffsetWidth() + "px");
+            }
+        }
+    }
+
+    @Override
+    public void setText(String text) {
+        DOM.setInnerText(captionElement, text);
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+
+        if (DOM.eventGetType(event) == Event.ONLOAD) {
+            Util.notifyParentOfSizeChange(this, true);
+
+        } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN
+                && event.getButton() == Event.BUTTON_LEFT) {
+            clickPending = true;
+            if (BrowserInfo.get().isIE()) {
+               // Only for IE, because it doesn't support :active CSS selector
+               // Simple check is cheaper than DOM manipulation
+                addStyleName(CLASSNAME_DOWN);
+            }
+        } else if (DOM.eventGetType(event) == Event.ONMOUSEMOVE) {
+            clickPending = false;
+        } else if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
+            if (clickPending) {
+                click();
+            }
+            if (BrowserInfo.get().isIE()) {
+                removeStyleName(CLASSNAME_DOWN);
+            }
+            clickPending = false;
+        } else if (DOM.eventGetType(event) == Event.ONMOUSEUP) {
+            if (BrowserInfo.get().isIE()) {
+                removeStyleName(CLASSNAME_DOWN);
+            }
+        }
+
+        if (client != null) {
+            client.handleTooltipEvent(event, this);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        /* Workaround for IE7 button size part 1 (#2014) */
+        if (BrowserInfo.get().isIE7() && this.width != null) {
+            if (this.width.equals(width)) {
+                return;
+            }
+
+            if (width == null) {
+                width = "";
+            }
+        }
+
+        this.width = width;
+        super.setWidth(width);
+
+        /* Workaround for IE7 button size part 2 (#2014) */
+        if (BrowserInfo.get().isIE7()) {
+            super.setWidth(width);
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VCalendarPanel.java
new file mode 100644 (file)
index 0000000..afb3349
--- /dev/null
@@ -0,0 +1,520 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Date;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.Event;\r
+import com.google.gwt.user.client.Timer;\r
+import com.google.gwt.user.client.ui.FlexTable;\r
+import com.google.gwt.user.client.ui.MouseListener;\r
+import com.google.gwt.user.client.ui.MouseListenerCollection;\r
+import com.google.gwt.user.client.ui.SourcesMouseEvents;\r
+import com.google.gwt.user.client.ui.SourcesTableEvents;\r
+import com.google.gwt.user.client.ui.TableListener;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.DateTimeService;\r
+import com.vaadin.terminal.gwt.client.LocaleService;\r
+\r
+public class VCalendarPanel extends FlexTable implements MouseListener {\r
+\r
+    private final VDateField datefield;\r
+\r
+    private VEventButton prevYear;\r
+\r
+    private VEventButton nextYear;\r
+\r
+    private VEventButton prevMonth;\r
+\r
+    private VEventButton nextMonth;\r
+\r
+    private VTime time;\r
+\r
+    private Date minDate = null;\r
+\r
+    private Date maxDate = null;\r
+\r
+    private CalendarEntrySource entrySource;\r
+\r
+    /* Needed to identify resolution changes */\r
+    private int resolution = VDateField.RESOLUTION_YEAR;\r
+\r
+    /* Needed to identify locale changes */\r
+    private String locale = LocaleService.getDefaultLocale();\r
+\r
+    public VCalendarPanel(VDateField parent) {\r
+        datefield = parent;\r
+        setStyleName(VDateField.CLASSNAME + "-calendarpanel");\r
+        // buildCalendar(true);\r
+        addTableListener(new DateClickListener(this));\r
+    }\r
+\r
+    public VCalendarPanel(VDateField parent, Date min, Date max) {\r
+        datefield = parent;\r
+        setStyleName(VDateField.CLASSNAME + "-calendarpanel");\r
+        // buildCalendar(true);\r
+        addTableListener(new DateClickListener(this));\r
+\r
+    }\r
+\r
+    private void buildCalendar(boolean forceRedraw) {\r
+        final boolean needsMonth = datefield.getCurrentResolution() > VDateField.RESOLUTION_YEAR;\r
+        boolean needsBody = datefield.getCurrentResolution() >= VDateField.RESOLUTION_DAY;\r
+        final boolean needsTime = datefield.getCurrentResolution() >= VDateField.RESOLUTION_HOUR;\r
+        forceRedraw = prevYear == null ? true : forceRedraw;\r
+        buildCalendarHeader(forceRedraw, needsMonth);\r
+        clearCalendarBody(!needsBody);\r
+        if (needsBody) {\r
+            buildCalendarBody();\r
+        }\r
+        if (needsTime) {\r
+            buildTime(forceRedraw);\r
+        } else if (time != null) {\r
+            remove(time);\r
+            time = null;\r
+        }\r
+    }\r
+\r
+    private void clearCalendarBody(boolean remove) {\r
+        if (!remove) {\r
+            for (int row = 2; row < 8; row++) {\r
+                for (int col = 0; col < 7; col++) {\r
+                    setHTML(row, col, "&nbsp;");\r
+                }\r
+            }\r
+        } else if (getRowCount() > 2) {\r
+            while (getRowCount() > 2) {\r
+                removeRow(2);\r
+            }\r
+        }\r
+    }\r
+\r
+    private void buildCalendarHeader(boolean forceRedraw, boolean needsMonth) {\r
+        if (forceRedraw) {\r
+            if (prevMonth == null) { // Only do once\r
+                prevYear = new VEventButton();\r
+                prevYear.setHTML("&laquo;");\r
+                prevYear.setStyleName("i-button-prevyear");\r
+                nextYear = new VEventButton();\r
+                nextYear.setHTML("&raquo;");\r
+                nextYear.setStyleName("i-button-nextyear");\r
+                prevYear.addMouseListener(this);\r
+                nextYear.addMouseListener(this);\r
+                setWidget(0, 0, prevYear);\r
+                setWidget(0, 4, nextYear);\r
+\r
+                if (needsMonth) {\r
+                    prevMonth = new VEventButton();\r
+                    prevMonth.setHTML("&lsaquo;");\r
+                    prevMonth.setStyleName("i-button-prevmonth");\r
+                    nextMonth = new VEventButton();\r
+                    nextMonth.setHTML("&rsaquo;");\r
+                    nextMonth.setStyleName("i-button-nextmonth");\r
+                    prevMonth.addMouseListener(this);\r
+                    nextMonth.addMouseListener(this);\r
+                    setWidget(0, 3, nextMonth);\r
+                    setWidget(0, 1, prevMonth);\r
+                }\r
+\r
+                getFlexCellFormatter().setColSpan(0, 2, 3);\r
+                getRowFormatter().addStyleName(0,\r
+                        VDateField.CLASSNAME + "-calendarpanel-header");\r
+            } else if (!needsMonth) {\r
+                // Remove month traverse buttons\r
+                prevMonth.removeMouseListener(this);\r
+                nextMonth.removeMouseListener(this);\r
+                remove(prevMonth);\r
+                remove(nextMonth);\r
+                prevMonth = null;\r
+                nextMonth = null;\r
+            }\r
+\r
+            // Print weekday names\r
+            final int firstDay = datefield.getDateTimeService()\r
+                    .getFirstDayOfWeek();\r
+            for (int i = 0; i < 7; i++) {\r
+                int day = i + firstDay;\r
+                if (day > 6) {\r
+                    day = 0;\r
+                }\r
+                if (datefield.getCurrentResolution() > VDateField.RESOLUTION_MONTH) {\r
+                    setHTML(1, i, "<strong>"\r
+                            + datefield.getDateTimeService().getShortDay(day)\r
+                            + "</strong>");\r
+                } else {\r
+                    setHTML(1, i, "");\r
+                }\r
+            }\r
+        }\r
+\r
+        final String monthName = needsMonth ? datefield.getDateTimeService()\r
+                .getMonth(datefield.getShowingDate().getMonth()) : "";\r
+        final int year = datefield.getShowingDate().getYear() + 1900;\r
+        setHTML(0, 2, "<span class=\"" + VDateField.CLASSNAME\r
+                + "-calendarpanel-month\">" + monthName + " " + year\r
+                + "</span>");\r
+    }\r
+\r
+    private void buildCalendarBody() {\r
+        // date actually selected?\r
+        Date currentDate = datefield.getCurrentDate();\r
+        Date showing = datefield.getShowingDate();\r
+        boolean selected = (currentDate != null\r
+                && currentDate.getMonth() == showing.getMonth() && currentDate\r
+                .getYear() == showing.getYear());\r
+\r
+        final int startWeekDay = datefield.getDateTimeService()\r
+                .getStartWeekDay(datefield.getShowingDate());\r
+        final int numDays = DateTimeService.getNumberOfDaysInMonth(datefield\r
+                .getShowingDate());\r
+        int dayCount = 0;\r
+        final Date today = new Date();\r
+        final Date curr = new Date(datefield.getShowingDate().getTime());\r
+        for (int row = 2; row < 8; row++) {\r
+            for (int col = 0; col < 7; col++) {\r
+                if (!(row == 2 && col < startWeekDay)) {\r
+                    if (dayCount < numDays) {\r
+                        final int selectedDate = ++dayCount;\r
+                        String title = "";\r
+                        if (entrySource != null) {\r
+                            curr.setDate(dayCount);\r
+                            final List entries = entrySource.getEntries(curr,\r
+                                    VDateField.RESOLUTION_DAY);\r
+                            if (entries != null) {\r
+                                for (final Iterator it = entries.iterator(); it\r
+                                        .hasNext();) {\r
+                                    final CalendarEntry entry = (CalendarEntry) it\r
+                                            .next();\r
+                                    title += (title.length() > 0 ? ", " : "")\r
+                                            + entry.getStringForDate(curr);\r
+                                }\r
+                            }\r
+                        }\r
+                        final String baseclass = VDateField.CLASSNAME\r
+                                + "-calendarpanel-day";\r
+                        String cssClass = baseclass;\r
+                        if (!isEnabledDate(curr)) {\r
+                            cssClass += " " + baseclass + "-disabled";\r
+                        }\r
+                        if (selected\r
+                                && datefield.getShowingDate().getDate() == dayCount) {\r
+                            cssClass += " " + baseclass + "-selected";\r
+                        }\r
+                        if (today.getDate() == dayCount\r
+                                && today.getMonth() == datefield\r
+                                        .getShowingDate().getMonth()\r
+                                && today.getYear() == datefield\r
+                                        .getShowingDate().getYear()) {\r
+                            cssClass += " " + baseclass + "-today";\r
+                        }\r
+                        if (title.length() > 0) {\r
+                            cssClass += " " + baseclass + "-entry";\r
+                        }\r
+                        setHTML(row, col, "<span title=\"" + title\r
+                                + "\" class=\"" + cssClass + "\">"\r
+                                + selectedDate + "</span>");\r
+                    } else {\r
+                        break;\r
+                    }\r
+\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    private void buildTime(boolean forceRedraw) {\r
+        if (time == null) {\r
+            time = new VTime(datefield);\r
+            setText(8, 0, ""); // Add new row\r
+            getFlexCellFormatter().setColSpan(8, 0, 7);\r
+            setWidget(8, 0, time);\r
+        }\r
+        time.updateTime(forceRedraw);\r
+    }\r
+\r
+    /**\r
+     * \r
+     * @param forceRedraw\r
+     *            Build all from scratch, in case of e.g. locale changes\r
+     */\r
+    public void updateCalendar() {\r
+        // Locale and resolution changes force a complete redraw\r
+        buildCalendar(locale != datefield.getCurrentLocale()\r
+                || resolution != datefield.getCurrentResolution());\r
+        if (datefield instanceof VTextualDate) {\r
+            ((VTextualDate) datefield).buildDate();\r
+        }\r
+        locale = datefield.getCurrentLocale();\r
+        resolution = datefield.getCurrentResolution();\r
+    }\r
+\r
+    private boolean isEnabledDate(Date date) {\r
+        if ((minDate != null && date.before(minDate))\r
+                || (maxDate != null && date.after(maxDate))) {\r
+            return false;\r
+        }\r
+        return true;\r
+    }\r
+\r
+    private void processClickEvent(Widget sender, boolean updateVariable) {\r
+        if (!datefield.isEnabled() || datefield.isReadonly()) {\r
+            return;\r
+        }\r
+        Date showingDate = datefield.getShowingDate();\r
+        if (!updateVariable) {\r
+            if (sender == prevYear) {\r
+                showingDate.setYear(showingDate.getYear() - 1);\r
+                updateCalendar();\r
+            } else if (sender == nextYear) {\r
+                showingDate.setYear(showingDate.getYear() + 1);\r
+                updateCalendar();\r
+            } else if (sender == prevMonth) {\r
+                int currentMonth = showingDate.getMonth();\r
+                showingDate.setMonth(currentMonth - 1);\r
+\r
+                /*\r
+                 * If the selected date was e.g. 31.12 the new date would be\r
+                 * 31.11 but this date is invalid so the new date will be 1.12.\r
+                 * This is taken care of by decreasing the date until we have\r
+                 * the correct month.\r
+                 */\r
+                while (showingDate.getMonth() == currentMonth) {\r
+                    showingDate.setDate(showingDate.getDate() - 1);\r
+                }\r
+\r
+                updateCalendar();\r
+            } else if (sender == nextMonth) {\r
+                int currentMonth = showingDate.getMonth();\r
+                showingDate.setMonth(currentMonth + 1);\r
+                int requestedMonth = (currentMonth + 1) % 12;\r
+\r
+                /*\r
+                 * If the selected date was e.g. 31.3 the new date would be 31.4\r
+                 * but this date is invalid so the new date will be 1.5. This is\r
+                 * taken care of by decreasing the date until we have the\r
+                 * correct month.\r
+                 */\r
+                while (showingDate.getMonth() != requestedMonth) {\r
+                    showingDate.setDate(showingDate.getDate() - 1);\r
+                }\r
+\r
+                updateCalendar();\r
+            }\r
+        } else {\r
+            if (datefield.getCurrentResolution() == VDateField.RESOLUTION_YEAR\r
+                    || datefield.getCurrentResolution() == VDateField.RESOLUTION_MONTH) {\r
+                // Due to current UI, update variable if res=year/month\r
+                datefield.setCurrentDate(new Date(showingDate.getTime()));\r
+                if (datefield.getCurrentResolution() == VDateField.RESOLUTION_MONTH) {\r
+                    datefield.getClient().updateVariable(datefield.getId(),\r
+                            "month", datefield.getCurrentDate().getMonth() + 1,\r
+                            false);\r
+                }\r
+                datefield.getClient().updateVariable(datefield.getId(), "year",\r
+                        datefield.getCurrentDate().getYear() + 1900,\r
+                        datefield.isImmediate());\r
+\r
+                /* Must update the value in the textfield also */\r
+                updateCalendar();\r
+            }\r
+        }\r
+    }\r
+\r
+    private Timer timer;\r
+\r
+    public void onMouseDown(final Widget sender, int x, int y) {\r
+        // Allow user to click-n-hold for fast-forward or fast-rewind.\r
+        // Timer is first used for a 500ms delay after mousedown. After that has\r
+        // elapsed, another timer is triggered to go off every 150ms. Both\r
+        // timers are cancelled on mouseup or mouseout.\r
+        if (sender instanceof VEventButton) {\r
+            processClickEvent(sender, false);\r
+            timer = new Timer() {\r
+                @Override\r
+                public void run() {\r
+                    timer = new Timer() {\r
+                        @Override\r
+                        public void run() {\r
+                            processClickEvent(sender, false);\r
+                        }\r
+                    };\r
+                    timer.scheduleRepeating(150);\r
+                }\r
+            };\r
+            timer.schedule(500);\r
+        }\r
+    }\r
+\r
+    public void onMouseEnter(Widget sender) {\r
+    }\r
+\r
+    public void onMouseLeave(Widget sender) {\r
+        if (timer != null) {\r
+            timer.cancel();\r
+        }\r
+    }\r
+\r
+    public void onMouseMove(Widget sender, int x, int y) {\r
+    }\r
+\r
+    public void onMouseUp(Widget sender, int x, int y) {\r
+        if (timer != null) {\r
+            timer.cancel();\r
+        }\r
+        processClickEvent(sender, true);\r
+    }\r
+\r
+    private class VEventButton extends VButton implements SourcesMouseEvents {\r
+\r
+        private MouseListenerCollection mouseListeners;\r
+\r
+        public VEventButton() {\r
+            super();\r
+            sinkEvents(Event.FOCUSEVENTS | Event.KEYEVENTS | Event.ONCLICK\r
+                    | Event.MOUSEEVENTS);\r
+        }\r
+\r
+        public void addMouseListener(MouseListener listener) {\r
+            if (mouseListeners == null) {\r
+                mouseListeners = new MouseListenerCollection();\r
+            }\r
+            mouseListeners.add(listener);\r
+        }\r
+\r
+        public void removeMouseListener(MouseListener listener) {\r
+            if (mouseListeners != null) {\r
+                mouseListeners.remove(listener);\r
+            }\r
+        }\r
+\r
+        @Override\r
+        public void onBrowserEvent(Event event) {\r
+            super.onBrowserEvent(event);\r
+            switch (DOM.eventGetType(event)) {\r
+            case Event.ONMOUSEDOWN:\r
+            case Event.ONMOUSEUP:\r
+            case Event.ONMOUSEMOVE:\r
+            case Event.ONMOUSEOVER:\r
+            case Event.ONMOUSEOUT:\r
+                if (mouseListeners != null) {\r
+                    mouseListeners.fireMouseEvent(this, event);\r
+                }\r
+                break;\r
+            }\r
+        }\r
+    }\r
+\r
+    private class DateClickListener implements TableListener {\r
+\r
+        private final VCalendarPanel cal;\r
+\r
+        public DateClickListener(VCalendarPanel panel) {\r
+            cal = panel;\r
+        }\r
+\r
+        public void onCellClicked(SourcesTableEvents sender, int row, int col) {\r
+            if (sender != cal || row < 2 || row > 7\r
+                    || !cal.datefield.isEnabled() || cal.datefield.isReadonly()) {\r
+                return;\r
+            }\r
+\r
+            final String text = cal.getText(row, col);\r
+            if (text.equals(" ")) {\r
+                return;\r
+            }\r
+\r
+            try {\r
+                final Integer day = new Integer(text);\r
+                final Date newDate = cal.datefield.getShowingDate();\r
+                newDate.setDate(day.intValue());\r
+                if (!isEnabledDate(newDate)) {\r
+                    return;\r
+                }\r
+                if (cal.datefield.getCurrentDate() == null) {\r
+                    cal.datefield.setCurrentDate(new Date(newDate.getTime()));\r
+\r
+                    // Init variables with current time\r
+                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                            "hour", newDate.getHours(), false);\r
+                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                            "min", newDate.getMinutes(), false);\r
+                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                            "sec", newDate.getSeconds(), false);\r
+                    datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                            "msec", datefield.getMilliseconds(), false);\r
+                }\r
+\r
+                cal.datefield.getCurrentDate().setTime(newDate.getTime());\r
+                cal.datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                        "day", cal.datefield.getCurrentDate().getDate(), false);\r
+                cal.datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                        "month", cal.datefield.getCurrentDate().getMonth() + 1,\r
+                        false);\r
+                cal.datefield.getClient().updateVariable(cal.datefield.getId(),\r
+                        "year",\r
+                        cal.datefield.getCurrentDate().getYear() + 1900,\r
+                        cal.datefield.isImmediate());\r
+\r
+                if (datefield instanceof VTextualDate\r
+                        && resolution < VDateField.RESOLUTION_HOUR) {\r
+                    ((VToolkitOverlay) getParent()).hide();\r
+                } else {\r
+                    updateCalendar();\r
+                }\r
+\r
+            } catch (final NumberFormatException e) {\r
+                // Not a number, ignore and stop here\r
+                return;\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    public void setLimits(Date min, Date max) {\r
+        if (min != null) {\r
+            final Date d = new Date(min.getTime());\r
+            d.setHours(0);\r
+            d.setMinutes(0);\r
+            d.setSeconds(1);\r
+            minDate = d;\r
+        } else {\r
+            minDate = null;\r
+        }\r
+        if (max != null) {\r
+            final Date d = new Date(max.getTime());\r
+            d.setHours(24);\r
+            d.setMinutes(59);\r
+            d.setSeconds(59);\r
+            maxDate = d;\r
+        } else {\r
+            maxDate = null;\r
+        }\r
+    }\r
+\r
+    public void setCalendarEntrySource(CalendarEntrySource entrySource) {\r
+        this.entrySource = entrySource;\r
+    }\r
+\r
+    public CalendarEntrySource getCalendarEntrySource() {\r
+        return entrySource;\r
+    }\r
+\r
+    public interface CalendarEntrySource {\r
+        public List getEntries(Date date, int resolution);\r
+    }\r
+\r
+    /**\r
+     * Sets focus to Calendar panel.\r
+     * \r
+     * @param focus\r
+     */\r
+    public void setFocus(boolean focus) {\r
+        nextYear.setFocus(focus);\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java b/src/com/vaadin/terminal/gwt/client/ui/VCheckBox.java
new file mode 100644 (file)
index 0000000..2c6470f
--- /dev/null
@@ -0,0 +1,140 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VCheckBox extends com.google.gwt.user.client.ui.CheckBox implements
+        Paintable, Field {
+
+    public static final String CLASSNAME = "i-checkbox";
+
+    String id;
+
+    boolean immediate;
+
+    ApplicationConnection client;
+
+    private Element errorIndicatorElement;
+
+    private Icon icon;
+
+    private boolean isBlockMode = false;
+
+    public VCheckBox() {
+        setStyleName(CLASSNAME);
+        addClickListener(new ClickListener() {
+
+            public void onClick(Widget sender) {
+                if (id == null || client == null) {
+                    return;
+                }
+                client.updateVariable(id, "state", isChecked(), immediate);
+            }
+
+        });
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+        Element el = DOM.getFirstChild(getElement());
+        while (el != null) {
+            DOM.sinkEvents(el,
+                    (DOM.getEventsSunk(el) | VTooltip.TOOLTIP_EVENTS));
+            el = DOM.getNextSibling(el);
+        }
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // Save details
+        this.client = client;
+        id = uidl.getId();
+
+        // Ensure correct implementation
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        if (uidl.hasAttribute("error")) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = DOM.createDiv();
+                errorIndicatorElement.setInnerHTML("&nbsp;");
+                DOM.setElementProperty(errorIndicatorElement, "className",
+                        "i-errorindicator");
+                DOM.appendChild(getElement(), errorIndicatorElement);
+                DOM.sinkEvents(errorIndicatorElement, VTooltip.TOOLTIP_EVENTS
+                        | Event.ONCLICK);
+            }
+        } else if (errorIndicatorElement != null) {
+            DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
+        }
+
+        if (uidl.hasAttribute("readonly")) {
+            setEnabled(false);
+        }
+
+        if (uidl.hasAttribute("icon")) {
+            if (icon == null) {
+                icon = new Icon(client);
+                DOM.insertChild(getElement(), icon.getElement(), 1);
+                icon.sinkEvents(VTooltip.TOOLTIP_EVENTS);
+                icon.sinkEvents(Event.ONCLICK);
+            }
+            icon.setUri(uidl.getStringAttribute("icon"));
+        } else if (icon != null) {
+            // detach icon
+            DOM.removeChild(getElement(), icon.getElement());
+            icon = null;
+        }
+
+        // Set text
+        setText(uidl.getStringAttribute("caption"));
+        setChecked(uidl.getBooleanVariable("state"));
+        immediate = uidl.getBooleanAttribute("immediate");
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        if (icon != null && (event.getTypeInt() == Event.ONCLICK)
+                && (event.getTarget() == icon.getElement())) {
+            setChecked(!isChecked());
+        }
+        super.onBrowserEvent(event);
+        if (event.getTypeInt() == Event.ONLOAD) {
+            Util.notifyParentOfSizeChange(this, true);
+        }
+        if (client != null) {
+            client.handleTooltipEvent(event, this);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        setBlockMode();
+        super.setWidth(width);
+    }
+
+    @Override
+    public void setHeight(String height) {
+        setBlockMode();
+        super.setHeight(height);
+    }
+
+    /**
+     * makes container element (span) to be block element to enable sizing.
+     */
+    private void setBlockMode() {
+        if (!isBlockMode) {
+            DOM.setStyleAttribute(getElement(), "display", "block");
+            isBlockMode = true;
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java b/src/com/vaadin/terminal/gwt/client/ui/VContextMenu.java
new file mode 100644 (file)
index 0000000..f0d1e87
--- /dev/null
@@ -0,0 +1,157 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.dom.client.TableSectionElement;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.MenuBar;
+import com.google.gwt.user.client.ui.MenuItem;
+import com.google.gwt.user.client.ui.PopupPanel;
+
+public class VContextMenu extends VToolkitOverlay implements SubPartAware {
+
+    private ActionOwner actionOwner;
+
+    private final CMenuBar menu = new CMenuBar();
+
+    private int left;
+
+    private int top;
+
+    /**
+     * This method should be used only by Client object as only one per client
+     * should exists. Request an instance via client.getContextMenu();
+     * 
+     * @param cli
+     *            to be set as an owner of menu
+     */
+    public VContextMenu() {
+        super(true, false, true);
+        setWidget(menu);
+        setStyleName("i-contextmenu");
+    }
+
+    /**
+     * Sets the element from which to build menu
+     * 
+     * @param ao
+     */
+    public void setActionOwner(ActionOwner ao) {
+        actionOwner = ao;
+    }
+
+    /**
+     * Shows context menu at given location.
+     * 
+     * @param left
+     * @param top
+     */
+    public void showAt(int left, int top) {
+        this.left = left;
+        this.top = top;
+        menu.clearItems();
+        final Action[] actions = actionOwner.getActions();
+        for (int i = 0; i < actions.length; i++) {
+            final Action a = actions[i];
+            menu.addItem(new MenuItem(a.getHTML(), true, a));
+        }
+
+        setPopupPositionAndShow(new PositionCallback() {
+            public void setPosition(int offsetWidth, int offsetHeight) {
+                // mac FF gets bad width due GWT popups overflow hacks,
+                // re-determine width
+                offsetWidth = menu.getOffsetWidth();
+                int left = VContextMenu.this.left;
+                int top = VContextMenu.this.top;
+                if (offsetWidth + left > Window.getClientWidth()) {
+                    left = left - offsetWidth;
+                    if (left < 0) {
+                        left = 0;
+                    }
+                }
+                if (offsetHeight + top > Window.getClientHeight()) {
+                    top = top - offsetHeight;
+                    if (top < 0) {
+                        top = 0;
+                    }
+                }
+                setPopupPosition(left, top);
+            }
+        });
+    }
+
+    public void showAt(ActionOwner ao, int left, int top) {
+        setActionOwner(ao);
+        showAt(left, top);
+    }
+
+    /**
+     * Extend standard Gwt MenuBar to set proper settings and to override
+     * onPopupClosed method so that PopupPanel gets closed.
+     */
+    class CMenuBar extends MenuBar {
+        public CMenuBar() {
+            super(true);
+        }
+
+        @Override
+        public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+            super.onPopupClosed(sender, autoClosed);
+            hide();
+        }
+
+        /*
+         * public void onBrowserEvent(Event event) { // Remove current selection
+         * when mouse leaves if (DOM.eventGetType(event) == Event.ONMOUSEOUT) {
+         * Element to = DOM.eventGetToElement(event); if
+         * (!DOM.isOrHasChild(getElement(), to)) { DOM.setElementProperty(
+         * super.getSelectedItem().getElement(), "className",
+         * super.getSelectedItem().getStylePrimaryName()); } }
+         * 
+         * super.onBrowserEvent(event); }
+         */
+    }
+
+    public Element getSubPartElement(String subPart) {
+        int index = Integer.parseInt(subPart.substring(6));
+        // ApplicationConnection.getConsole().log(
+        // "Searching element for selection index " + index);
+        Element wrapperdiv = menu.getElement();
+        com.google.gwt.dom.client.TableSectionElement tBody = (TableSectionElement) wrapperdiv
+                .getFirstChildElement().getFirstChildElement();
+        TableRowElement item = tBody.getRows().getItem(index);
+        com.google.gwt.dom.client.Element clickableDivElement = item
+                .getFirstChildElement().getFirstChildElement();
+        return clickableDivElement.cast();
+    }
+
+    public String getSubPartName(Element subElement) {
+        if (getElement().isOrHasChild(subElement)) {
+            com.google.gwt.dom.client.Element e = subElement;
+            {
+                while (e != null && !e.getTagName().toLowerCase().equals("tr")) {
+                    e = e.getParentElement();
+                    // ApplicationConnection.getConsole().log("Found row");
+                }
+            }
+            com.google.gwt.dom.client.TableSectionElement parentElement = (TableSectionElement) e
+                    .getParentElement();
+            NodeList<TableRowElement> rows = parentElement.getRows();
+            for (int i = 0; i < rows.getLength(); i++) {
+                if (rows.getItem(i) == e) {
+                    // ApplicationConnection.getConsole().log(
+                    // "Found index for row" + 1);
+                    return "option" + i;
+                }
+            }
+            return null;
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomComponent.java
new file mode 100644 (file)
index 0000000..117c67e
--- /dev/null
@@ -0,0 +1,153 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Set;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VCustomComponent extends SimplePanel implements Container {
+
+    private static final String CLASSNAME = "i-customcomponent";
+    private String height;
+    private ApplicationConnection client;
+    private boolean rendering;
+    private String width;
+    private RenderSpace renderSpace = new RenderSpace();
+
+    public VCustomComponent() {
+        super();
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateFromUIDL(UIDL uidl, final ApplicationConnection client) {
+        rendering = true;
+        if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
+            return;
+        }
+        this.client = client;
+
+        final UIDL child = uidl.getChildUIDL(0);
+        if (child != null) {
+            final Paintable p = client.getPaintable(child);
+            if (p != getWidget()) {
+                if (getWidget() != null) {
+                    client.unregisterPaintable((Paintable) getWidget());
+                    clear();
+                }
+                setWidget((Widget) p);
+            }
+            p.updateFromUIDL(child, client);
+        }
+
+        boolean updateDynamicSize = updateDynamicSize();
+        if (updateDynamicSize) {
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    // FIXME deferred relative size update needed to fix some
+                    // scrollbar issues in sampler. This must be the wrong way
+                    // to do it. Might be that some other component is broken.
+                    client.handleComponentRelativeSize(VCustomComponent.this);
+
+                }
+            });
+        }
+
+        renderSpace.setWidth(getElement().getOffsetWidth());
+        renderSpace.setHeight(getElement().getOffsetHeight());
+
+        rendering = false;
+    }
+
+    private boolean updateDynamicSize() {
+        boolean updated = false;
+        if (isDynamicWidth()) {
+            int childWidth = Util.getRequiredWidth(getWidget());
+            getElement().getStyle().setPropertyPx("width", childWidth);
+            updated = true;
+        }
+        if (isDynamicHeight()) {
+            int childHeight = Util.getRequiredHeight(getWidget());
+            getElement().getStyle().setPropertyPx("height", childHeight);
+            updated = true;
+        }
+
+        return updated;
+    }
+
+    private boolean isDynamicWidth() {
+        return width == null || width.equals("");
+    }
+
+    private boolean isDynamicHeight() {
+        return height == null || height.equals("");
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (getWidget() == component) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        if (hasChildComponent(oldComponent)) {
+            clear();
+            setWidget(newComponent);
+        } else {
+            throw new IllegalStateException();
+        }
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        // NOP, custom component dont render composition roots caption
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        return !updateDynamicSize();
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        return renderSpace;
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        renderSpace.setHeight(getElement().getOffsetHeight());
+
+        if (!height.equals(this.height)) {
+            this.height = height;
+            if (!rendering) {
+                client.runDescendentsLayout(this);
+            }
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        super.setWidth(width);
+        renderSpace.setWidth(getElement().getOffsetWidth());
+
+        if (!width.equals(this.width)) {
+            this.width = width;
+            if (!rendering) {
+                client.runDescendentsLayout(this);
+            }
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VCustomLayout.java
new file mode 100644 (file)
index 0000000..5078acc
--- /dev/null
@@ -0,0 +1,644 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.dom.client.ImageElement;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.VCaptionWrapper;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;
+
+/**
+ * Custom Layout implements complex layout defined with HTML template.
+ * 
+ * @author IT Mill
+ * 
+ */
+public class VCustomLayout extends ComplexPanel implements Paintable,
+        Container, ContainerResizedListener {
+
+    public static final String CLASSNAME = "i-customlayout";
+
+    /** Location-name to containing element in DOM map */
+    private final HashMap locationToElement = new HashMap();
+
+    /** Location-name to contained widget map */
+    private final HashMap<String, Widget> locationToWidget = new HashMap<String, Widget>();
+
+    /** Widget to captionwrapper map */
+    private final HashMap widgetToCaptionWrapper = new HashMap();
+
+    /** Name of the currently rendered style */
+    String currentTemplateName;
+
+    /** Unexecuted scripts loaded from the template */
+    private String scripts = "";
+
+    /** Paintable ID of this paintable */
+    private String pid;
+
+    private ApplicationConnection client;
+
+    /** Has the template been loaded from contents passed in UIDL **/
+    private boolean hasTemplateContents = false;
+
+    private Element elementWithNativeResizeFunction;
+
+    private String height = "";
+
+    private String width = "";
+
+    private HashMap<String, FloatSize> locationToExtraSize = new HashMap<String, FloatSize>();
+
+    public VCustomLayout() {
+        setElement(DOM.createDiv());
+        // Clear any unwanted styling
+        DOM.setStyleAttribute(getElement(), "border", "none");
+        DOM.setStyleAttribute(getElement(), "margin", "0");
+        DOM.setStyleAttribute(getElement(), "padding", "0");
+
+        if (BrowserInfo.get().isIE()) {
+            DOM.setStyleAttribute(getElement(), "position", "relative");
+        }
+
+        setStyleName(CLASSNAME);
+    }
+
+    /**
+     * Sets widget to given location.
+     * 
+     * If location already contains a widget it will be removed.
+     * 
+     * @param widget
+     *            Widget to be set into location.
+     * @param location
+     *            location name where widget will be added
+     * 
+     * @throws IllegalArgumentException
+     *             if no such location is found in the layout.
+     */
+    public void setWidget(Widget widget, String location) {
+
+        if (widget == null) {
+            return;
+        }
+
+        // If no given location is found in the layout, and exception is throws
+        Element elem = (Element) locationToElement.get(location);
+        if (elem == null && hasTemplate()) {
+            throw new IllegalArgumentException("No location " + location
+                    + " found");
+        }
+
+        // Get previous widget
+        final Widget previous = locationToWidget.get(location);
+        // NOP if given widget already exists in this location
+        if (previous == widget) {
+            return;
+        }
+
+        if (previous != null) {
+            remove(previous);
+        }
+
+        // if template is missing add element in order
+        if (!hasTemplate()) {
+            elem = getElement();
+        }
+
+        // Add widget to location
+        super.add(widget, elem);
+        locationToWidget.put(location, widget);
+    }
+
+    /** Update the layout from UIDL */
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        this.client = client;
+        // ApplicationConnection manages generic component features
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        pid = uidl.getId();
+        if (!hasTemplate()) {
+            // Update HTML template only once
+            initializeHTML(uidl, client);
+        }
+
+        // Evaluate scripts
+        eval(scripts);
+        scripts = null;
+
+        iLayout();
+        // TODO Check if this is needed
+        client.runDescendentsLayout(this);
+
+        Set oldWidgets = new HashSet();
+        oldWidgets.addAll(locationToWidget.values());
+
+        // For all contained widgets
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            final UIDL uidlForChild = (UIDL) i.next();
+            if (uidlForChild.getTag().equals("location")) {
+                final String location = uidlForChild.getStringAttribute("name");
+                final Paintable child = client.getPaintable(uidlForChild
+                        .getChildUIDL(0));
+                try {
+                    setWidget((Widget) child, location);
+                    child.updateFromUIDL(uidlForChild.getChildUIDL(0), client);
+                } catch (final IllegalArgumentException e) {
+                    // If no location is found, this component is not visible
+                }
+                oldWidgets.remove(child);
+            }
+        }
+        for (Iterator iterator = oldWidgets.iterator(); iterator.hasNext();) {
+            Widget oldWidget = (Widget) iterator.next();
+            if (oldWidget.isAttached()) {
+                // slot of this widget is emptied, remove it
+                remove(oldWidget);
+            }
+        }
+
+        iLayout();
+        // TODO Check if this is needed
+        client.runDescendentsLayout(this);
+
+    }
+
+    /** Initialize HTML-layout. */
+    private void initializeHTML(UIDL uidl, ApplicationConnection client) {
+
+        final String newTemplateContents = uidl
+                .getStringAttribute("templateContents");
+        final String newTemplate = uidl.getStringAttribute("template");
+
+        currentTemplateName = null;
+        hasTemplateContents = false;
+
+        String template = "";
+        if (newTemplate != null) {
+            // Get the HTML-template from client
+            template = client.getResource("layouts/" + newTemplate + ".html");
+            if (template == null) {
+                template = "<em>Layout file layouts/"
+                        + newTemplate
+                        + ".html is missing. Components will be drawn for debug purposes.</em>";
+            } else {
+                currentTemplateName = newTemplate;
+            }
+        } else {
+            hasTemplateContents = true;
+            template = newTemplateContents;
+        }
+
+        // Connect body of the template to DOM
+        template = extractBodyAndScriptsFromTemplate(template);
+
+        // TODO prefix img src:s here with a regeps, cannot work further with IE
+
+        String themeUri = client.getThemeUri();
+        String relImgPrefix = themeUri + "/layouts/";
+
+        // prefix all relative image elements to point to theme dir with a
+        // regexp search
+        template = template.replaceAll(
+                "<((?:img)|(?:IMG))\\s([^>]*)src=\"((?![a-z]+:)[^/][^\"]+)\"",
+                "<$1 $2src=\"" + relImgPrefix + "$3\"");
+        // also support src attributes without quotes
+        template = template
+                .replaceAll(
+                        "<((?:img)|(?:IMG))\\s([^>]*)src=[^\"]((?![a-z]+:)[^/][^ />]+)[ />]",
+                        "<$1 $2src=\"" + relImgPrefix + "$3\"");
+        // also prefix relative style="...url(...)..."
+        template = template
+                .replaceAll(
+                        "(<[^>]+style=\"[^\"]*url\\()((?![a-z]+:)[^/][^\"]+)(\\)[^>]*>)",
+                        "$1 " + relImgPrefix + "$2 $3");
+
+        getElement().setInnerHTML(template);
+
+        // Remap locations to elements
+        locationToElement.clear();
+        scanForLocations(getElement());
+
+        initImgElements();
+
+        elementWithNativeResizeFunction = DOM.getFirstChild(getElement());
+        if (elementWithNativeResizeFunction == null) {
+            elementWithNativeResizeFunction = getElement();
+        }
+        publishResizedFunction(elementWithNativeResizeFunction);
+
+    }
+
+    private native boolean uriEndsWithSlash()
+    /*-{
+        var path =  $wnd.location.pathname;
+        if(path.charAt(path.length - 1) == "/")
+            return true;
+        return false;
+    }-*/;
+
+    private boolean hasTemplate() {
+        if (currentTemplateName == null && !hasTemplateContents) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /** Collect locations from template */
+    private void scanForLocations(Element elem) {
+
+        final String location = elem.getAttribute("location");
+        if (!"".equals(location)) {
+            locationToElement.put(location, elem);
+            elem.setInnerHTML("");
+            int x = Util.measureHorizontalPaddingAndBorder(elem, 0);
+            int y = Util.measureVerticalPaddingAndBorder(elem, 0);
+
+            FloatSize fs = new FloatSize(x, y);
+
+            locationToExtraSize.put(location, fs);
+
+        } else {
+            final int len = DOM.getChildCount(elem);
+            for (int i = 0; i < len; i++) {
+                scanForLocations(DOM.getChild(elem, i));
+            }
+        }
+    }
+
+    /** Evaluate given script in browser document */
+    private static native void eval(String script)
+    /*-{
+      try {
+        if (script != null) 
+      eval("{ var document = $doc; var window = $wnd; "+ script + "}");
+      } catch (e) {
+      }
+    }-*/;
+
+    /**
+     * Img elements needs some special handling in custom layout. Img elements
+     * will get their onload events sunk. This way custom layout can notify
+     * parent about possible size change.
+     */
+    private void initImgElements() {
+        NodeList<com.google.gwt.dom.client.Element> nodeList = getElement()
+                .getElementsByTagName("IMG");
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            com.google.gwt.dom.client.ImageElement img = (ImageElement) nodeList
+                    .getItem(i);
+            DOM.sinkEvents((Element) img.cast(), Event.ONLOAD);
+        }
+    }
+
+    /**
+     * Extract body part and script tags from raw html-template.
+     * 
+     * Saves contents of all script-tags to private property: scripts. Returns
+     * contents of the body part for the html without script-tags. Also replaces
+     * all _UID_ tags with an unique id-string.
+     * 
+     * @param html
+     *            Original HTML-template received from server
+     * @return html that is used to create the HTMLPanel.
+     */
+    private String extractBodyAndScriptsFromTemplate(String html) {
+
+        // Replace UID:s
+        html = html.replaceAll("_UID_", pid + "__");
+
+        // Exctract script-tags
+        scripts = "";
+        int endOfPrevScript = 0;
+        int nextPosToCheck = 0;
+        String lc = html.toLowerCase();
+        String res = "";
+        int scriptStart = lc.indexOf("<script", nextPosToCheck);
+        while (scriptStart > 0) {
+            res += html.substring(endOfPrevScript, scriptStart);
+            scriptStart = lc.indexOf(">", scriptStart);
+            final int j = lc.indexOf("</script>", scriptStart);
+            scripts += html.substring(scriptStart + 1, j) + ";";
+            nextPosToCheck = endOfPrevScript = j + "</script>".length();
+            scriptStart = lc.indexOf("<script", nextPosToCheck);
+        }
+        res += html.substring(endOfPrevScript);
+
+        // Extract body
+        html = res;
+        lc = html.toLowerCase();
+        int startOfBody = lc.indexOf("<body");
+        if (startOfBody < 0) {
+            res = html;
+        } else {
+            res = "";
+            startOfBody = lc.indexOf(">", startOfBody) + 1;
+            final int endOfBody = lc.indexOf("</body>", startOfBody);
+            if (endOfBody > startOfBody) {
+                res = html.substring(startOfBody, endOfBody);
+            } else {
+                res = html.substring(startOfBody);
+            }
+        }
+
+        return res;
+    }
+
+    /** Replace child components */
+    public void replaceChildComponent(Widget from, Widget to) {
+        final String location = getLocation(from);
+        if (location == null) {
+            throw new IllegalArgumentException();
+        }
+        setWidget(to, location);
+    }
+
+    /** Does this layout contain given child */
+    public boolean hasChildComponent(Widget component) {
+        return locationToWidget.containsValue(component);
+    }
+
+    /** Update caption for given widget */
+    public void updateCaption(Paintable component, UIDL uidl) {
+        VCaptionWrapper wrapper = (VCaptionWrapper) widgetToCaptionWrapper
+                .get(component);
+        if (VCaption.isNeeded(uidl)) {
+            if (wrapper == null) {
+                final String loc = getLocation((Widget) component);
+                super.remove((Widget) component);
+                wrapper = new VCaptionWrapper(component, client);
+                super.add(wrapper, (Element) locationToElement.get(loc));
+                widgetToCaptionWrapper.put(component, wrapper);
+            }
+            wrapper.updateCaption(uidl);
+        } else {
+            if (wrapper != null) {
+                final String loc = getLocation((Widget) component);
+                super.remove(wrapper);
+                super.add((Widget) wrapper.getPaintable(),
+                        (Element) locationToElement.get(loc));
+                widgetToCaptionWrapper.remove(component);
+            }
+        }
+    }
+
+    /** Get the location of an widget */
+    public String getLocation(Widget w) {
+        for (final Iterator i = locationToWidget.keySet().iterator(); i
+                .hasNext();) {
+            final String location = (String) i.next();
+            if (locationToWidget.get(location) == w) {
+                return location;
+            }
+        }
+        return null;
+    }
+
+    /** Removes given widget from the layout */
+    @Override
+    public boolean remove(Widget w) {
+        client.unregisterPaintable((Paintable) w);
+        final String location = getLocation(w);
+        if (location != null) {
+            locationToWidget.remove(location);
+        }
+        final VCaptionWrapper cw = (VCaptionWrapper) widgetToCaptionWrapper
+                .get(w);
+        if (cw != null) {
+            widgetToCaptionWrapper.remove(w);
+            return super.remove(cw);
+        } else if (w != null) {
+            return super.remove(w);
+        }
+        return false;
+    }
+
+    /** Adding widget without specifying location is not supported */
+    @Override
+    public void add(Widget w) {
+        throw new UnsupportedOperationException();
+    }
+
+    /** Clear all widgets from the layout */
+    @Override
+    public void clear() {
+        super.clear();
+        locationToWidget.clear();
+        widgetToCaptionWrapper.clear();
+    }
+
+    public void iLayout() {
+        iLayoutJS(DOM.getFirstChild(getElement()));
+    }
+
+    /**
+     * This method is published to JS side with the same name into first DOM
+     * node of custom layout. This way if one implements some resizeable
+     * containers in custom layout he/she can notify children after resize.
+     */
+    public void notifyChildrenOfSizeChange() {
+        client.runDescendentsLayout(this);
+    }
+
+    @Override
+    public void onDetach() {
+        super.onDetach();
+        detachResizedFunction(elementWithNativeResizeFunction);
+    }
+
+    private native void detachResizedFunction(Element element)
+    /*-{
+       element.notifyChildrenOfSizeChange = null;
+    }-*/;
+
+    private native void publishResizedFunction(Element element)
+    /*-{
+       var self = this;
+       element.notifyChildrenOfSizeChange = function() {
+               self.@com.vaadin.terminal.gwt.client.ui.VCustomLayout::notifyChildrenOfSizeChange()();
+       };
+    }-*/;
+
+    /**
+     * In custom layout one may want to run layout functions made with
+     * JavaScript. This function tests if one exists (with name "iLayoutJS" in
+     * layouts first DOM node) and runs et. Return value is used to determine if
+     * children needs to be notified of size changes.
+     * 
+     * Note! When implementing a JS layout function you most likely want to call
+     * notifyChildrenOfSizeChange() function on your custom layouts main
+     * element. That method is used to control whether child components layout
+     * functions are to be run.
+     * 
+     * @param el
+     * @return true if layout function exists and was run successfully, else
+     *         false.
+     */
+    private native boolean iLayoutJS(Element el)
+    /*-{
+       if(el && el.iLayoutJS) {
+               try {
+                       el.iLayoutJS();
+                       return true;
+               } catch (e) {
+                       return false;
+               }
+       } else {
+               return false;
+       }
+    }-*/;
+
+    public boolean requestLayout(Set<Paintable> child) {
+        updateRelativeSizedComponents(true, true);
+
+        if (width.equals("") || height.equals("")) {
+            /* Automatically propagated upwards if the size can change */
+            return false;
+        }
+
+        return true;
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        com.google.gwt.dom.client.Element pe = child.getElement()
+                .getParentElement();
+
+        FloatSize extra = locationToExtraSize.get(getLocation(child));
+        return new RenderSpace(pe.getOffsetWidth() - (int) extra.getWidth(), pe
+                .getOffsetHeight()
+                - (int) extra.getHeight(), Util.mayHaveScrollBars(pe));
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (event.getTypeInt() == Event.ONLOAD) {
+            Util.notifyParentOfSizeChange(this, true);
+            event.cancelBubble(true);
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        if (this.height.equals(height)) {
+            return;
+        }
+
+        boolean shrinking = true;
+        if (isLarger(height, this.height)) {
+            shrinking = false;
+        }
+
+        this.height = height;
+        super.setHeight(height);
+
+        /*
+         * If the height shrinks we must remove all components with relative
+         * height from the DOM, update their height when they do not affect the
+         * available space and finally restore them to the original state
+         */
+        if (shrinking) {
+            updateRelativeSizedComponents(false, true);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (this.width.equals(width)) {
+            return;
+        }
+
+        boolean shrinking = true;
+        if (isLarger(width, this.width)) {
+            shrinking = false;
+        }
+
+        super.setWidth(width);
+        this.width = width;
+
+        /*
+         * If the width shrinks we must remove all components with relative
+         * width from the DOM, update their width when they do not affect the
+         * available space and finally restore them to the original state
+         */
+        if (shrinking) {
+            updateRelativeSizedComponents(true, false);
+        }
+    }
+
+    private void updateRelativeSizedComponents(boolean relativeWidth,
+            boolean relativeHeight) {
+
+        Set<Widget> relativeSizeWidgets = new HashSet<Widget>();
+
+        for (Widget widget : locationToWidget.values()) {
+            FloatSize relativeSize = client.getRelativeSize(widget);
+            if (relativeSize != null) {
+                if ((relativeWidth && (relativeSize.getWidth() >= 0.0f))
+                        || (relativeHeight && (relativeSize.getHeight() >= 0.0f))) {
+
+                    relativeSizeWidgets.add(widget);
+                    widget.getElement().getStyle().setProperty("position",
+                            "absolute");
+                }
+            }
+        }
+
+        for (Widget widget : relativeSizeWidgets) {
+            client.handleComponentRelativeSize(widget);
+            widget.getElement().getStyle().setProperty("position", "");
+        }
+    }
+
+    /**
+     * Compares newSize with currentSize and returns true if it is clear that
+     * newSize is larger than currentSize. Returns false if newSize is smaller
+     * or if it is unclear which one is smaller.
+     * 
+     * @param newSize
+     * @param currentSize
+     * @return
+     */
+    private boolean isLarger(String newSize, String currentSize) {
+        if (newSize.equals("") || currentSize.equals("")) {
+            return false;
+        }
+
+        if (!newSize.endsWith("px") || !currentSize.endsWith("px")) {
+            return false;
+        }
+
+        int newSizePx = Integer.parseInt(newSize.substring(0,
+                newSize.length() - 2));
+        int currentSizePx = Integer.parseInt(currentSize.substring(0,
+                currentSize.length() - 2));
+
+        boolean larger = newSizePx > currentSizePx;
+        return larger;
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateField.java b/src/com/vaadin/terminal/gwt/client/ui/VDateField.java
new file mode 100644 (file)
index 0000000..b9b2c3b
--- /dev/null
@@ -0,0 +1,233 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Date;\r
+\r
+import com.google.gwt.user.client.Event;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.ClientExceptionHandler;\r
+import com.vaadin.terminal.gwt.client.DateTimeService;\r
+import com.vaadin.terminal.gwt.client.VTooltip;\r
+import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;\r
+import com.vaadin.terminal.gwt.client.Paintable;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VDateField extends FlowPanel implements Paintable, Field {\r
+\r
+    public static final String CLASSNAME = "i-datefield";\r
+\r
+    protected String id;\r
+\r
+    protected ApplicationConnection client;\r
+\r
+    protected boolean immediate;\r
+\r
+    public static final int RESOLUTION_YEAR = 0;\r
+    public static final int RESOLUTION_MONTH = 1;\r
+    public static final int RESOLUTION_DAY = 2;\r
+    public static final int RESOLUTION_HOUR = 3;\r
+    public static final int RESOLUTION_MIN = 4;\r
+    public static final int RESOLUTION_SEC = 5;\r
+    public static final int RESOLUTION_MSEC = 6;\r
+\r
+    protected int currentResolution = RESOLUTION_YEAR;\r
+\r
+    protected String currentLocale;\r
+\r
+    protected boolean readonly;\r
+\r
+    protected boolean enabled;\r
+\r
+    protected Date date = null;\r
+    // e.g when paging a calendar, before actually selecting\r
+    protected Date showingDate = new Date();\r
+\r
+    protected DateTimeService dts;\r
+\r
+    public VDateField() {\r
+        setStyleName(CLASSNAME);\r
+        dts = new DateTimeService();\r
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);\r
+    }\r
+\r
+    @Override\r
+    public void onBrowserEvent(Event event) {\r
+        super.onBrowserEvent(event);\r
+        if (client != null) {\r
+            client.handleTooltipEvent(event, this);\r
+        }\r
+    }\r
+\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        // Ensure correct implementation and let layout manage caption\r
+        if (client.updateComponent(this, uidl, true)) {\r
+            return;\r
+        }\r
+\r
+        // Save details\r
+        this.client = client;\r
+        id = uidl.getId();\r
+        immediate = uidl.getBooleanAttribute("immediate");\r
+\r
+        readonly = uidl.getBooleanAttribute("readonly");\r
+        enabled = !uidl.getBooleanAttribute("disabled");\r
+\r
+        if (uidl.hasAttribute("locale")) {\r
+            final String locale = uidl.getStringAttribute("locale");\r
+            try {\r
+                dts.setLocale(locale);\r
+                currentLocale = locale;\r
+            } catch (final LocaleNotLoadedException e) {\r
+                currentLocale = dts.getLocale();\r
+                ClientExceptionHandler.displayError(\r
+                        "Tried to use an unloaded locale \"" + locale\r
+                                + "\". Using default locale (" + currentLocale\r
+                                + ").", e);\r
+            }\r
+        }\r
+\r
+        int newResolution;\r
+        if (uidl.hasVariable("msec")) {\r
+            newResolution = RESOLUTION_MSEC;\r
+        } else if (uidl.hasVariable("sec")) {\r
+            newResolution = RESOLUTION_SEC;\r
+        } else if (uidl.hasVariable("min")) {\r
+            newResolution = RESOLUTION_MIN;\r
+        } else if (uidl.hasVariable("hour")) {\r
+            newResolution = RESOLUTION_HOUR;\r
+        } else if (uidl.hasVariable("day")) {\r
+            newResolution = RESOLUTION_DAY;\r
+        } else if (uidl.hasVariable("month")) {\r
+            newResolution = RESOLUTION_MONTH;\r
+        } else {\r
+            newResolution = RESOLUTION_YEAR;\r
+        }\r
+\r
+        currentResolution = newResolution;\r
+\r
+        final int year = uidl.getIntVariable("year");\r
+        final int month = (currentResolution >= RESOLUTION_MONTH) ? uidl\r
+                .getIntVariable("month") : -1;\r
+        final int day = (currentResolution >= RESOLUTION_DAY) ? uidl\r
+                .getIntVariable("day") : -1;\r
+        final int hour = (currentResolution >= RESOLUTION_HOUR) ? uidl\r
+                .getIntVariable("hour") : 0;\r
+        final int min = (currentResolution >= RESOLUTION_MIN) ? uidl\r
+                .getIntVariable("min") : 0;\r
+        final int sec = (currentResolution >= RESOLUTION_SEC) ? uidl\r
+                .getIntVariable("sec") : 0;\r
+        final int msec = (currentResolution >= RESOLUTION_MSEC) ? uidl\r
+                .getIntVariable("msec") : 0;\r
+\r
+        // Construct new date for this datefield (only if not null)\r
+        if (year > -1) {\r
+            date = new Date((long) getTime(year, month, day, hour, min, sec,\r
+                    msec));\r
+            showingDate.setTime(date.getTime());\r
+        } else {\r
+            date = null;\r
+            showingDate = new Date();\r
+        }\r
+\r
+    }\r
+\r
+    /*\r
+     * We need this redundant native function because Java's Date object doesn't\r
+     * have a setMilliseconds method.\r
+     */\r
+    private static native double getTime(int y, int m, int d, int h, int mi,\r
+            int s, int ms)\r
+    /*-{\r
+       try {\r
+               var date = new Date(2000,1,1,1); // don't use current date here\r
+               if(y && y >= 0) date.setFullYear(y);\r
+               if(m && m >= 1) date.setMonth(m-1);\r
+               if(d && d >= 0) date.setDate(d);\r
+               if(h >= 0) date.setHours(h);\r
+               if(mi >= 0) date.setMinutes(mi);\r
+               if(s >= 0) date.setSeconds(s);\r
+               if(ms >= 0) date.setMilliseconds(ms);\r
+               return date.getTime();\r
+       } catch (e) {\r
+               // TODO print some error message on the console\r
+               //console.log(e);\r
+               return (new Date()).getTime();\r
+       }\r
+    }-*/;\r
+\r
+    public int getMilliseconds() {\r
+        return (int) (date.getTime() - date.getTime() / 1000 * 1000);\r
+    }\r
+\r
+    public void setMilliseconds(int ms) {\r
+        date.setTime(date.getTime() / 1000 * 1000 + ms);\r
+    }\r
+\r
+    public int getShowingMilliseconds() {\r
+        return (int) (showingDate.getTime() - showingDate.getTime() / 1000 * 1000);\r
+    }\r
+\r
+    public void setShowingMilliseconds(int ms) {\r
+        showingDate.setTime(showingDate.getTime() / 1000 * 1000 + ms);\r
+    }\r
+\r
+    public int getCurrentResolution() {\r
+        return currentResolution;\r
+    }\r
+\r
+    public void setCurrentResolution(int currentResolution) {\r
+        this.currentResolution = currentResolution;\r
+    }\r
+\r
+    public String getCurrentLocale() {\r
+        return currentLocale;\r
+    }\r
+\r
+    public void setCurrentLocale(String currentLocale) {\r
+        this.currentLocale = currentLocale;\r
+    }\r
+\r
+    public Date getCurrentDate() {\r
+        return date;\r
+    }\r
+\r
+    public void setCurrentDate(Date date) {\r
+        this.date = date;\r
+    }\r
+\r
+    public Date getShowingDate() {\r
+        return showingDate;\r
+    }\r
+\r
+    public void setShowingDate(Date date) {\r
+        showingDate = date;\r
+    }\r
+\r
+    public boolean isImmediate() {\r
+        return immediate;\r
+    }\r
+\r
+    public boolean isReadonly() {\r
+        return readonly;\r
+    }\r
+\r
+    public boolean isEnabled() {\r
+        return enabled;\r
+    }\r
+\r
+    public DateTimeService getDateTimeService() {\r
+        return dts;\r
+    }\r
+\r
+    public String getId() {\r
+        return id;\r
+    }\r
+\r
+    public ApplicationConnection getClient() {\r
+        return client;\r
+    }\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VDateFieldCalendar.java
new file mode 100644 (file)
index 0000000..fec6756
--- /dev/null
@@ -0,0 +1,26 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VDateFieldCalendar extends VDateField {\r
+\r
+    private final VCalendarPanel date;\r
+\r
+    public VDateFieldCalendar() {\r
+        super();\r
+        date = new VCalendarPanel(this);\r
+        add(date);\r
+    }\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        super.updateFromUIDL(uidl, client);\r
+        date.updateCalendar();\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java b/src/com/vaadin/terminal/gwt/client/ui/VEmbedded.java
new file mode 100644 (file)
index 0000000..8d56821
--- /dev/null
@@ -0,0 +1,225 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Node;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.ObjectElement;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VEmbedded extends HTML implements Paintable {
+    private static String CLASSNAME = "i-embedded";
+
+    private String height;
+    private String width;
+    private Element browserElement;
+
+    private ApplicationConnection client;
+
+    public VEmbedded() {
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+        this.client = client;
+
+        boolean clearBrowserElement = true;
+
+        if (uidl.hasAttribute("type")) {
+            final String type = uidl.getStringAttribute("type");
+            if (type.equals("image")) {
+                Element el = null;
+                boolean created = false;
+                NodeList nodes = getElement().getChildNodes();
+                if (nodes != null && nodes.getLength() == 1) {
+                    Node n = nodes.getItem(0);
+                    if (n.getNodeType() == Node.ELEMENT_NODE) {
+                        Element e = (Element) n;
+                        if (e.getTagName().equals("IMG")) {
+                            el = e;
+                        }
+                    }
+                }
+                if (el == null) {
+                    setHTML("");
+                    el = DOM.createImg();
+                    created = true;
+                    client.addPngFix(el);
+                    DOM.sinkEvents(el, Event.ONLOAD);
+                }
+
+                // Set attributes
+                Style style = el.getStyle();
+                String w = uidl.getStringAttribute("width");
+                if (w != null) {
+                    style.setProperty("width", w);
+                } else {
+                    style.setProperty("width", "");
+                }
+                String h = uidl.getStringAttribute("height");
+                if (h != null) {
+                    style.setProperty("height", h);
+                } else {
+                    style.setProperty("height", "");
+                }
+                DOM.setElementProperty(el, "src", getSrc(uidl, client));
+
+                if (created) {
+                    // insert in dom late
+                    getElement().appendChild(el);
+                }
+
+            } else if (type.equals("browser")) {
+                if (browserElement == null) {
+                    setHTML("<iframe width=\"100%\" height=\"100%\" frameborder=\"0\" src=\""
+                            + getSrc(uidl, client)
+                            + "\" name=\""
+                            + uidl.getId() + "\"></iframe>");
+                    browserElement = DOM.getFirstChild(getElement());
+                } else {
+                    DOM.setElementAttribute(browserElement, "src", getSrc(uidl,
+                            client));
+                }
+                clearBrowserElement = false;
+            } else {
+                ApplicationConnection.getConsole().log(
+                        "Unknown Embedded type '" + type + "'");
+            }
+        } else if (uidl.hasAttribute("mimetype")) {
+            final String mime = uidl.getStringAttribute("mimetype");
+            if (mime.equals("application/x-shockwave-flash")) {
+                setHTML("<object width=\"" + width + "\" height=\"" + height
+                        + "\"><param name=\"movie\" value=\""
+                        + getSrc(uidl, client) + "\"><embed src=\""
+                        + getSrc(uidl, client) + "\" width=\"" + width
+                        + "\" height=\"" + height + "\"></embed></object>");
+            } else if (mime.equals("image/svg+xml")) {
+                String data;
+                if (getParameter("data", uidl) == null) {
+                    data = getSrc(uidl, client);
+                } else {
+                    data = "data:image/svg+xml," + getParameter("data", uidl);
+                }
+                setHTML("");
+                ObjectElement obj = Document.get().createObjectElement();
+                obj.setType(mime);
+                obj.setData(data);
+                if (width != null) {
+                    obj.getStyle().setProperty("width", "100%");
+                }
+                if (height != null) {
+                    obj.getStyle().setProperty("height", "100%");
+                }
+                getElement().appendChild(obj);
+
+            } else {
+                ApplicationConnection.getConsole().log(
+                        "Unknown Embedded mimetype '" + mime + "'");
+            }
+        } else {
+            ApplicationConnection.getConsole().log(
+                    "Unknown Embedded; no type or mimetype attribute");
+        }
+
+        if (clearBrowserElement) {
+            browserElement = null;
+        }
+
+    }
+
+    private static String getParameter(String paramName, UIDL uidl) {
+        Iterator childIterator = uidl.getChildIterator();
+        while (childIterator.hasNext()) {
+            Object child = childIterator.next();
+            if (child instanceof UIDL) {
+                UIDL childUIDL = (UIDL) child;
+                if (childUIDL.getTag().equals("embeddedparam")
+                        && childUIDL.getStringAttribute("name").equals(
+                                paramName)) {
+                    return childUIDL.getStringAttribute("value");
+                }
+
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Helper to return translated src-attribute from embedded's UIDL
+     * 
+     * @param uidl
+     * @param client
+     * @return
+     */
+    private String getSrc(UIDL uidl, ApplicationConnection client) {
+        String url = client.translateToolkitUri(uidl.getStringAttribute("src"));
+        if (url == null) {
+            return "";
+        }
+        return url;
+    }
+
+    @Override
+    public void setWidth(String width) {
+        this.width = width;
+        if (isDynamicHeight()) {
+            int oldHeight = getOffsetHeight();
+            super.setWidth(width);
+            int newHeight = getOffsetHeight();
+            /*
+             * Must notify parent if the height changes as a result of a width
+             * change
+             */
+            if (oldHeight != newHeight) {
+                Util.notifyParentOfSizeChange(this, false);
+            }
+        } else {
+            super.setWidth(width);
+        }
+
+    }
+
+    private boolean isDynamicHeight() {
+        return height == null || height.equals("");
+    }
+
+    @Override
+    public void setHeight(String height) {
+        this.height = height;
+        super.setHeight(height);
+    }
+
+    @Override
+    protected void onDetach() {
+        // Force browser to fire unload event when component is detached from
+        // the view (IE doesn't do this automatically)
+        if (browserElement != null) {
+            DOM.setElementAttribute(browserElement, "src", "javascript:false");
+        }
+        super.onDetach();
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (DOM.eventGetType(event) == Event.ONLOAD) {
+            Util.notifyParentOfSizeChange(this, true);
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
new file mode 100644 (file)
index 0000000..378986e
--- /dev/null
@@ -0,0 +1,1059 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+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.ClickListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusListener;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.Image;
+import com.google.gwt.user.client.ui.KeyboardListener;
+import com.google.gwt.user.client.ui.LoadListener;
+import com.google.gwt.user.client.ui.PopupListener;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Focusable;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+/**
+ * 
+ * TODO needs major refactoring (to be extensible etc)
+ */
+public class VFilterSelect extends Composite implements Paintable, Field,
+        KeyboardListener, ClickListener, FocusListener, Focusable {
+
+    public class FilterSelectSuggestion implements Suggestion, Command {
+
+        private final String key;
+        private final String caption;
+        private String iconUri;
+
+        public FilterSelectSuggestion(UIDL uidl) {
+            key = uidl.getStringAttribute("key");
+            caption = uidl.getStringAttribute("caption");
+            if (uidl.hasAttribute("icon")) {
+                iconUri = client.translateToolkitUri(uidl
+                        .getStringAttribute("icon"));
+            }
+        }
+
+        public String getDisplayString() {
+            final StringBuffer sb = new StringBuffer();
+            if (iconUri != null) {
+                sb.append("<img src=\"");
+                sb.append(iconUri);
+                sb.append("\" alt=\"\" class=\"i-icon\" />");
+            }
+            sb.append("<span>" + Util.escapeHTML(caption) + "</span>");
+            return sb.toString();
+        }
+
+        public String getReplacementString() {
+            return caption;
+        }
+
+        public int getOptionKey() {
+            return Integer.parseInt(key);
+        }
+
+        public String getIconUri() {
+            return iconUri;
+        }
+
+        public void execute() {
+            onSuggestionSelected(this);
+        }
+    }
+
+    public class SuggestionPopup extends VToolkitOverlay implements
+            PositionCallback, PopupListener {
+
+        private static final String Z_INDEX = "30000";
+
+        private final SuggestionMenu menu;
+
+        private final Element up = DOM.createDiv();
+        private final Element down = DOM.createDiv();
+        private final Element status = DOM.createDiv();
+
+        private boolean isPagingEnabled = true;
+
+        private long lastAutoClosed;
+
+        private int popupOuterPadding = -1;
+
+        private int topPosition;
+
+        SuggestionPopup() {
+            super(true, false, true);
+            menu = new SuggestionMenu();
+            setWidget(menu);
+            setStyleName(CLASSNAME + "-suggestpopup");
+            DOM.setStyleAttribute(getElement(), "zIndex", Z_INDEX);
+
+            final Element root = getContainerElement();
+
+            DOM.setInnerHTML(up, "<span>Prev</span>");
+            DOM.sinkEvents(up, Event.ONCLICK);
+            DOM.setInnerHTML(down, "<span>Next</span>");
+            DOM.sinkEvents(down, Event.ONCLICK);
+            DOM.insertChild(root, up, 0);
+            DOM.appendChild(root, down);
+            DOM.appendChild(root, status);
+            DOM.setElementProperty(status, "className", CLASSNAME + "-status");
+
+            addPopupListener(this);
+        }
+
+        public void showSuggestions(
+                Collection<FilterSelectSuggestion> currentSuggestions,
+                int currentPage, int totalSuggestions) {
+
+            // Add TT anchor point
+            DOM.setElementProperty(getElement(), "id",
+                    "TOOLKIT_COMBOBOX_OPTIONLIST");
+
+            menu.setSuggestions(currentSuggestions);
+            final int x = VFilterSelect.this.getAbsoluteLeft();
+            topPosition = tb.getAbsoluteTop();
+            topPosition += tb.getOffsetHeight();
+            setPopupPosition(x, topPosition);
+
+            final int first = currentPage * PAGELENTH
+                    + (nullSelectionAllowed && currentPage > 0 ? 0 : 1);
+            final int last = first + currentSuggestions.size() - 1;
+            final int matches = totalSuggestions
+                    - (nullSelectionAllowed ? 1 : 0);
+            if (last > 0) {
+                // nullsel not counted, as requested by user
+                DOM.setInnerText(status, (matches == 0 ? 0 : first)
+                        + "-"
+                        + ("".equals(lastFilter) && nullSelectionAllowed
+                                && currentPage == 0 ? last - 1 : last) + "/"
+                        + matches);
+            } else {
+                DOM.setInnerText(status, "");
+            }
+            // We don't need to show arrows or statusbar if there is only one
+            // page
+            if (matches <= PAGELENTH) {
+                setPagingEnabled(false);
+            } else {
+                setPagingEnabled(true);
+            }
+            setPrevButtonActive(first > 1);
+            setNextButtonActive(last < matches);
+
+            // clear previously fixed width
+            menu.setWidth("");
+            DOM.setStyleAttribute(DOM.getFirstChild(menu.getElement()),
+                    "width", "");
+
+            setPopupPositionAndShow(this);
+        }
+
+        private void setNextButtonActive(boolean b) {
+            if (b) {
+                DOM.sinkEvents(down, Event.ONCLICK);
+                DOM.setElementProperty(down, "className", CLASSNAME
+                        + "-nextpage");
+            } else {
+                DOM.sinkEvents(down, 0);
+                DOM.setElementProperty(down, "className", CLASSNAME
+                        + "-nextpage-off");
+            }
+        }
+
+        private void setPrevButtonActive(boolean b) {
+            if (b) {
+                DOM.sinkEvents(up, Event.ONCLICK);
+                DOM
+                        .setElementProperty(up, "className", CLASSNAME
+                                + "-prevpage");
+            } else {
+                DOM.sinkEvents(up, 0);
+                DOM.setElementProperty(up, "className", CLASSNAME
+                        + "-prevpage-off");
+            }
+
+        }
+
+        public void selectNextItem() {
+            final MenuItem cur = menu.getSelectedItem();
+            final int index = 1 + menu.getItems().indexOf(cur);
+            if (menu.getItems().size() > index) {
+                final MenuItem newSelectedItem = (MenuItem) menu.getItems()
+                        .get(index);
+                menu.selectItem(newSelectedItem);
+                tb.setText(newSelectedItem.getText());
+                tb.setSelectionRange(lastFilter.length(), newSelectedItem
+                        .getText().length()
+                        - lastFilter.length());
+
+            } else if (hasNextPage()) {
+                lastIndex = index - 1; // save for paging
+                filterOptions(currentPage + 1, lastFilter);
+            }
+        }
+
+        public void selectPrevItem() {
+            final MenuItem cur = menu.getSelectedItem();
+            final int index = -1 + menu.getItems().indexOf(cur);
+            if (index > -1) {
+                final MenuItem newSelectedItem = (MenuItem) menu.getItems()
+                        .get(index);
+                menu.selectItem(newSelectedItem);
+                tb.setText(newSelectedItem.getText());
+                tb.setSelectionRange(lastFilter.length(), newSelectedItem
+                        .getText().length()
+                        - lastFilter.length());
+            } else if (index == -1) {
+                if (currentPage > 0) {
+                    lastIndex = index + 1; // save for paging
+                    filterOptions(currentPage - 1, lastFilter);
+                }
+            } else {
+                final MenuItem newSelectedItem = (MenuItem) menu.getItems()
+                        .get(menu.getItems().size() - 1);
+                menu.selectItem(newSelectedItem);
+                tb.setText(newSelectedItem.getText());
+                tb.setSelectionRange(lastFilter.length(), newSelectedItem
+                        .getText().length()
+                        - lastFilter.length());
+            }
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            final Element target = DOM.eventGetTarget(event);
+            if (DOM.compare(target, up)
+                    || DOM.compare(target, DOM.getChild(up, 0))) {
+                filterOptions(currentPage - 1, lastFilter);
+            } else if (DOM.compare(target, down)
+                    || DOM.compare(target, DOM.getChild(down, 0))) {
+                filterOptions(currentPage + 1, lastFilter);
+            }
+            tb.setFocus(true);
+        }
+
+        public void setPagingEnabled(boolean paging) {
+            if (isPagingEnabled == paging) {
+                return;
+            }
+            if (paging) {
+                DOM.setStyleAttribute(down, "display", "");
+                DOM.setStyleAttribute(up, "display", "");
+                DOM.setStyleAttribute(status, "display", "");
+            } else {
+                DOM.setStyleAttribute(down, "display", "none");
+                DOM.setStyleAttribute(up, "display", "none");
+                DOM.setStyleAttribute(status, "display", "none");
+            }
+            isPagingEnabled = paging;
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see
+         * com.google.gwt.user.client.ui.PopupPanel$PositionCallback#setPosition
+         * (int, int)
+         */
+        public void setPosition(int offsetWidth, int offsetHeight) {
+
+            int top = -1;
+            int left = -1;
+
+            // reset menu size and retrieve its "natural" size
+            menu.setHeight("");
+            if (currentPage > 0) {
+                // fix height to avoid height change when getting to last page
+                menu.fixHeightTo(PAGELENTH);
+            }
+            offsetHeight = getOffsetHeight();
+
+            final int desiredWidth = getMainWidth();
+            int naturalMenuWidth = DOM.getElementPropertyInt(DOM
+                    .getFirstChild(menu.getElement()), "offsetWidth");
+
+            if (popupOuterPadding == -1) {
+                popupOuterPadding = Util.measureHorizontalPaddingAndBorder(
+                        getElement(), 2);
+            }
+
+            if (naturalMenuWidth < desiredWidth) {
+                menu.setWidth((desiredWidth - popupOuterPadding) + "px");
+                DOM.setStyleAttribute(DOM.getFirstChild(menu.getElement()),
+                        "width", "100%");
+                naturalMenuWidth = desiredWidth;
+            }
+
+            if (BrowserInfo.get().isIE()) {
+                /*
+                 * IE requires us to specify the width for the container
+                 * element. Otherwise it will be 100% wide
+                 */
+                int rootWidth = naturalMenuWidth - popupOuterPadding;
+                DOM.setStyleAttribute(getContainerElement(), "width", rootWidth
+                        + "px");
+            }
+
+            if (offsetHeight + getPopupTop() > Window.getClientHeight()
+                    + Window.getScrollTop()) {
+                // popup on top of input instead
+                top = getPopupTop() - offsetHeight
+                        - VFilterSelect.this.getOffsetHeight();
+                if (top < 0) {
+                    top = 0;
+                }
+            } else {
+                top = getPopupTop();
+                /*
+                 * Take popup top margin into account. getPopupTop() returns the
+                 * top value including the margin but the value we give must not
+                 * include the margin.
+                 */
+                int topMargin = (top - topPosition);
+                top -= topMargin;
+            }
+
+            // fetch real width (mac FF bugs here due GWT popups overflow:auto )
+            offsetWidth = DOM.getElementPropertyInt(DOM.getFirstChild(menu
+                    .getElement()), "offsetWidth");
+            if (offsetWidth + getPopupLeft() > Window.getClientWidth()
+                    + Window.getScrollLeft()) {
+                left = VFilterSelect.this.getAbsoluteLeft()
+                        + VFilterSelect.this.getOffsetWidth()
+                        + Window.getScrollLeft() - offsetWidth;
+                if (left < 0) {
+                    left = 0;
+                }
+            } else {
+                left = getPopupLeft();
+            }
+            setPopupPosition(left, top);
+
+        }
+
+        /**
+         * @return true if popup was just closed
+         */
+        public boolean isJustClosed() {
+            final long now = (new Date()).getTime();
+            return (lastAutoClosed > 0 && (now - lastAutoClosed) < 200);
+        }
+
+        public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+            if (autoClosed) {
+                lastAutoClosed = (new Date()).getTime();
+            }
+        }
+
+        /**
+         * Updates style names in suggestion popup to help theme building.
+         */
+        public void updateStyleNames(UIDL uidl) {
+            if (uidl.hasAttribute("style")) {
+                setStyleName(CLASSNAME + "-suggestpopup");
+                final String[] styles = uidl.getStringAttribute("style").split(
+                        " ");
+                for (int i = 0; i < styles.length; i++) {
+                    addStyleDependentName(styles[i]);
+                }
+            }
+        }
+
+    }
+
+    public class SuggestionMenu extends MenuBar {
+
+        SuggestionMenu() {
+            super(true);
+            setStyleName(CLASSNAME + "-suggestmenu");
+        }
+
+        /**
+         * Fixes menus height to use same space as full page would use. Needed
+         * to avoid height changes when quickly "scrolling" to last page
+         */
+        public void fixHeightTo(int pagelenth) {
+            if (currentSuggestions.size() > 0) {
+                final int pixels = pagelenth * (getOffsetHeight() - 2)
+                        / currentSuggestions.size();
+                setHeight((pixels + 2) + "px");
+            }
+        }
+
+        public void setSuggestions(
+                Collection<FilterSelectSuggestion> suggestions) {
+            clearItems();
+            final Iterator<FilterSelectSuggestion> it = suggestions.iterator();
+            while (it.hasNext()) {
+                final FilterSelectSuggestion s = it.next();
+                final MenuItem mi = new MenuItem(s.getDisplayString(), true, s);
+
+                com.google.gwt.dom.client.Element child = mi.getElement()
+                        .getFirstChildElement();
+                while (child != null) {
+                    if (child.getNodeName().toLowerCase().equals("img")) {
+                        DOM
+                                .sinkEvents((Element) child.cast(),
+                                        (DOM.getEventsSunk((Element) child
+                                                .cast()) | Event.ONLOAD));
+                    }
+                    child = child.getNextSiblingElement();
+                }
+
+                this.addItem(mi);
+                if (s == currentSuggestion) {
+                    selectItem(mi);
+                }
+            }
+        }
+
+        public void doSelectedItemAction() {
+            final MenuItem item = getSelectedItem();
+            final String enteredItemValue = tb.getText();
+            // check for exact match in menu
+            int p = getItems().size();
+            if (p > 0) {
+                for (int i = 0; i < p; i++) {
+                    final MenuItem potentialExactMatch = (MenuItem) getItems()
+                            .get(i);
+                    if (potentialExactMatch.getText().equals(enteredItemValue)) {
+                        selectItem(potentialExactMatch);
+                        doItemAction(potentialExactMatch, true);
+                        suggestionPopup.hide();
+                        return;
+                    }
+                }
+            }
+            if (allowNewItem) {
+
+                if (!prompting && !enteredItemValue.equals(lastNewItemString)) {
+                    /*
+                     * Store last sent new item string to avoid double sends
+                     */
+                    lastNewItemString = enteredItemValue;
+                    client.updateVariable(paintableId, "newitem",
+                            enteredItemValue, immediate);
+                }
+            } else if (item != null
+                    && !"".equals(lastFilter)
+                    && item.getText().toLowerCase().startsWith(
+                            lastFilter.toLowerCase())) {
+                doItemAction(item, true);
+            } else {
+                if (currentSuggestion != null) {
+                    String text = currentSuggestion.getReplacementString();
+                    /* TODO?
+                    if (text.equals("")) {
+                        addStyleDependentName(CLASSNAME_PROMPT);
+                        tb.setText(inputPrompt);
+                        prompting = true;
+                    } else {
+                        tb.setText(text);
+                        prompting = false;
+                        removeStyleDependentName(CLASSNAME_PROMPT);
+                    }
+                    */
+                    selectedOptionKey = currentSuggestion.key;
+                }
+            }
+            suggestionPopup.hide();
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            if (event.getTypeInt() == Event.ONLOAD) {
+                if (suggestionPopup.isVisible()) {
+                    setWidth("");
+                    DOM.setStyleAttribute(DOM.getFirstChild(getElement()),
+                            "width", "");
+                    suggestionPopup.setPopupPositionAndShow(suggestionPopup);
+                }
+            }
+            super.onBrowserEvent(event);
+        }
+    }
+
+    public static final int FILTERINGMODE_OFF = 0;
+    public static final int FILTERINGMODE_STARTSWITH = 1;
+    public static final int FILTERINGMODE_CONTAINS = 2;
+
+    private static final String CLASSNAME = "i-filterselect";
+
+    public static final int PAGELENTH = 10;
+
+    private final FlowPanel panel = new FlowPanel();
+
+    private final TextBox tb = new TextBox() {
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (client != null) {
+                client.handleTooltipEvent(event, VFilterSelect.this);
+            }
+        }
+    };
+
+    private final SuggestionPopup suggestionPopup = new SuggestionPopup();
+
+    private final HTML popupOpener = new HTML("");
+
+    private final Image selectedItemIcon = new Image();
+
+    private ApplicationConnection client;
+
+    private String paintableId;
+
+    private int currentPage;
+
+    private final Collection<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>();
+
+    private boolean immediate;
+
+    private String selectedOptionKey;
+
+    private boolean filtering = false;
+
+    private String lastFilter = "";
+    private int lastIndex = -1; // last selected index when using arrows
+
+    private FilterSelectSuggestion currentSuggestion;
+
+    private int totalMatches;
+    private boolean allowNewItem;
+    private boolean nullSelectionAllowed;
+    private boolean enabled;
+
+    // shown in unfocused empty field, disappears on focus (e.g "Search here")
+    private static final String CLASSNAME_PROMPT = "prompt";
+    private static final String ATTR_INPUTPROMPT = "prompt";
+    private String inputPrompt = "";
+    private boolean prompting = false;
+
+    // Set true when popupopened has been clicked. Cleared on each UIDL-update.
+    // This handles the special case where are not filtering yet and the
+    // selected value has changed on the server-side. See #2119
+    private boolean popupOpenerClicked;
+    private String width = null;
+    private int textboxPadding = -1;
+    private int componentPadding = -1;
+    private int suggestionPopupMinWidth = 0;
+    /*
+     * Stores the last new item string to avoid double submissions. Cleared on
+     * uidl updates
+     */
+    private String lastNewItemString;
+    private boolean focused = false;
+
+    public VFilterSelect() {
+        selectedItemIcon.setVisible(false);
+        selectedItemIcon.setStyleName("i-icon");
+        selectedItemIcon.addLoadListener(new LoadListener() {
+            public void onError(Widget sender) {
+            }
+
+            public void onLoad(Widget sender) {
+                updateRootWidth();
+                updateSelectedIconPosition();
+            }
+        });
+
+        panel.add(selectedItemIcon);
+        tb.sinkEvents(VTooltip.TOOLTIP_EVENTS);
+        panel.add(tb);
+        panel.add(popupOpener);
+        initWidget(panel);
+        setStyleName(CLASSNAME);
+        tb.addKeyboardListener(this);
+        tb.setStyleName(CLASSNAME + "-input");
+        tb.addFocusListener(this);
+        popupOpener.setStyleName(CLASSNAME + "-button");
+        popupOpener.addClickListener(this);
+    }
+
+    public boolean hasNextPage() {
+        if (totalMatches > (currentPage + 1) * PAGELENTH) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void filterOptions(int page) {
+        filterOptions(page, tb.getText());
+    }
+
+    public void filterOptions(int page, String filter) {
+        if (filter.equals(lastFilter) && currentPage == page) {
+            if (!suggestionPopup.isAttached()) {
+                suggestionPopup.showSuggestions(currentSuggestions,
+                        currentPage, totalMatches);
+            }
+            return;
+        }
+        if (!filter.equals(lastFilter)) {
+            // we are on subsequent page and text has changed -> reset page
+            if ("".equals(filter)) {
+                // let server decide
+                page = -1;
+            } else {
+                page = 0;
+            }
+        }
+
+        filtering = true;
+        client.updateVariable(paintableId, "filter", filter, false);
+        client.updateVariable(paintableId, "page", page, true);
+        lastFilter = filter;
+        currentPage = page;
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        paintableId = uidl.getId();
+        this.client = client;
+
+        boolean readonly = uidl.hasAttribute("readonly");
+        boolean disabled = uidl.hasAttribute("disabled");
+
+        if (disabled || readonly) {
+            tb.setEnabled(false);
+            enabled = false;
+        } else {
+            tb.setEnabled(true);
+            enabled = true;
+        }
+
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        // not a FocusWidget -> needs own tabindex handling
+        if (uidl.hasAttribute("tabindex")) {
+            tb.setTabIndex(uidl.getIntAttribute("tabindex"));
+        }
+
+        immediate = uidl.hasAttribute("immediate");
+
+        nullSelectionAllowed = uidl.hasAttribute("nullselect");
+
+        currentPage = uidl.getIntVariable("page");
+
+        if (uidl.hasAttribute(ATTR_INPUTPROMPT)) {
+            // input prompt changed from server
+            inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
+        } else {
+            inputPrompt = "";
+        }
+
+        suggestionPopup.setPagingEnabled(true);
+        suggestionPopup.updateStyleNames(uidl);
+
+        allowNewItem = uidl.hasAttribute("allownewitem");
+        lastNewItemString = null;
+
+        currentSuggestions.clear();
+        final UIDL options = uidl.getChildUIDL(0);
+        totalMatches = uidl.getIntAttribute("totalMatches");
+
+        String captions = inputPrompt;
+
+        for (final Iterator i = options.getChildIterator(); i.hasNext();) {
+            final UIDL optionUidl = (UIDL) i.next();
+            final FilterSelectSuggestion suggestion = new FilterSelectSuggestion(
+                    optionUidl);
+            currentSuggestions.add(suggestion);
+            if (optionUidl.hasAttribute("selected")) {
+                if (!filtering || popupOpenerClicked) {
+                    tb.setText(suggestion.getReplacementString());
+                    selectedOptionKey = "" + suggestion.getOptionKey();
+                }
+                currentSuggestion = suggestion;
+                setSelectedItemIcon(suggestion.getIconUri());
+            }
+
+            // Collect captions so we can calculate minimum width for textarea
+            if (captions.length() > 0) {
+                captions += "|";
+            }
+            captions += suggestion.getReplacementString();
+        }
+
+        if ((!filtering || popupOpenerClicked) && uidl.hasVariable("selected")
+                && uidl.getStringArrayVariable("selected").length == 0) {
+            // select nulled
+            if (!filtering || !popupOpenerClicked) {
+                setPromptingOn();
+            }
+            selectedOptionKey = null;
+        }
+
+        if (filtering
+                && lastFilter.toLowerCase().equals(
+                        uidl.getStringVariable("filter"))) {
+            suggestionPopup.showSuggestions(currentSuggestions, currentPage,
+                    totalMatches);
+            filtering = false;
+            if (!popupOpenerClicked && lastIndex != -1) {
+                // we're paging w/ arrows
+                if (lastIndex == 0) {
+                    // going up, select last item
+                    int lastItem = PAGELENTH - 1;
+                    List items = suggestionPopup.menu.getItems();
+                    /*
+                     * The first page can contain less than 10 items if the null
+                     * selection item is filtered away
+                     */
+                    if (lastItem >= items.size()) {
+                        lastItem = items.size() - 1;
+                    }
+                    suggestionPopup.menu.selectItem((MenuItem) items
+                            .get(lastItem));
+                } else {
+                    // going down, select first item
+                    suggestionPopup.menu
+                            .selectItem((MenuItem) suggestionPopup.menu
+                                    .getItems().get(0));
+                }
+                lastIndex = -1; // reset
+            }
+        }
+
+        // Calculate minumum textarea width
+        suggestionPopupMinWidth = minWidth(captions);
+
+        popupOpenerClicked = false;
+
+        updateRootWidth();
+    }
+
+    private void setPromptingOn() {
+        prompting = true;
+        addStyleDependentName(CLASSNAME_PROMPT);
+        tb.setText(inputPrompt);
+    }
+
+    private void setPromptingOff(String text) {
+        tb.setText(text);
+        prompting = false;
+        removeStyleDependentName(CLASSNAME_PROMPT);
+    }
+
+    public void onSuggestionSelected(FilterSelectSuggestion suggestion) {
+        currentSuggestion = suggestion;
+        String newKey;
+        if (suggestion.key.equals("")) {
+            // "nullselection"
+            newKey = "";
+        } else {
+            // normal selection
+            newKey = String.valueOf(suggestion.getOptionKey());
+        }
+
+        String text = suggestion.getReplacementString();
+        if ("".equals(newKey) && !focused) {
+            setPromptingOn();
+        } else {
+            setPromptingOff(text);
+        }
+        setSelectedItemIcon(suggestion.getIconUri());
+        if (!newKey.equals(selectedOptionKey)) {
+            selectedOptionKey = newKey;
+            client.updateVariable(paintableId, "selected",
+                    new String[] { selectedOptionKey }, immediate);
+            // currentPage = -1; // forget the page
+        }
+        suggestionPopup.hide();
+    }
+
+    private void setSelectedItemIcon(String iconUri) {
+        if (iconUri == null) {
+            selectedItemIcon.setVisible(false);
+            updateRootWidth();
+        } else {
+            selectedItemIcon.setUrl(iconUri);
+            selectedItemIcon.setVisible(true);
+            updateRootWidth();
+            updateSelectedIconPosition();
+        }
+    }
+
+    private void updateSelectedIconPosition() {
+        // Position icon vertically to middle
+        int availableHeight = getOffsetHeight();
+        int iconHeight = Util.getRequiredHeight(selectedItemIcon);
+        int marginTop = (availableHeight - iconHeight) / 2;
+        DOM.setStyleAttribute(selectedItemIcon.getElement(), "marginTop",
+                marginTop + "px");
+    }
+
+    public void onKeyDown(Widget sender, char keyCode, int modifiers) {
+        if (enabled && suggestionPopup.isAttached()) {
+            switch (keyCode) {
+            case KeyboardListener.KEY_DOWN:
+                suggestionPopup.selectNextItem();
+                DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+                break;
+            case KeyboardListener.KEY_UP:
+                suggestionPopup.selectPrevItem();
+                DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+                break;
+            case KeyboardListener.KEY_PAGEDOWN:
+                if (hasNextPage()) {
+                    filterOptions(currentPage + 1, lastFilter);
+                }
+                break;
+            case KeyboardListener.KEY_PAGEUP:
+                if (currentPage > 0) {
+                    filterOptions(currentPage - 1, lastFilter);
+                }
+                break;
+            case KeyboardListener.KEY_ENTER:
+            case KeyboardListener.KEY_TAB:
+                suggestionPopup.menu.doSelectedItemAction();
+                break;
+            }
+        }
+    }
+
+    public void onKeyPress(Widget sender, char keyCode, int modifiers) {
+
+    }
+
+    public void onKeyUp(Widget sender, char keyCode, int modifiers) {
+        if (enabled) {
+            switch (keyCode) {
+            case KeyboardListener.KEY_ENTER:
+            case KeyboardListener.KEY_TAB:
+            case KeyboardListener.KEY_SHIFT:
+            case KeyboardListener.KEY_CTRL:
+            case KeyboardListener.KEY_ALT:
+                ; // NOP
+                break;
+            case KeyboardListener.KEY_DOWN:
+            case KeyboardListener.KEY_UP:
+            case KeyboardListener.KEY_PAGEDOWN:
+            case KeyboardListener.KEY_PAGEUP:
+                if (suggestionPopup.isAttached()) {
+                    break;
+                } else {
+                    // open popup as from gadget
+                    filterOptions(-1, "");
+                    lastFilter = "";
+                    tb.selectAll();
+                    break;
+                }
+            case KeyboardListener.KEY_ESCAPE:
+                if (currentSuggestion != null) {
+                    String text = currentSuggestion.getReplacementString();
+                    setPromptingOff(text);
+                    selectedOptionKey = currentSuggestion.key;
+                } else {
+                    setPromptingOn();
+                    selectedOptionKey = null;
+                }
+                lastFilter = "";
+                suggestionPopup.hide();
+                break;
+            default:
+                filterOptions(currentPage);
+                break;
+            }
+        }
+    }
+
+    /**
+     * Listener for popupopener
+     */
+    public void onClick(Widget sender) {
+        if (enabled) {
+            // ask suggestionPopup if it was just closed, we are using GWT
+            // Popup's auto close feature
+            if (!suggestionPopup.isJustClosed()) {
+                filterOptions(-1, "");
+                popupOpenerClicked = true;
+                lastFilter = "";
+            } else if (selectedOptionKey == null) {
+                tb.setText(inputPrompt);
+                prompting = true;
+            }
+            DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+            tb.setFocus(true);
+            tb.selectAll();
+
+        }
+    }
+
+    /*
+     * Calculate minumum width for FilterSelect textarea
+     */
+    private native int minWidth(String captions)
+    /*-{
+        if(!captions || captions.length <= 0)
+                return 0;
+        captions = captions.split("|");
+        var d = $wnd.document.createElement("div");
+        var html = "";
+        for(var i=0; i < captions.length; i++) {
+                html += "<div>" + captions[i] + "</div>";
+                // TODO apply same CSS classname as in suggestionmenu
+        }
+        d.style.position = "absolute";
+        d.style.top = "0";
+        d.style.left = "0";
+        d.style.visibility = "hidden";
+        d.innerHTML = html;
+        $wnd.document.body.appendChild(d);
+        var w = d.offsetWidth;
+        $wnd.document.body.removeChild(d);
+        return w;
+    }-*/;
+
+    public void onFocus(Widget sender) {
+        focused = true;
+        if (prompting) {
+            setPromptingOff("");
+        }
+        addStyleDependentName("focus");
+    }
+
+    public void onLostFocus(Widget sender) {
+        focused = false;
+        if (!suggestionPopup.isAttached() || suggestionPopup.isJustClosed()) {
+            // typing so fast the popup was never opened, or it's just closed
+            suggestionPopup.menu.doSelectedItemAction();
+        }
+        if (selectedOptionKey == null) {
+            setPromptingOn();
+        }
+        removeStyleDependentName("focus");
+    }
+
+    public void focus() {
+        focused = true;
+        if (prompting) {
+            setPromptingOff("");
+        }
+        tb.setFocus(true);
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (width == null || width.equals("")) {
+            this.width = null;
+        } else {
+            this.width = width;
+        }
+        Util.setWidthExcludingPaddingAndBorder(this, width, 4);
+        updateRootWidth();
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        Util.setHeightExcludingPaddingAndBorder(tb, height, 3);
+    }
+
+    private void updateRootWidth() {
+        if (width == null) {
+            /*
+             * When the width is not specified we must specify width for root
+             * div so the popupopener won't wrap to the next line and also so
+             * the size of the combobox won't change over time.
+             */
+            int tbWidth = Util.getRequiredWidth(tb);
+            int openerWidth = Util.getRequiredWidth(popupOpener);
+            int iconWidth = Util.getRequiredWidth(selectedItemIcon);
+
+            int w = tbWidth + openerWidth + iconWidth;
+            if (suggestionPopupMinWidth > w) {
+                setTextboxWidth(suggestionPopupMinWidth);
+                w = suggestionPopupMinWidth;
+            } else {
+                /*
+                 * Firefox3 has its own way of doing rendering so we need to
+                 * specify the width for the TextField to make sure it actually
+                 * is rendered as wide as FF3 says it is
+                 */
+                tb.setWidth((tbWidth - getTextboxPadding()) + "px");
+            }
+            super.setWidth((w) + "px");
+            // Freeze the initial width, so that it won't change even if the
+            // icon size changes
+            width = w + "px";
+
+        } else {
+            /*
+             * When the width is specified we also want to explicitly specify
+             * widths for textbox and popupopener
+             */
+            setTextboxWidth(getMainWidth() - getComponentPadding());
+
+        }
+    }
+
+    private int getMainWidth() {
+        int componentWidth;
+        if (BrowserInfo.get().isIE6()) {
+            // Required in IE when textfield is wider than this.width
+            DOM.setStyleAttribute(getElement(), "overflow", "hidden");
+            componentWidth = getOffsetWidth();
+            DOM.setStyleAttribute(getElement(), "overflow", "");
+        } else {
+            componentWidth = getOffsetWidth();
+        }
+        return componentWidth;
+    }
+
+    private void setTextboxWidth(int componentWidth) {
+        int padding = getTextboxPadding();
+        int popupOpenerWidth = Util.getRequiredWidth(popupOpener);
+        int iconWidth = Util.getRequiredWidth(selectedItemIcon);
+        int textboxWidth = componentWidth - padding - popupOpenerWidth
+                - iconWidth;
+        if (textboxWidth < 0) {
+            textboxWidth = 0;
+        }
+        tb.setWidth(textboxWidth + "px");
+    }
+
+    private int getTextboxPadding() {
+        if (textboxPadding < 0) {
+            textboxPadding = Util.measureHorizontalPaddingAndBorder(tb
+                    .getElement(), 4);
+        }
+        return textboxPadding;
+    }
+
+    private int getComponentPadding() {
+        if (componentPadding < 0) {
+            componentPadding = Util.measureHorizontalPaddingAndBorder(
+                    getElement(), 3);
+        }
+        return componentPadding;
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VForm.java b/src/com/vaadin/terminal/gwt/client/ui/VForm.java
new file mode 100644 (file)
index 0000000..05e2358
--- /dev/null
@@ -0,0 +1,288 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Set;\r
+\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.Element;\r
+import com.google.gwt.user.client.ui.ComplexPanel;\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.Container;\r
+import com.vaadin.terminal.gwt.client.VErrorMessage;\r
+import com.vaadin.terminal.gwt.client.Paintable;\r
+import com.vaadin.terminal.gwt.client.RenderInformation;\r
+import com.vaadin.terminal.gwt.client.RenderSpace;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+import com.vaadin.terminal.gwt.client.Util;\r
+\r
+public class VForm extends ComplexPanel implements Container {\r
+\r
+    private String height = "";\r
+\r
+    private String width = "";\r
+\r
+    public static final String CLASSNAME = "i-form";\r
+\r
+    private Container lo;\r
+    private Element legend = DOM.createLegend();\r
+    private Element caption = DOM.createSpan();\r
+    private Element errorIndicatorElement = DOM.createDiv();\r
+    private Element desc = DOM.createDiv();\r
+    private Icon icon;\r
+    private VErrorMessage errorMessage = new VErrorMessage();\r
+\r
+    private Element fieldContainer = DOM.createDiv();\r
+\r
+    private Element footerContainer = DOM.createDiv();\r
+\r
+    private Element fieldSet = DOM.createFieldSet();\r
+\r
+    private Container footer;\r
+\r
+    private ApplicationConnection client;\r
+\r
+    private RenderInformation renderInformation = new RenderInformation();\r
+\r
+    private int borderPaddingHorizontal;\r
+\r
+    private int borderPaddingVertical;\r
+\r
+    private boolean rendering = false;\r
+\r
+    public VForm() {\r
+        setElement(DOM.createDiv());\r
+        DOM.appendChild(getElement(), fieldSet);\r
+        setStyleName(CLASSNAME);\r
+        DOM.appendChild(fieldSet, legend);\r
+        DOM.appendChild(legend, caption);\r
+        DOM.setElementProperty(errorIndicatorElement, "className",\r
+                "i-errorindicator");\r
+        DOM.setStyleAttribute(errorIndicatorElement, "display", "none");\r
+        DOM.setInnerText(errorIndicatorElement, " "); // needed for IE\r
+        DOM.setElementProperty(desc, "className", "i-form-description");\r
+        DOM.appendChild(fieldSet, desc);\r
+        DOM.appendChild(fieldSet, fieldContainer);\r
+        errorMessage.setVisible(false);\r
+        errorMessage.setStyleName(CLASSNAME + "-errormessage");\r
+        DOM.appendChild(fieldSet, errorMessage.getElement());\r
+        DOM.appendChild(fieldSet, footerContainer);\r
+    }\r
+\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        rendering = true;\r
+        boolean measure = false;\r
+        if (this.client == null) {\r
+            this.client = client;\r
+            measure = true;\r
+        }\r
+\r
+        if (client.updateComponent(this, uidl, false)) {\r
+            rendering = false;\r
+            return;\r
+        }\r
+\r
+        if (measure) {\r
+            // Measure the border when the style names have been set\r
+            borderPaddingVertical = getOffsetHeight();\r
+            int ow = getOffsetWidth();\r
+            int dow = desc.getOffsetWidth();\r
+            borderPaddingHorizontal = ow - dow;\r
+        }\r
+\r
+        boolean legendEmpty = true;\r
+        if (uidl.hasAttribute("caption")) {\r
+            DOM.setInnerText(caption, uidl.getStringAttribute("caption"));\r
+            legendEmpty = false;\r
+        } else {\r
+            DOM.setInnerText(caption, "");\r
+        }\r
+        if (uidl.hasAttribute("icon")) {\r
+            if (icon == null) {\r
+                icon = new Icon(client);\r
+                DOM.insertChild(legend, icon.getElement(), 0);\r
+            }\r
+            icon.setUri(uidl.getStringAttribute("icon"));\r
+            legendEmpty = false;\r
+        } else {\r
+            if (icon != null) {\r
+                DOM.removeChild(legend, icon.getElement());\r
+            }\r
+        }\r
+        if (legendEmpty) {\r
+            DOM.setStyleAttribute(legend, "display", "none");\r
+        } else {\r
+            DOM.setStyleAttribute(legend, "display", "");\r
+        }\r
+\r
+        if (uidl.hasAttribute("error")) {\r
+            final UIDL errorUidl = uidl.getErrors();\r
+            errorMessage.updateFromUIDL(errorUidl);\r
+            errorMessage.setVisible(true);\r
+\r
+        } else {\r
+            errorMessage.setVisible(false);\r
+        }\r
+\r
+        if (uidl.hasAttribute("description")) {\r
+            DOM.setInnerHTML(desc, uidl.getStringAttribute("description"));\r
+        } else {\r
+            DOM.setInnerHTML(desc, "");\r
+        }\r
+\r
+        updateSize();\r
+        // TODO Check if this is needed\r
+        client.runDescendentsLayout(this);\r
+\r
+        final UIDL layoutUidl = uidl.getChildUIDL(0);\r
+        Container newLo = (Container) client.getPaintable(layoutUidl);\r
+        if (lo == null) {\r
+            lo = newLo;\r
+            add((Widget) lo, fieldContainer);\r
+        } else if (lo != newLo) {\r
+            client.unregisterPaintable(lo);\r
+            remove((Widget) lo);\r
+            lo = newLo;\r
+            add((Widget) lo, fieldContainer);\r
+        }\r
+        lo.updateFromUIDL(layoutUidl, client);\r
+\r
+        if (uidl.getChildCount() > 1) {\r
+            // render footer\r
+            Container newFooter = (Container) client.getPaintable(uidl\r
+                    .getChildUIDL(1));\r
+            if (footer == null) {\r
+                add((Widget) newFooter, footerContainer);\r
+                footer = newFooter;\r
+            } else if (newFooter != footer) {\r
+                remove((Widget) footer);\r
+                client.unregisterPaintable(footer);\r
+                add((Widget) newFooter, footerContainer);\r
+            }\r
+            footer = newFooter;\r
+            footer.updateFromUIDL(uidl.getChildUIDL(1), client);\r
+        } else {\r
+            if (footer != null) {\r
+                remove((Widget) footer);\r
+                client.unregisterPaintable(footer);\r
+            }\r
+        }\r
+\r
+        rendering = false;\r
+    }\r
+\r
+    public void updateSize() {\r
+\r
+        renderInformation.updateSize(getElement());\r
+\r
+        renderInformation.setContentAreaHeight(renderInformation\r
+                .getRenderedSize().getHeight()\r
+                - borderPaddingVertical);\r
+        if (BrowserInfo.get().isIE6()) {\r
+            getElement().getStyle().setProperty("overflow", "hidden");\r
+        }\r
+        renderInformation.setContentAreaWidth(renderInformation\r
+                .getRenderedSize().getWidth()\r
+                - borderPaddingHorizontal);\r
+    }\r
+\r
+    public RenderSpace getAllocatedSpace(Widget child) {\r
+        if (child == lo) {\r
+            int hPixels = 0;\r
+            if (!"".equals(height)) {\r
+                hPixels = getOffsetHeight();\r
+                hPixels -= borderPaddingVertical;\r
+                hPixels -= footerContainer.getOffsetHeight();\r
+                hPixels -= errorMessage.getOffsetHeight();\r
+                hPixels -= desc.getOffsetHeight();\r
+\r
+            }\r
+\r
+            return new RenderSpace(renderInformation.getContentAreaSize()\r
+                    .getWidth(), hPixels);\r
+        } else if (child == footer) {\r
+            return new RenderSpace(footerContainer.getOffsetWidth(), 0);\r
+        } else {\r
+            ApplicationConnection.getConsole().error(\r
+                    "Invalid child requested RenderSpace information");\r
+            return null;\r
+        }\r
+    }\r
+\r
+    public boolean hasChildComponent(Widget component) {\r
+        return component != null && (component == lo || component == footer);\r
+    }\r
+\r
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {\r
+        if (!hasChildComponent(oldComponent)) {\r
+            throw new IllegalArgumentException(\r
+                    "Old component is not inside this Container");\r
+        }\r
+        remove(oldComponent);\r
+        if (oldComponent == lo) {\r
+            lo = (Container) newComponent;\r
+            add((Widget) lo, fieldContainer);\r
+        } else {\r
+            footer = (Container) newComponent;\r
+            add((Widget) footer, footerContainer);\r
+        }\r
+\r
+    }\r
+\r
+    public boolean requestLayout(Set<Paintable> child) {\r
+\r
+        if (height != null && width != null) {\r
+            /*\r
+             * If the height and width has been specified the child components\r
+             * cannot make the size of the layout change\r
+             */\r
+\r
+            return true;\r
+        }\r
+\r
+        if (renderInformation.updateSize(getElement())) {\r
+            return false;\r
+        } else {\r
+            return true;\r
+        }\r
+\r
+    }\r
+\r
+    public void updateCaption(Paintable component, UIDL uidl) {\r
+        // NOP form don't render caption for neither field layout nor footer\r
+        // layout\r
+    }\r
+\r
+    @Override\r
+    public void setHeight(String height) {\r
+        if (this.height.equals(height)) {\r
+            return;\r
+        }\r
+\r
+        this.height = height;\r
+        super.setHeight(height);\r
+\r
+        updateSize();\r
+    }\r
+\r
+    @Override\r
+    public void setWidth(String width) {\r
+        if (Util.equals(this.width, width)) {\r
+            return;\r
+        }\r
+\r
+        this.width = width;\r
+        super.setWidth(width);\r
+\r
+        updateSize();\r
+\r
+        if (!rendering && height.equals("")) {\r
+            // Width might affect height\r
+            Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);\r
+        }\r
+    }\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VFormLayout.java
new file mode 100644 (file)
index 0000000..4ffc67b
--- /dev/null
@@ -0,0 +1,464 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.StyleConstants;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+/**
+ * Two col Layout that places caption on left col and field on right col
+ */
+public class VFormLayout extends SimplePanel implements Container {
+
+    private final static String CLASSNAME = "i-formlayout";
+
+    private ApplicationConnection client;
+    private VFormLayoutTable table;
+
+    private String width = "";
+    private String height = "";
+
+    private boolean rendering = false;
+
+    public VFormLayout() {
+        super();
+        setStylePrimaryName(CLASSNAME);
+        table = new VFormLayoutTable();
+        setWidget(table);
+    }
+
+    public class VFormLayoutTable extends FlexTable {
+
+        private static final int COLUMN_CAPTION = 0;
+        private static final int COLUMN_ERRORFLAG = 1;
+        private static final int COLUMN_WIDGET = 2;
+
+        private HashMap<Paintable, Caption> componentToCaption = new HashMap<Paintable, Caption>();
+        private HashMap<Paintable, ErrorFlag> componentToError = new HashMap<Paintable, ErrorFlag>();
+
+        public VFormLayoutTable() {
+            DOM.setElementProperty(getElement(), "cellPadding", "0");
+            DOM.setElementProperty(getElement(), "cellSpacing", "0");
+        }
+
+        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+            final VMarginInfo margins = new VMarginInfo(uidl
+                    .getIntAttribute("margins"));
+
+            Element margin = getElement();
+            setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_TOP,
+                    margins.hasTop());
+            setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT,
+                    margins.hasRight());
+            setStyleName(margin,
+                    CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM, margins
+                            .hasBottom());
+            setStyleName(margin, CLASSNAME + "-" + StyleConstants.MARGIN_LEFT,
+                    margins.hasLeft());
+
+            setStyleName(margin, CLASSNAME + "-" + "spacing", uidl
+                    .hasAttribute("spacing"));
+
+            int i = 0;
+            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);
+                if (caption == null) {
+                    caption = new Caption(p, client);
+                    componentToCaption.put(p, caption);
+                }
+                ErrorFlag error = componentToError.get(p);
+                if (error == null) {
+                    error = new ErrorFlag();
+                    componentToError.put(p, 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);
+                }
+                getCellFormatter().setStyleName(i, COLUMN_WIDGET,
+                        CLASSNAME + "-contentcell");
+                getCellFormatter().setStyleName(i, COLUMN_CAPTION,
+                        CLASSNAME + "-captioncell");
+                setWidget(i, COLUMN_CAPTION, caption);
+
+                setContentWidth(i);
+
+                getCellFormatter().setStyleName(i, COLUMN_ERRORFLAG,
+                        CLASSNAME + "-errorcell");
+                setWidget(i, COLUMN_ERRORFLAG, error);
+
+                p.updateFromUIDL(childUidl, client);
+
+                String rowstyles = CLASSNAME + "-row";
+                if (i == 0) {
+                    rowstyles += " " + CLASSNAME + "-firstrow";
+                }
+                if (!it.hasNext()) {
+                    rowstyles += " " + CLASSNAME + "-lastrow";
+                }
+
+                getRowFormatter().setStyleName(i, rowstyles);
+
+            }
+
+            while (getRowCount() > i) {
+                final Paintable p = (Paintable) getWidget(i, COLUMN_WIDGET);
+                client.unregisterPaintable(p);
+                componentToCaption.remove(p);
+                removeRow(i);
+            }
+
+            /*
+             * Must update relative sized fields last when it is clear how much
+             * space they are allowed to use
+             */
+            for (Paintable p : componentToCaption.keySet()) {
+                client.handleComponentRelativeSize((Widget) p);
+            }
+        }
+
+        public void setContentWidths() {
+            for (int row = 0; row < getRowCount(); row++) {
+                setContentWidth(row);
+            }
+        }
+
+        private void setContentWidth(int row) {
+            String width = "";
+            if (!isDynamicWidth()) {
+                width = "100%";
+            }
+            getCellFormatter().setWidth(row, COLUMN_WIDGET, width);
+        }
+
+        public void replaceChildComponent(Widget oldComponent,
+                Widget newComponent) {
+            int i;
+            for (i = 0; i < getRowCount(); i++) {
+                Widget candidate = getWidget(i, COLUMN_WIDGET);
+                if (oldComponent == candidate) {
+                    final Caption newCap = new Caption(
+                            (Paintable) newComponent, client);
+                    componentToCaption.put((Paintable) newComponent, newCap);
+                    ErrorFlag error = componentToError.get(newComponent);
+                    if (error == null) {
+                        error = new ErrorFlag();
+                        componentToError.put((Paintable) newComponent, error);
+                    }
+
+                    setWidget(i, COLUMN_CAPTION, newCap);
+                    setWidget(i, COLUMN_ERRORFLAG, error);
+                    setWidget(i, COLUMN_WIDGET, newComponent);
+                    break;
+                }
+            }
+
+        }
+
+        public boolean hasChildComponent(Widget component) {
+            return componentToCaption.containsKey(component);
+        }
+
+        public void updateCaption(Paintable component, UIDL uidl) {
+            final Caption c = componentToCaption.get(component);
+            if (c != null) {
+                c.updateCaption(uidl);
+            }
+            final ErrorFlag e = componentToError.get(component);
+            if (e != null) {
+                e.updateFromUIDL(uidl, component);
+            }
+
+        }
+
+        public int getAllocatedWidth(Widget child, int availableWidth) {
+            Caption caption = componentToCaption.get(child);
+            ErrorFlag error = componentToError.get(child);
+            int width = availableWidth;
+
+            if (caption != null) {
+                width -= DOM.getParent(caption.getElement()).getOffsetWidth();
+            }
+            if (error != null) {
+                width -= DOM.getParent(error.getElement()).getOffsetWidth();
+            }
+
+            return width;
+        }
+
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+
+        this.client = client;
+
+        if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
+            return;
+        }
+
+        table.updateFromUIDL(uidl, client);
+
+        rendering = false;
+    }
+
+    public boolean isDynamicWidth() {
+        return width.equals("");
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        return table.hasChildComponent(component);
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        table.replaceChildComponent(oldComponent, newComponent);
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        table.updateCaption(component, uidl);
+    }
+
+    public class Caption extends HTML {
+
+        public static final String CLASSNAME = "i-caption";
+
+        private final Paintable owner;
+
+        private Element requiredFieldIndicator;
+
+        private Icon icon;
+
+        private Element captionText;
+
+        private final ApplicationConnection client;
+
+        /**
+         * 
+         * @param component
+         *            optional owner of caption. If not set, getOwner will
+         *            return null
+         * @param client
+         */
+        public Caption(Paintable component, ApplicationConnection client) {
+            super();
+            this.client = client;
+            owner = component;
+            setStyleName(CLASSNAME);
+            sinkEvents(VTooltip.TOOLTIP_EVENTS);
+        }
+
+        public void updateCaption(UIDL uidl) {
+            setVisible(!uidl.getBooleanAttribute("invisible"));
+
+            setStyleName(getElement(), "i-disabled", uidl
+                    .hasAttribute("disabled"));
+
+            boolean isEmpty = true;
+
+            if (uidl.hasAttribute("icon")) {
+                if (icon == null) {
+                    icon = new Icon(client);
+
+                    DOM.insertChild(getElement(), icon.getElement(), 0);
+                }
+                icon.setUri(uidl.getStringAttribute("icon"));
+                isEmpty = false;
+            } else {
+                if (icon != null) {
+                    DOM.removeChild(getElement(), icon.getElement());
+                    icon = null;
+                }
+
+            }
+
+            if (uidl.hasAttribute("caption")) {
+                if (captionText == null) {
+                    captionText = DOM.createSpan();
+                    DOM.insertChild(getElement(), captionText, icon == null ? 0
+                            : 1);
+                }
+                String c = uidl.getStringAttribute("caption");
+                if (c == null) {
+                    c = "";
+                } else {
+                    isEmpty = false;
+                }
+                DOM.setInnerText(captionText, c);
+            } else {
+                // TODO should span also be removed
+            }
+
+            if (uidl.hasAttribute("description")) {
+                if (captionText != null) {
+                    addStyleDependentName("hasdescription");
+                } else {
+                    removeStyleDependentName("hasdescription");
+                }
+            }
+
+            if (uidl.getBooleanAttribute("required")) {
+                if (requiredFieldIndicator == null) {
+                    requiredFieldIndicator = DOM.createSpan();
+                    DOM.setInnerText(requiredFieldIndicator, "*");
+                    DOM.setElementProperty(requiredFieldIndicator, "className",
+                            "i-required-field-indicator");
+                    DOM.appendChild(getElement(), requiredFieldIndicator);
+                }
+            } else {
+                if (requiredFieldIndicator != null) {
+                    DOM.removeChild(getElement(), requiredFieldIndicator);
+                    requiredFieldIndicator = null;
+                }
+            }
+
+            // Workaround for IE weirdness, sometimes returns bad height in some
+            // circumstances when Caption is empty. See #1444
+            // IE7 bugs more often. I wonder what happens when IE8 arrives...
+            if (Util.isIE()) {
+                if (isEmpty) {
+                    setHeight("0px");
+                    DOM.setStyleAttribute(getElement(), "overflow", "hidden");
+                } else {
+                    setHeight("");
+                    DOM.setStyleAttribute(getElement(), "overflow", "");
+                }
+
+            }
+
+        }
+
+        /**
+         * Returns Paintable for which this Caption belongs to.
+         * 
+         * @return owner Widget
+         */
+        public Paintable getOwner() {
+            return owner;
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (client != null) {
+                client.handleTooltipEvent(event, owner);
+            }
+        }
+    }
+
+    private class ErrorFlag extends HTML {
+        private static final String CLASSNAME = VFormLayout.CLASSNAME
+                + "-error-indicator";
+        Element errorIndicatorElement;
+        private Paintable owner;
+
+        public ErrorFlag() {
+            setStyleName(CLASSNAME);
+            sinkEvents(VTooltip.TOOLTIP_EVENTS);
+        }
+
+        public void updateFromUIDL(UIDL uidl, Paintable component) {
+            owner = component;
+            if (uidl.hasAttribute("error")
+                    && !uidl.getBooleanAttribute("hideErrors")) {
+                if (errorIndicatorElement == null) {
+                    errorIndicatorElement = DOM.createDiv();
+                    DOM.setInnerHTML(errorIndicatorElement, "&nbsp;");
+                    DOM.setElementProperty(errorIndicatorElement, "className",
+                            "i-errorindicator");
+                    DOM.appendChild(getElement(), errorIndicatorElement);
+                }
+
+            } else if (errorIndicatorElement != null) {
+                DOM.removeChild(getElement(), errorIndicatorElement);
+                errorIndicatorElement = null;
+            }
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (owner != null) {
+                client.handleTooltipEvent(event, owner);
+            }
+        }
+
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        if (height.equals("") || width.equals("")) {
+            // A dynamic size might change due to children changes
+            return false;
+        }
+
+        return true;
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        int width = 0;
+        int height = 0;
+
+        if (!this.width.equals("")) {
+            int availableWidth = getOffsetWidth();
+            width = table.getAllocatedWidth(child, availableWidth);
+        }
+
+        return new RenderSpace(width, height, false);
+    }
+
+    @Override
+    public void setHeight(String height) {
+        if (this.height.equals(height)) {
+            return;
+        }
+
+        this.height = height;
+        super.setHeight(height);
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (this.width.equals(width)) {
+            return;
+        }
+
+        this.width = width;
+        super.setWidth(width);
+
+        if (!rendering) {
+            table.setContentWidths();
+            if (height.equals("")) {
+                // Width might affect height
+                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
+            }
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VGridLayout.java
new file mode 100644 (file)
index 0000000..ebaad51
--- /dev/null
@@ -0,0 +1,1018 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.AbsolutePanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.StyleConstants;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;
+import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;
+
+public class VGridLayout extends SimplePanel implements Paintable, Container {
+
+    public static final String CLASSNAME = "i-gridlayout";
+
+    private DivElement margin = Document.get().createDivElement();
+
+    private final AbsolutePanel canvas = new AbsolutePanel();
+
+    private ApplicationConnection client;
+
+    protected HashMap<Widget, ChildComponentContainer> widgetToComponentContainer = new HashMap<Widget, ChildComponentContainer>();
+
+    private HashMap<Paintable, Cell> paintableToCell = new HashMap<Paintable, Cell>();
+
+    private int spacingPixelsHorizontal;
+    private int spacingPixelsVertical;
+
+    private int[] columnWidths;
+    private int[] rowHeights;
+
+    private String height;
+
+    private String width;
+
+    private int[] colExpandRatioArray;
+
+    private int[] rowExpandRatioArray;
+
+    private int[] minColumnWidths;
+
+    private int[] minRowHeights;
+
+    private boolean rendering;
+
+    private HashMap<Widget, ChildComponentContainer> nonRenderedWidgets;
+
+    private boolean sizeChangedDuringRendering = false;
+
+    public VGridLayout() {
+        super();
+        getElement().appendChild(margin);
+        setStyleName(CLASSNAME);
+        setWidget(canvas);
+    }
+
+    @Override
+    protected Element getContainerElement() {
+        return margin.cast();
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+        this.client = client;
+
+        if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
+            return;
+        }
+
+        boolean mightToggleVScrollBar = "".equals(height) && !"".equals(width);
+        boolean mightToggleHScrollBar = "".equals(width) && !"".equals(height);
+        int wBeforeRender = 0;
+        int hBeforeRender = 0;
+        if (mightToggleHScrollBar || mightToggleVScrollBar) {
+            wBeforeRender = canvas.getOffsetWidth();
+            hBeforeRender = getOffsetHeight();
+        }
+        canvas.setWidth("0px");
+
+        handleMargins(uidl);
+        detectSpacing(uidl);
+
+        int cols = uidl.getIntAttribute("w");
+        int rows = uidl.getIntAttribute("h");
+
+        columnWidths = new int[cols];
+        rowHeights = new int[rows];
+
+        if (cells == null) {
+            cells = new Cell[cols][rows];
+        } else if (cells.length != cols || cells[0].length != rows) {
+            Cell[][] newCells = new Cell[cols][rows];
+            for (int i = 0; i < cells.length; i++) {
+                for (int j = 0; j < cells[i].length; j++) {
+                    if (i < cols && j < rows) {
+                        newCells[i][j] = cells[i][j];
+                    }
+                }
+            }
+            cells = newCells;
+        }
+
+        nonRenderedWidgets = (HashMap<Widget, ChildComponentContainer>) widgetToComponentContainer
+                .clone();
+
+        final int[] alignments = uidl.getIntArrayAttribute("alignments");
+        int alignmentIndex = 0;
+
+        LinkedList<Cell> pendingCells = new LinkedList<Cell>();
+
+        LinkedList<Cell> relativeHeighted = new LinkedList<Cell>();
+
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            final UIDL r = (UIDL) i.next();
+            if ("gr".equals(r.getTag())) {
+                for (final Iterator j = r.getChildIterator(); j.hasNext();) {
+                    final UIDL c = (UIDL) j.next();
+                    if ("gc".equals(c.getTag())) {
+                        Cell cell = getCell(c);
+                        if (cell.hasContent()) {
+                            boolean rendered = cell.renderIfNoRelativeWidth();
+                            cell.alignment = alignments[alignmentIndex++];
+                            if (!rendered) {
+                                pendingCells.add(cell);
+                            }
+
+                            if (cell.colspan > 1) {
+                                storeColSpannedCell(cell);
+                            } else if (rendered) {
+                                // strore non-colspanned widths to columnWidth
+                                // array
+                                if (columnWidths[cell.col] < cell.getWidth()) {
+                                    columnWidths[cell.col] = cell.getWidth();
+                                }
+                            }
+                            if (cell.hasRelativeHeight()) {
+                                relativeHeighted.add(cell);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        distributeColSpanWidths();
+        colExpandRatioArray = uidl.getIntArrayAttribute("colExpand");
+        rowExpandRatioArray = uidl.getIntArrayAttribute("rowExpand");
+
+        minColumnWidths = cloneArray(columnWidths);
+        expandColumns();
+
+        renderRemainingComponentsWithNoRelativeHeight(pendingCells);
+
+        detectRowHeights();
+
+        expandRows();
+
+        renderRemainingComponents(pendingCells);
+
+        for (Cell cell : relativeHeighted) {
+            Widget widget2 = cell.cc.getWidget();
+            client.handleComponentRelativeSize(widget2);
+            cell.cc.updateWidgetSize();
+        }
+
+        layoutCells();
+
+        // clean non rendered components
+        for (Widget w : nonRenderedWidgets.keySet()) {
+            ChildComponentContainer childComponentContainer = widgetToComponentContainer
+                    .get(w);
+            paintableToCell.remove(w);
+            widgetToComponentContainer.remove(w);
+            childComponentContainer.removeFromParent();
+            client.unregisterPaintable((Paintable) w);
+        }
+        nonRenderedWidgets = null;
+
+        rendering = false;
+        sizeChangedDuringRendering = false;
+
+        boolean needsRelativeSizeCheck = false;
+
+        if (mightToggleHScrollBar && wBeforeRender != canvas.getOffsetWidth()) {
+            needsRelativeSizeCheck = true;
+        }
+        if (mightToggleVScrollBar && hBeforeRender != getOffsetHeight()) {
+            needsRelativeSizeCheck = true;
+        }
+        if (needsRelativeSizeCheck) {
+            client.handleComponentRelativeSize(this);
+        }
+    }
+
+    private static int[] cloneArray(int[] toBeCloned) {
+        int[] clone = new int[toBeCloned.length];
+        for (int i = 0; i < clone.length; i++) {
+            clone[i] = toBeCloned[i] * 1;
+        }
+        return clone;
+    }
+
+    private void expandRows() {
+        if (!"".equals(height)) {
+            int usedSpace = minRowHeights[0];
+            for (int i = 1; i < minRowHeights.length; i++) {
+                usedSpace += spacingPixelsVertical + minRowHeights[i];
+            }
+            int availableSpace = getOffsetHeight() - marginTopAndBottom;
+            int excessSpace = availableSpace - usedSpace;
+            int distributed = 0;
+            if (excessSpace > 0) {
+                for (int i = 0; i < rowHeights.length; i++) {
+                    int ew = excessSpace * rowExpandRatioArray[i] / 1000;
+                    rowHeights[i] = minRowHeights[i] + ew;
+                    distributed += ew;
+                }
+                excessSpace -= distributed;
+                int c = 0;
+                while (excessSpace > 0) {
+                    rowHeights[c % rowHeights.length]++;
+                    excessSpace--;
+                    c++;
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        if (!height.equals(this.height)) {
+            this.height = height;
+            if (rendering) {
+                sizeChangedDuringRendering = true;
+            } else {
+                expandRows();
+                layoutCells();
+                for (Paintable c : paintableToCell.keySet()) {
+                    client.handleComponentRelativeSize((Widget) c);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        super.setWidth(width);
+        if (!width.equals(this.width)) {
+            this.width = width;
+            if (rendering) {
+                sizeChangedDuringRendering = true;
+            } else {
+                int[] oldWidths = cloneArray(columnWidths);
+                expandColumns();
+                boolean heightChanged = false;
+                HashSet<Integer> dirtyRows = null;
+                for (int i = 0; i < oldWidths.length; i++) {
+                    if (columnWidths[i] != oldWidths[i]) {
+                        Cell[] column = cells[i];
+                        for (int j = 0; j < column.length; j++) {
+                            Cell c = column[j];
+                            if (c != null && c.cc != null
+                                    && c.widthCanAffectHeight()) {
+                                c.cc.setContainerSize(c.getAvailableWidth(), c
+                                        .getAvailableHeight());
+                                client.handleComponentRelativeSize(c.cc
+                                        .getWidget());
+                                c.cc.updateWidgetSize();
+                                int newHeight = c.getHeight();
+                                if (columnWidths[i] < oldWidths[i]
+                                        && newHeight > minRowHeights[j]) {
+                                    minRowHeights[j] = newHeight;
+                                    if (newHeight > rowHeights[j]) {
+                                        rowHeights[j] = newHeight;
+                                        heightChanged = true;
+                                    }
+                                } else if (newHeight < minRowHeights[j]) {
+                                    // need to recalculate new minimum height
+                                    // for this row
+                                    if (dirtyRows == null) {
+                                        dirtyRows = new HashSet<Integer>();
+                                    }
+                                    dirtyRows.add(j);
+                                }
+                            }
+                        }
+                    }
+                }
+                if (dirtyRows != null) {
+                    /* flag indicating that there is a potential row shrinking */
+                    boolean rowMayShrink = false;
+                    for (Integer rowIndex : dirtyRows) {
+                        int oldMinimum = minRowHeights[rowIndex];
+                        int newMinimum = 0;
+                        for (int colIndex = 0; colIndex < columnWidths.length; colIndex++) {
+                            Cell cell = cells[colIndex][rowIndex];
+                            if (cell != null && !cell.hasRelativeHeight()
+                                    && cell.getHeight() > newMinimum) {
+                                newMinimum = cell.getHeight();
+                            }
+                        }
+                        if (newMinimum < oldMinimum) {
+                            minRowHeights[rowIndex] = rowHeights[rowIndex] = newMinimum;
+                            rowMayShrink = true;
+                        }
+                    }
+                    if (rowMayShrink) {
+                        distributeRowSpanHeights();
+                        minRowHeights = cloneArray(rowHeights);
+                        heightChanged = true;
+                    }
+
+                }
+                layoutCells();
+                for (Paintable c : paintableToCell.keySet()) {
+                    client.handleComponentRelativeSize((Widget) c);
+                }
+                if (heightChanged && "".equals(height)) {
+                    Util.notifyParentOfSizeChange(this, false);
+                }
+            }
+        }
+    }
+
+    private void expandColumns() {
+        if (!"".equals(width)) {
+            int usedSpace = minColumnWidths[0];
+            for (int i = 1; i < minColumnWidths.length; i++) {
+                usedSpace += spacingPixelsHorizontal + minColumnWidths[i];
+            }
+            canvas.setWidth("");
+            int availableSpace = canvas.getOffsetWidth();
+            int excessSpace = availableSpace - usedSpace;
+            int distributed = 0;
+            if (excessSpace > 0) {
+                for (int i = 0; i < columnWidths.length; i++) {
+                    int ew = excessSpace * colExpandRatioArray[i] / 1000;
+                    columnWidths[i] = minColumnWidths[i] + ew;
+                    distributed += ew;
+                }
+                excessSpace -= distributed;
+                int c = 0;
+                while (excessSpace > 0) {
+                    columnWidths[c % columnWidths.length]++;
+                    excessSpace--;
+                    c++;
+                }
+            }
+        }
+    }
+
+    private void layoutCells() {
+        int x = 0;
+        int y = 0;
+        for (int i = 0; i < cells.length; i++) {
+            y = 0;
+            for (int j = 0; j < cells[i].length; j++) {
+                Cell cell = cells[i][j];
+                if (cell != null) {
+                    cell.layout(x, y);
+                }
+                y += rowHeights[j] + spacingPixelsVertical;
+            }
+            x += columnWidths[i] + spacingPixelsHorizontal;
+        }
+
+        if ("".equals(width)) {
+            canvas.setWidth((x - spacingPixelsHorizontal) + "px");
+        } else {
+            // main element defines width
+            canvas.setWidth("");
+        }
+        int canvasHeight;
+        if ("".equals(height)) {
+            canvasHeight = y - spacingPixelsVertical;
+        } else {
+            canvasHeight = getOffsetHeight() - marginTopAndBottom;
+        }
+        canvas.setHeight(canvasHeight + "px");
+    }
+
+    private void renderRemainingComponents(LinkedList<Cell> pendingCells) {
+        for (Cell cell : pendingCells) {
+            cell.render();
+        }
+    }
+
+    private void detectRowHeights() {
+
+        // collect min rowheight from non-rowspanned cells
+        for (int i = 0; i < cells.length; i++) {
+            for (int j = 0; j < cells[i].length; j++) {
+                Cell cell = cells[i][j];
+                if (cell != null) {
+                    /*
+                     * Setting fixing container width may in some situations
+                     * affect height. Example: Label with wrapping text without
+                     * or with relative width.
+                     */
+                    if (cell.cc != null && cell.widthCanAffectHeight()) {
+                        cell.cc.setWidth(cell.getAvailableWidth() + "px");
+                        cell.cc.updateWidgetSize();
+                    }
+                    if (cell.rowspan == 1) {
+                        if (!cell.hasRelativeHeight()
+                                && rowHeights[j] < cell.getHeight()) {
+                            rowHeights[j] = cell.getHeight();
+                        }
+                    } else {
+                        storeRowSpannedCell(cell);
+                    }
+                }
+            }
+        }
+
+        distributeRowSpanHeights();
+
+        minRowHeights = cloneArray(rowHeights);
+    }
+
+    private void storeRowSpannedCell(Cell cell) {
+        SpanList l = null;
+        for (SpanList list : rowSpans) {
+            if (list.span < cell.rowspan) {
+                continue;
+            } else {
+                // insert before this
+                l = list;
+                break;
+            }
+        }
+        if (l == null) {
+            l = new SpanList(cell.rowspan);
+            rowSpans.add(l);
+        } else if (l.span != cell.rowspan) {
+            SpanList newL = new SpanList(cell.rowspan);
+            rowSpans.add(rowSpans.indexOf(l), newL);
+            l = newL;
+        }
+        l.cells.add(cell);
+    }
+
+    private void renderRemainingComponentsWithNoRelativeHeight(
+            LinkedList<Cell> pendingCells) {
+
+        for (Iterator iterator = pendingCells.iterator(); iterator.hasNext();) {
+            Cell cell = (Cell) iterator.next();
+            if (!cell.hasRelativeHeight()) {
+                cell.render();
+                iterator.remove();
+            }
+        }
+
+    }
+
+    /**
+     * Iterates colspanned cells, ensures cols have enough space to accommodate
+     * them
+     */
+    private void distributeColSpanWidths() {
+        for (SpanList list : colSpans) {
+            for (Cell cell : list.cells) {
+                int width = cell.getWidth();
+                int allocated = columnWidths[cell.col];
+                for (int i = 1; i < cell.colspan; i++) {
+                    allocated += spacingPixelsHorizontal
+                            + columnWidths[cell.col + i];
+                }
+                if (allocated < width) {
+                    // columnWidths needs to be expanded due colspanned cell
+                    int neededExtraSpace = width - allocated;
+                    int spaceForColunms = neededExtraSpace / cell.colspan;
+                    for (int i = 0; i < cell.colspan; i++) {
+                        int col = cell.col + i;
+                        columnWidths[col] += spaceForColunms;
+                        neededExtraSpace -= spaceForColunms;
+                    }
+                    if (neededExtraSpace > 0) {
+                        for (int i = 0; i < cell.colspan; i++) {
+                            int col = cell.col + i;
+                            columnWidths[col] += 1;
+                            neededExtraSpace -= 1;
+                            if (neededExtraSpace == 0) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Iterates rowspanned cells, ensures rows have enough space to accommodate
+     * them
+     */
+    private void distributeRowSpanHeights() {
+        for (SpanList list : rowSpans) {
+            for (Cell cell : list.cells) {
+                int height = cell.getHeight();
+                int allocated = rowHeights[cell.row];
+                for (int i = 1; i < cell.rowspan; i++) {
+                    allocated += spacingPixelsVertical
+                            + rowHeights[cell.row + i];
+                }
+                if (allocated < height) {
+                    // columnWidths needs to be expanded due colspanned cell
+                    int neededExtraSpace = height - allocated;
+                    int spaceForColunms = neededExtraSpace / cell.rowspan;
+                    for (int i = 0; i < cell.rowspan; i++) {
+                        int row = cell.row + i;
+                        rowHeights[row] += spaceForColunms;
+                        neededExtraSpace -= spaceForColunms;
+                    }
+                    if (neededExtraSpace > 0) {
+                        for (int i = 0; i < cell.rowspan; i++) {
+                            int row = cell.row + i;
+                            rowHeights[row] += 1;
+                            neededExtraSpace -= 1;
+                            if (neededExtraSpace == 0) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private LinkedList<SpanList> colSpans = new LinkedList<SpanList>();
+    private LinkedList<SpanList> rowSpans = new LinkedList<SpanList>();
+
+    private int marginTopAndBottom;
+
+    private class SpanList {
+        final int span;
+        List<Cell> cells = new LinkedList<Cell>();
+
+        public SpanList(int span) {
+            this.span = span;
+        }
+    }
+
+    private void storeColSpannedCell(Cell cell) {
+        SpanList l = null;
+        for (SpanList list : colSpans) {
+            if (list.span < cell.colspan) {
+                continue;
+            } else {
+                // insert before this
+                l = list;
+                break;
+            }
+        }
+        if (l == null) {
+            l = new SpanList(cell.colspan);
+            colSpans.add(l);
+        } else if (l.span != cell.colspan) {
+
+            SpanList newL = new SpanList(cell.colspan);
+            colSpans.add(colSpans.indexOf(l), newL);
+            l = newL;
+        }
+        l.cells.add(cell);
+    }
+
+    private void detectSpacing(UIDL uidl) {
+        DivElement spacingmeter = Document.get().createDivElement();
+        spacingmeter.setClassName(CLASSNAME + "-" + "spacing-"
+                + (uidl.getBooleanAttribute("spacing") ? "on" : "off"));
+        spacingmeter.getStyle().setProperty("width", "0");
+        spacingmeter.getStyle().setProperty("height", "0");
+        canvas.getElement().appendChild(spacingmeter);
+        spacingPixelsHorizontal = spacingmeter.getOffsetWidth();
+        spacingPixelsVertical = spacingmeter.getOffsetHeight();
+        canvas.getElement().removeChild(spacingmeter);
+    }
+
+    private void handleMargins(UIDL uidl) {
+        final VMarginInfo margins = new VMarginInfo(uidl
+                .getIntAttribute("margins"));
+
+        String styles = CLASSNAME + "-margin";
+        if (margins.hasTop()) {
+            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_TOP;
+        }
+        if (margins.hasRight()) {
+            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_RIGHT;
+        }
+        if (margins.hasBottom()) {
+            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_BOTTOM;
+        }
+        if (margins.hasLeft()) {
+            styles += " " + CLASSNAME + "-" + StyleConstants.MARGIN_LEFT;
+        }
+        margin.setClassName(styles);
+
+        marginTopAndBottom = margin.getOffsetHeight()
+                - canvas.getOffsetHeight();
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        return paintableToCell.containsKey(component);
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        ChildComponentContainer componentContainer = widgetToComponentContainer
+                .remove(oldComponent);
+        if (componentContainer == null) {
+            return;
+        }
+
+        componentContainer.setWidget(newComponent);
+        widgetToComponentContainer.put(newComponent, componentContainer);
+
+        paintableToCell.put((Paintable) newComponent, paintableToCell
+                .get(oldComponent));
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        ChildComponentContainer cc = widgetToComponentContainer.get(component);
+        if (cc != null) {
+            cc.updateCaption(uidl, client);
+        }
+        if (!rendering) {
+            // ensure rel size details are updated
+            paintableToCell.get(component).updateRelSizeStatus(uidl);
+        }
+    }
+
+    public boolean requestLayout(final Set<Paintable> changedChildren) {
+        boolean needsLayout = false;
+        boolean reDistributeColSpanWidths = false;
+        boolean reDistributeRowSpanHeights = false;
+        int offsetHeight = canvas.getOffsetHeight();
+        int offsetWidth = canvas.getOffsetWidth();
+        if ("".equals(width) || "".equals(height)) {
+            needsLayout = true;
+        }
+        ArrayList<Integer> dirtyColumns = new ArrayList<Integer>();
+        ArrayList<Integer> dirtyRows = new ArrayList<Integer>();
+        for (Paintable paintable : changedChildren) {
+
+            Cell cell = paintableToCell.get(paintable);
+            if (!cell.hasRelativeHeight() || !cell.hasRelativeWidth()) {
+                // cell sizes will only stay still if only relatively
+                // sized
+                // components
+                // check if changed child affects min col widths
+                cell.cc.setWidth("");
+                cell.cc.setHeight("");
+
+                cell.cc.updateWidgetSize();
+                int width = cell.getWidth();
+                int allocated = columnWidths[cell.col];
+                for (int i = 1; i < cell.colspan; i++) {
+                    allocated += spacingPixelsHorizontal
+                            + columnWidths[cell.col + i];
+                }
+                if (allocated < width) {
+                    needsLayout = true;
+                    if (cell.colspan == 1) {
+                        // do simple column width expansion
+                        columnWidths[cell.col] = minColumnWidths[cell.col] = width;
+                    } else {
+                        // mark that col span expansion is needed
+                        reDistributeColSpanWidths = true;
+                    }
+                } else if (allocated != width) {
+                    // size is smaller thant allocated, column might
+                    // shrink
+                    dirtyColumns.add(cell.col);
+                }
+
+                int height = cell.getHeight();
+
+                allocated = rowHeights[cell.row];
+                for (int i = 1; i < cell.rowspan; i++) {
+                    allocated += spacingPixelsVertical
+                            + rowHeights[cell.row + i];
+                }
+                if (allocated < height) {
+                    needsLayout = true;
+                    if (cell.rowspan == 1) {
+                        // do simple row expansion
+                        rowHeights[cell.row] = minRowHeights[cell.row] = height;
+                    } else {
+                        // mark that row span expansion is needed
+                        reDistributeRowSpanHeights = true;
+                    }
+                } else if (allocated != height) {
+                    // size is smaller than allocated, row might shrink
+                    dirtyRows.add(cell.row);
+                }
+            }
+        }
+
+        if (dirtyColumns.size() > 0) {
+            for (Integer colIndex : dirtyColumns) {
+                int colW = 0;
+                for (int i = 0; i < rowHeights.length; i++) {
+                    Cell cell = cells[colIndex][i];
+                    if (cell != null && cell.getChildUIDL() != null
+                            && !cell.hasRelativeWidth() && cell.colspan == 1) {
+                        int width = cell.getWidth();
+                        if (width > colW) {
+                            colW = width;
+                        }
+                    }
+                }
+                minColumnWidths[colIndex] = colW;
+            }
+            needsLayout = true;
+            // ensure colspanned columns have enough space
+            columnWidths = cloneArray(minColumnWidths);
+            distributeColSpanWidths();
+            reDistributeColSpanWidths = false;
+        }
+
+        if (reDistributeColSpanWidths) {
+            distributeColSpanWidths();
+        }
+
+        if (dirtyRows.size() > 0) {
+            needsLayout = true;
+            for (Integer rowIndex : dirtyRows) {
+                // recalculate min row height
+                int rowH = minRowHeights[rowIndex] = 0;
+                // loop all columns on row rowIndex
+                for (int i = 0; i < columnWidths.length; i++) {
+                    Cell cell = cells[i][rowIndex];
+                    if (cell != null && cell.getChildUIDL() != null
+                            && !cell.hasRelativeHeight() && cell.rowspan == 1) {
+                        int h = cell.getHeight();
+                        if (h > rowH) {
+                            rowH = h;
+                        }
+                    }
+                }
+                minRowHeights[rowIndex] = rowH;
+            }
+            // TODO could check only some row spans
+            rowHeights = cloneArray(minRowHeights);
+            distributeRowSpanHeights();
+            reDistributeRowSpanHeights = false;
+        }
+
+        if (reDistributeRowSpanHeights) {
+            distributeRowSpanHeights();
+        }
+
+        if (needsLayout) {
+            expandColumns();
+            expandRows();
+            layoutCells();
+            // loop all relative sized components and update their size
+            for (int i = 0; i < cells.length; i++) {
+                for (int j = 0; j < cells[i].length; j++) {
+                    Cell cell = cells[i][j];
+                    if (cell != null
+                            && cell.cc != null
+                            && (cell.hasRelativeHeight() || cell
+                                    .hasRelativeWidth())) {
+                        client.handleComponentRelativeSize(cell.cc.getWidget());
+                    }
+                }
+            }
+        }
+        if (canvas.getOffsetHeight() != offsetHeight
+                || canvas.getOffsetWidth() != offsetWidth) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        Cell cell = paintableToCell.get(child);
+        assert cell != null;
+        return cell.getAllocatedSpace();
+    }
+
+    private Cell[][] cells;
+
+    /**
+     * Private helper class.
+     */
+    private class Cell {
+        private boolean relHeight = false;
+        private boolean relWidth = false;
+        private boolean widthCanAffectHeight = false;
+
+        public Cell(UIDL c) {
+            row = c.getIntAttribute("y");
+            col = c.getIntAttribute("x");
+            setUidl(c);
+        }
+
+        public boolean widthCanAffectHeight() {
+            return widthCanAffectHeight;
+        }
+
+        public boolean hasRelativeHeight() {
+            return relHeight;
+        }
+
+        public RenderSpace getAllocatedSpace() {
+            return new RenderSpace(getAvailableWidth()
+                    - cc.getCaptionWidthAfterComponent(), getAvailableHeight()
+                    - cc.getCaptionHeightAboveComponent());
+        }
+
+        public boolean hasContent() {
+            return childUidl != null;
+        }
+
+        /**
+         * @return total of spanned cols
+         */
+        private int getAvailableWidth() {
+            int width = columnWidths[col];
+            for (int i = 1; i < colspan; i++) {
+                width += spacingPixelsHorizontal + columnWidths[col + i];
+            }
+            return width;
+        }
+
+        /**
+         * @return total of spanned rows
+         */
+        private int getAvailableHeight() {
+            int height = rowHeights[row];
+            for (int i = 1; i < rowspan; i++) {
+                height += spacingPixelsVertical + rowHeights[row + i];
+            }
+            return height;
+        }
+
+        public void layout(int x, int y) {
+            if (cc != null && cc.isAttached()) {
+                canvas.setWidgetPosition(cc, x, y);
+                cc.setContainerSize(getAvailableWidth(), getAvailableHeight());
+                cc.setAlignment(new AlignmentInfo(alignment));
+                cc.updateAlignments(getAvailableWidth(), getAvailableHeight());
+            }
+        }
+
+        public int getWidth() {
+            if (cc != null) {
+                int w = cc.getWidgetSize().getWidth()
+                        + cc.getCaptionWidthAfterComponent();
+                return w;
+            } else {
+                return 0;
+            }
+        }
+
+        public int getHeight() {
+            if (cc != null) {
+                return cc.getWidgetSize().getHeight()
+                        + cc.getCaptionHeightAboveComponent();
+            } else {
+                return 0;
+            }
+        }
+
+        public boolean renderIfNoRelativeWidth() {
+            if (childUidl == null) {
+                return false;
+            }
+            if (!hasRelativeWidth()) {
+                render();
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        protected boolean hasRelativeWidth() {
+            return relWidth;
+        }
+
+        protected void render() {
+            assert childUidl != null;
+
+            Paintable paintable = client.getPaintable(childUidl);
+            assert paintable != null;
+            if (cc == null || cc.getWidget() != paintable) {
+                if (widgetToComponentContainer.containsKey(paintable)) {
+                    cc = widgetToComponentContainer.get(paintable);
+                    cc.setWidth("");
+                    cc.setHeight("");
+                } else {
+                    cc = new ChildComponentContainer((Widget) paintable,
+                            CellBasedLayout.ORIENTATION_VERTICAL);
+                    widgetToComponentContainer.put((Widget) paintable, cc);
+                    paintableToCell.put(paintable, this);
+                    cc.setWidth("");
+                    canvas.add(cc, 0, 0);
+                }
+            }
+            cc.renderChild(childUidl, client, -1);
+            if (sizeChangedDuringRendering && Util.isCached(childUidl)) {
+                client.handleComponentRelativeSize(cc.getWidget());
+            }
+            cc.updateWidgetSize();
+            nonRenderedWidgets.remove(paintable);
+        }
+
+        public UIDL getChildUIDL() {
+            return childUidl;
+        }
+
+        final int row;
+        final int col;
+        int colspan = 1;
+        int rowspan = 1;
+        UIDL childUidl;
+        int alignment;
+        ChildComponentContainer cc;
+
+        public void setUidl(UIDL c) {
+            // Set cell width
+            colspan = c.hasAttribute("w") ? c.getIntAttribute("w") : 1;
+            // Set cell height
+            rowspan = c.hasAttribute("h") ? c.getIntAttribute("h") : 1;
+            // ensure we will lose reference to old cells, now overlapped by
+            // this cell
+            for (int i = 0; i < colspan; i++) {
+                for (int j = 0; j < rowspan; j++) {
+                    if (i > 0 || j > 0) {
+                        cells[col + i][row + j] = null;
+                    }
+                }
+            }
+
+            c = c.getChildUIDL(0); // we are interested about childUidl
+            if (childUidl != null) {
+                if (c == null) {
+                    // content has vanished, old content will be removed from
+                    // canvas
+                    // later durin render phase
+                    cc = null;
+                } else if (cc != null
+                        && cc.getWidget() != client.getPaintable(c)) {
+                    // content has changed
+                    cc = null;
+                    if (widgetToComponentContainer.containsKey(client
+                            .getPaintable(c))) {
+                        // cc exist for this component (moved) use that for this
+                        // cell
+                        cc = widgetToComponentContainer.get(client
+                                .getPaintable(c));
+                        cc.setWidth("");
+                        cc.setHeight("");
+                    }
+                }
+            }
+            childUidl = c;
+            updateRelSizeStatus(c);
+        }
+
+        protected void updateRelSizeStatus(UIDL uidl) {
+            if (uidl != null && !uidl.getBooleanAttribute("cached")) {
+                if (uidl.hasAttribute("height")
+                        && uidl.getStringAttribute("height").contains("%")) {
+                    relHeight = true;
+                } else {
+                    relHeight = false;
+                }
+                if (uidl.hasAttribute("width")) {
+                    widthCanAffectHeight = relWidth = uidl.getStringAttribute(
+                            "width").contains("%");
+                    if (uidl.hasAttribute("height")) {
+                        widthCanAffectHeight = false;
+                    }
+                } else {
+                    widthCanAffectHeight = !uidl.hasAttribute("height");
+                    relWidth = false;
+                }
+            }
+        }
+    }
+
+    private Cell getCell(UIDL c) {
+        int row = c.getIntAttribute("y");
+        int col = c.getIntAttribute("x");
+        Cell cell = cells[col][row];
+        if (cell == null) {
+            cell = new Cell(c);
+            cells[col][row] = cell;
+        } else {
+            cell.setUidl(c);
+        }
+        return cell;
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VHorizontalLayout.java
new file mode 100644 (file)
index 0000000..042413c
--- /dev/null
@@ -0,0 +1,11 @@
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+public class VHorizontalLayout extends VOrderedLayout {\r
+\r
+    public static final String CLASSNAME = "i-horizontallayout";\r
+\r
+    public VHorizontalLayout() {\r
+        super(CLASSNAME, ORIENTATION_HORIZONTAL);\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLabel.java b/src/com/vaadin/terminal/gwt/client/ui/VLabel.java
new file mode 100644 (file)
index 0000000..5374f3c
--- /dev/null
@@ -0,0 +1,123 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.PreElement;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HTML;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VLabel extends HTML implements Paintable {
+
+    public static final String CLASSNAME = "i-label";
+    private static final String CLASSNAME_UNDEFINED_WIDTH = "i-label-undef-w";
+
+    private ApplicationConnection client;
+    private int verticalPaddingBorder = 0;
+    private int horizontalPaddingBorder = 0;
+
+    public VLabel() {
+        super();
+        setStyleName(CLASSNAME);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+    }
+
+    public VLabel(String text) {
+        super(text);
+        setStyleName(CLASSNAME);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (event.getTypeInt() == Event.ONLOAD) {
+            Util.notifyParentOfSizeChange(this, true);
+            event.cancelBubble(true);
+            return;
+        }
+        if (client != null) {
+            client.handleTooltipEvent(event, this);
+        }
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        this.client = client;
+
+        boolean sinkOnloads = false;
+
+        final String mode = uidl.getStringAttribute("mode");
+        if (mode == null || "text".equals(mode)) {
+            setText(uidl.getChildString(0));
+        } else if ("pre".equals(mode)) {
+            PreElement preElement = Document.get().createPreElement();
+            preElement.setInnerText(uidl.getChildUIDL(0).getChildString(0));
+            // clear existing content
+            setHTML("");
+            // add preformatted text to dom
+            getElement().appendChild(preElement);
+        } else if ("uidl".equals(mode)) {
+            setHTML(uidl.getChildrenAsXML());
+        } else if ("xhtml".equals(mode)) {
+            UIDL content = uidl.getChildUIDL(0).getChildUIDL(0);
+            if (content.getChildCount() > 0) {
+                setHTML(content.getChildString(0));
+            } else {
+                setHTML("");
+            }
+            sinkOnloads = true;
+        } else if ("xml".equals(mode)) {
+            setHTML(uidl.getChildUIDL(0).getChildString(0));
+        } else if ("raw".equals(mode)) {
+            setHTML(uidl.getChildUIDL(0).getChildString(0));
+            sinkOnloads = true;
+        } else {
+            setText("");
+        }
+        if (sinkOnloads) {
+            sinkOnloadsForContainedImgs();
+        }
+    }
+
+    private void sinkOnloadsForContainedImgs() {
+        NodeList<Element> images = getElement().getElementsByTagName("img");
+        for (int i = 0; i < images.getLength(); i++) {
+            Element img = images.getItem(i);
+            DOM.sinkEvents((com.google.gwt.user.client.Element) img,
+                    Event.ONLOAD);
+        }
+
+    }
+
+    @Override
+    public void setHeight(String height) {
+        verticalPaddingBorder = Util.setHeightExcludingPaddingAndBorder(this,
+                height, verticalPaddingBorder);
+    }
+
+    @Override
+    public void setWidth(String width) {
+        horizontalPaddingBorder = Util.setWidthExcludingPaddingAndBorder(this,
+                width, horizontalPaddingBorder);
+        if (width == null || width.equals("")) {
+            setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, true);
+        } else {
+            setStyleName(getElement(), CLASSNAME_UNDEFINED_WIDTH, false);
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VLink.java b/src/com/vaadin/terminal/gwt/client/ui/VLink.java
new file mode 100644 (file)
index 0000000..6aee7eb
--- /dev/null
@@ -0,0 +1,182 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+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.ClickListener;
+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.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VLink extends HTML implements Paintable, ClickListener {
+
+    public static final String CLASSNAME = "i-link";
+
+    private static final int BORDER_STYLE_DEFAULT = 0;
+    private static final int BORDER_STYLE_MINIMAL = 1;
+    private static final int BORDER_STYLE_NONE = 2;
+
+    private String src;
+
+    private String target;
+
+    private int borderStyle = BORDER_STYLE_DEFAULT;
+
+    private boolean enabled;
+
+    private boolean readonly;
+
+    private int targetWidth;
+
+    private int targetHeight;
+
+    private Element errorIndicatorElement;
+
+    private final Element anchor = DOM.createAnchor();
+
+    private final Element captionElement = DOM.createSpan();
+
+    private Icon icon;
+
+    private ApplicationConnection client;
+
+    public VLink() {
+        super();
+        getElement().appendChild(anchor);
+        anchor.appendChild(captionElement);
+        addClickListener(this);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+        // Ensure correct implementation,
+        // but don't let container manage caption etc.
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        this.client = client;
+
+        enabled = uidl.hasAttribute("disabled") ? false : true;
+        readonly = uidl.hasAttribute("readonly") ? true : false;
+
+        if (uidl.hasAttribute("name")) {
+            target = uidl.getStringAttribute("name");
+            anchor.setAttribute("target", target);
+        }
+        if (uidl.hasAttribute("src")) {
+            src = client.translateToolkitUri(uidl.getStringAttribute("src"));
+            anchor.setAttribute("href", src);
+        }
+
+        if (uidl.hasAttribute("border")) {
+            if ("none".equals(uidl.getStringAttribute("border"))) {
+                borderStyle = BORDER_STYLE_NONE;
+            } else {
+                borderStyle = BORDER_STYLE_MINIMAL;
+            }
+        } else {
+            borderStyle = BORDER_STYLE_DEFAULT;
+        }
+
+        targetHeight = uidl.hasAttribute("targetHeight") ? uidl
+                .getIntAttribute("targetHeight") : -1;
+        targetWidth = uidl.hasAttribute("targetWidth") ? uidl
+                .getIntAttribute("targetWidth") : -1;
+
+        // Set link caption
+        captionElement.setInnerText(uidl.getStringAttribute("caption"));
+
+        // handle error
+        if (uidl.hasAttribute("error")) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = DOM.createDiv();
+                DOM.setElementProperty(errorIndicatorElement, "className",
+                        "i-errorindicator");
+            }
+            DOM.insertChild(getElement(), errorIndicatorElement, 0);
+        } else if (errorIndicatorElement != null) {
+            DOM.setStyleAttribute(errorIndicatorElement, "display", "none");
+        }
+
+        if (uidl.hasAttribute("icon")) {
+            if (icon == null) {
+                icon = new Icon(client);
+                anchor.insertBefore(icon.getElement(), captionElement);
+            }
+            icon.setUri(uidl.getStringAttribute("icon"));
+        }
+
+    }
+
+    public void onClick(Widget sender) {
+        if (enabled && !readonly) {
+            if (target == null) {
+                target = "_self";
+            }
+            String features;
+            switch (borderStyle) {
+            case BORDER_STYLE_NONE:
+                features = "menubar=no,location=no,status=no";
+                break;
+            case BORDER_STYLE_MINIMAL:
+                features = "menubar=yes,location=no,status=no";
+                break;
+            default:
+                features = "";
+                break;
+            }
+
+            if (targetWidth > 0) {
+                features += (features.length() > 0 ? "," : "") + "width="
+                        + targetWidth;
+            }
+            if (targetHeight > 0) {
+                features += (features.length() > 0 ? "," : "") + "height="
+                        + targetHeight;
+            }
+
+            if (features.length() > 0) {
+                // if 'special features' are set, use window.open(), unless
+                // a modifier key is held (ctrl to open in new tab etc)
+                Event e = DOM.eventGetCurrentEvent();
+                if (!e.getCtrlKey() && !e.getAltKey() && !e.getShiftKey()
+                        && !e.getMetaKey()) {
+                    Window.open(src, target, features);
+                    e.preventDefault();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        final Element target = DOM.eventGetTarget(event);
+        if (event.getTypeInt() == Event.ONLOAD) {
+            Util.notifyParentOfSizeChange(this, true);
+        }
+        if (client != null) {
+            client.handleTooltipEvent(event, this);
+        }
+        if (target == captionElement || target == anchor
+                || (icon != null && target == icon.getElement())) {
+            super.onBrowserEvent(event);
+        }
+        if (!enabled) {
+            event.preventDefault();
+        }
+
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VListSelect.java
new file mode 100644 (file)
index 0000000..84443a3
--- /dev/null
@@ -0,0 +1,141 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VListSelect extends VOptionGroupBase {
+
+    public static final String CLASSNAME = "i-select";
+
+    private static final int VISIBLE_COUNT = 10;
+
+    protected TooltipListBox select;
+
+    private int lastSelectedIndex = -1;
+
+    public VListSelect() {
+        super(new TooltipListBox(true), CLASSNAME);
+        select = (TooltipListBox) optionsContainer;
+        select.setSelect(this);
+        select.addChangeListener(this);
+        select.addClickListener(this);
+        select.setStyleName(CLASSNAME + "-select");
+        select.setVisibleItemCount(VISIBLE_COUNT);
+    }
+
+    @Override
+    protected void buildOptions(UIDL uidl) {
+        select.setClient(client);
+        select.setMultipleSelect(isMultiselect());
+        select.setEnabled(!isDisabled() && !isReadonly());
+        select.clear();
+        if (!isMultiselect() && isNullSelectionAllowed()
+                && !isNullSelectionItemAvailable()) {
+            // can't unselect last item in singleselect mode
+            select.addItem("", null);
+        }
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            final UIDL optionUidl = (UIDL) i.next();
+            select.addItem(optionUidl.getStringAttribute("caption"), optionUidl
+                    .getStringAttribute("key"));
+            if (optionUidl.hasAttribute("selected")) {
+                select.setItemSelected(select.getItemCount() - 1, true);
+            }
+        }
+        if (getRows() > 0) {
+            select.setVisibleItemCount(getRows());
+        }
+    }
+
+    @Override
+    protected Object[] getSelectedItems() {
+        final Vector selectedItemKeys = new Vector();
+        for (int i = 0; i < select.getItemCount(); i++) {
+            if (select.isItemSelected(i)) {
+                selectedItemKeys.add(select.getValue(i));
+            }
+        }
+        return selectedItemKeys.toArray();
+    }
+
+    @Override
+    public void onChange(Widget sender) {
+        final int si = select.getSelectedIndex();
+        if (si == -1 && !isNullSelectionAllowed()) {
+            select.setSelectedIndex(lastSelectedIndex);
+        } else {
+            lastSelectedIndex = si;
+            if (isMultiselect()) {
+                client.updateVariable(id, "selected", getSelectedItems(),
+                        isImmediate());
+            } else {
+                client.updateVariable(id, "selected", new String[] { ""
+                        + getSelectedItem() }, isImmediate());
+            }
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        select.setHeight(height);
+        super.setHeight(height);
+    }
+
+    @Override
+    public void setWidth(String width) {
+        select.setWidth(width);
+        super.setWidth(width);
+    }
+
+    @Override
+    protected void setTabIndex(int tabIndex) {
+        ((TooltipListBox) optionsContainer).setTabIndex(tabIndex);
+    }
+
+    public void focus() {
+        select.setFocus(true);
+    }
+
+}
+
+/**
+ * Extended ListBox to listen tooltip events and forward them to generic
+ * handler.
+ */
+class TooltipListBox extends ListBox {
+    private ApplicationConnection client;
+    private Paintable pntbl;
+
+    TooltipListBox(boolean isMultiselect) {
+        super(isMultiselect);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+    }
+
+    public void setClient(ApplicationConnection client) {
+        this.client = client;
+    }
+
+    public void setSelect(Paintable s) {
+        pntbl = s;
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (client != null) {
+            client.handleTooltipEvent(event, pntbl);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMarginInfo.java b/src/com/vaadin/terminal/gwt/client/ui/VMarginInfo.java
new file mode 100644 (file)
index 0000000..961624d
--- /dev/null
@@ -0,0 +1,76 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.io.Serializable;
+
+@SuppressWarnings("serial")
+public class VMarginInfo implements Serializable {
+
+    private static final int TOP = 1;
+    private static final int RIGHT = 2;
+    private static final int BOTTOM = 4;
+    private static final int LEFT = 8;
+
+    private int bitMask;
+
+    public VMarginInfo(int bitMask) {
+        this.bitMask = bitMask;
+    }
+
+    public VMarginInfo(boolean top, boolean right, boolean bottom, boolean left) {
+        setMargins(top, right, bottom, left);
+    }
+
+    public void setMargins(boolean top, boolean right, boolean bottom,
+            boolean left) {
+        bitMask = top ? TOP : 0;
+        bitMask += right ? RIGHT : 0;
+        bitMask += bottom ? BOTTOM : 0;
+        bitMask += left ? LEFT : 0;
+    }
+
+    public void setMargins(VMarginInfo marginInfo) {
+        bitMask = marginInfo.bitMask;
+    }
+
+    public boolean hasLeft() {
+        return (bitMask & LEFT) == LEFT;
+    }
+
+    public boolean hasRight() {
+        return (bitMask & RIGHT) == RIGHT;
+    }
+
+    public boolean hasTop() {
+        return (bitMask & TOP) == TOP;
+    }
+
+    public boolean hasBottom() {
+        return (bitMask & BOTTOM) == BOTTOM;
+    }
+
+    public int getBitMask() {
+        return bitMask;
+    }
+
+    public void setMargins(boolean enabled) {
+        if (enabled) {
+            bitMask = TOP + RIGHT + BOTTOM + LEFT;
+        } else {
+            bitMask = 0;
+        }
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof VMarginInfo)) {
+            return false;
+        }
+
+        return ((VMarginInfo) obj).bitMask == bitMask;
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
new file mode 100644 (file)
index 0000000..1a71099
--- /dev/null
@@ -0,0 +1,644 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Stack;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.HasHTML;
+import com.google.gwt.user.client.ui.PopupListener;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.UIObject;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VMenuBar extends Widget implements Paintable, PopupListener {
+
+    /** Set the CSS class name to allow styling. */
+    public static final String CLASSNAME = "i-menubar";
+
+    /** For server connections **/
+    protected String uidlId;
+    protected ApplicationConnection client;
+
+    protected final VMenuBar hostReference = this;
+    protected String submenuIcon = null;
+    protected boolean collapseItems = true;
+    protected CustomMenuItem moreItem = null;
+
+    // Construct an empty command to be used when the item has no command
+    // associated
+    protected static final Command emptyCommand = null;
+
+    /** Widget fields **/
+    protected boolean subMenu;
+    protected ArrayList<CustomMenuItem> items;
+    protected Element containerElement;
+    protected VToolkitOverlay popup;
+    protected VMenuBar visibleChildMenu;
+    protected VMenuBar parentMenu;
+    protected CustomMenuItem selected;
+
+    public VMenuBar() {
+        // Create an empty horizontal menubar
+        this(false);
+    }
+
+    public VMenuBar(boolean subMenu) {
+        super();
+        setElement(DOM.createDiv());
+
+        items = new ArrayList<CustomMenuItem>();
+        popup = null;
+        visibleChildMenu = null;
+
+        Element table = DOM.createTable();
+        Element tbody = DOM.createTBody();
+        DOM.appendChild(getElement(), table);
+        DOM.appendChild(table, tbody);
+
+        if (!subMenu) {
+            setStyleName(CLASSNAME);
+            Element tr = DOM.createTR();
+            DOM.appendChild(tbody, tr);
+            containerElement = tr;
+        } else {
+            setStyleName(CLASSNAME + "-submenu");
+            containerElement = tbody;
+        }
+        this.subMenu = subMenu;
+
+        sinkEvents(Event.ONCLICK | Event.ONMOUSEOVER | Event.ONMOUSEOUT);
+    }
+
+    /**
+     * This method must be implemented to update the client-side component from
+     * UIDL data received from server.
+     * 
+     * This method is called when the page is loaded for the first time, and
+     * every time UI changes in the component are received from the server.
+     */
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // This call should be made first. Ensure correct implementation,
+        // and let the containing layout manage caption, etc.
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        // For future connections
+        this.client = client;
+        uidlId = uidl.getId();
+
+        // Empty the menu every time it receives new information
+        if (!getItems().isEmpty()) {
+            clearItems();
+        }
+
+        UIDL options = uidl.getChildUIDL(0);
+
+        if (options.hasAttribute("submenuIcon")) {
+            submenuIcon = client.translateToolkitUri(uidl.getChildUIDL(0)
+                    .getStringAttribute("submenuIcon"));
+        } else {
+            submenuIcon = null;
+        }
+
+        collapseItems = options.getBooleanAttribute("collapseItems");
+
+        if (collapseItems) {
+            UIDL moreItemUIDL = options.getChildUIDL(0);
+            StringBuffer itemHTML = new StringBuffer();
+
+            if (moreItemUIDL.hasAttribute("icon")) {
+                itemHTML.append("<img src=\""
+                        + client.translateToolkitUri(moreItemUIDL
+                                .getStringAttribute("icon"))
+                        + "\" align=\"left\" />");
+            }
+            itemHTML.append(moreItemUIDL.getStringAttribute("text"));
+
+            moreItem = new CustomMenuItem(itemHTML.toString(), emptyCommand);
+        }
+
+        UIDL uidlItems = uidl.getChildUIDL(1);
+        Iterator<UIDL> itr = uidlItems.getChildIterator();
+        Stack<Iterator<UIDL>> iteratorStack = new Stack<Iterator<UIDL>>();
+        Stack<VMenuBar> menuStack = new Stack<VMenuBar>();
+        VMenuBar currentMenu = this;
+
+        while (itr.hasNext()) {
+            UIDL item = (UIDL) itr.next();
+            CustomMenuItem currentItem = null;
+
+            String itemText = item.getStringAttribute("text");
+            final int itemId = item.getIntAttribute("id");
+
+            boolean itemHasCommand = item.getBooleanAttribute("command");
+
+            // Construct html from the text and the optional icon
+            StringBuffer itemHTML = new StringBuffer();
+
+            if (item.hasAttribute("icon")) {
+                itemHTML.append("<img src=\""
+                        + client.translateToolkitUri(item
+                                .getStringAttribute("icon"))
+                        + "\" align=\"left\" />");
+            }
+
+            itemHTML.append(itemText);
+
+            if (currentMenu != this && item.getChildCount() > 0
+                    && submenuIcon != null) {
+                itemHTML.append("<img src=\"" + submenuIcon
+                        + "\" align=\"right\" />");
+            }
+
+            Command cmd = null;
+
+            if (itemHasCommand) {
+                // Construct a command that fires onMenuClick(int) with the
+                // item's id-number
+                cmd = new Command() {
+                    public void execute() {
+                        hostReference.onMenuClick(itemId);
+                    }
+                };
+            }
+
+            currentItem = currentMenu.addItem(itemHTML.toString(), cmd);
+
+            if (item.getChildCount() > 0) {
+                menuStack.push(currentMenu);
+                iteratorStack.push(itr);
+                itr = item.getChildIterator();
+                currentMenu = new VMenuBar(true);
+                currentItem.setSubMenu(currentMenu);
+            }
+
+            while (!itr.hasNext() && !iteratorStack.empty()) {
+                itr = iteratorStack.pop();
+                currentMenu = (VMenuBar) menuStack.pop();
+            }
+        }// while
+
+        // we might need to collapse the top-level menu
+        if (collapseItems) {
+            int topLevelWidth = 0;
+
+            int ourWidth = getOffsetWidth();
+
+            int i = 0;
+            for (; i < getItems().size() && topLevelWidth < ourWidth; i++) {
+                CustomMenuItem item = (CustomMenuItem) getItems().get(i);
+                topLevelWidth += item.getOffsetWidth();
+            }
+
+            if (topLevelWidth > getOffsetWidth()) {
+                ArrayList<CustomMenuItem> toBeCollapsed = new ArrayList<CustomMenuItem>();
+                VMenuBar collapsed = new VMenuBar(true);
+                for (int j = i - 2; j < getItems().size(); j++) {
+                    toBeCollapsed.add(getItems().get(j));
+                }
+
+                for (int j = 0; j < toBeCollapsed.size(); j++) {
+                    CustomMenuItem item = (CustomMenuItem) toBeCollapsed.get(j);
+                    removeItem(item);
+
+                    // it's ugly, but we have to insert the submenu icon
+                    if (item.getSubMenu() != null && submenuIcon != null) {
+                        StringBuffer itemText = new StringBuffer(item.getHTML());
+                        itemText.append("<img src=\"");
+                        itemText.append(submenuIcon);
+                        itemText.append("\" align=\"right\" />");
+                        item.setHTML(itemText.toString());
+                    }
+
+                    collapsed.addItem(item);
+                }
+
+                moreItem.setSubMenu(collapsed);
+                addItem(moreItem);
+            }
+        }
+    }// updateFromUIDL
+
+    /**
+     * This is called by the items in the menu and it communicates the
+     * information to the server
+     * 
+     * @param clickedItemId
+     *            id of the item that was clicked
+     */
+    public void onMenuClick(int clickedItemId) {
+        // Updating the state to the server can not be done before
+        // the server connection is known, i.e., before updateFromUIDL()
+        // has been called.
+        if (uidlId != null && client != null) {
+            // Communicate the user interaction parameters to server. This call
+            // will initiate an AJAX request to the server.
+            client.updateVariable(uidlId, "clickedId", clickedItemId, true);
+        }
+    }
+
+    /** Widget methods **/
+
+    /**
+     * Returns a list of items in this menu
+     */
+    public List<CustomMenuItem> getItems() {
+        return items;
+    }
+
+    /**
+     * Remove all the items in this menu
+     */
+    public void clearItems() {
+        Element e = getContainingElement();
+        while (DOM.getChildCount(e) > 0) {
+            DOM.removeChild(e, DOM.getChild(e, 0));
+        }
+        items.clear();
+    }
+
+    /**
+     * Returns the containing element of the menu
+     * 
+     * @return
+     */
+    public Element getContainingElement() {
+        return containerElement;
+    }
+
+    /**
+     * Returns a new child element to add an item to
+     * 
+     * @return
+     */
+    public Element getNewChildElement() {
+        if (subMenu) {
+            Element tr = DOM.createTR();
+            DOM.appendChild(getContainingElement(), tr);
+            return tr;
+        } else {
+            return getContainingElement();
+        }
+
+    }
+
+    /**
+     * Add a new item to this menu
+     * 
+     * @param html
+     *            items text
+     * @param cmd
+     *            items command
+     * @return the item created
+     */
+    public CustomMenuItem addItem(String html, Command cmd) {
+        CustomMenuItem item = new CustomMenuItem(html, cmd);
+        addItem(item);
+        return item;
+    }
+
+    /**
+     * Add a new item to this menu
+     * 
+     * @param item
+     */
+    public void addItem(CustomMenuItem item) {
+        DOM.appendChild(getNewChildElement(), item.getElement());
+        item.setParentMenu(this);
+        item.setSelected(false);
+        items.add(item);
+    }
+
+    /**
+     * Remove the given item from this menu
+     * 
+     * @param item
+     */
+    public void removeItem(CustomMenuItem item) {
+        if (items.contains(item)) {
+            int index = items.indexOf(item);
+            Element container = getContainingElement();
+
+            DOM.removeChild(container, DOM.getChild(container, index));
+            items.remove(index);
+        }
+    }
+
+    /*
+     * @see
+     * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt.user
+     * .client.Event)
+     */
+    @Override
+    public void onBrowserEvent(Event e) {
+        super.onBrowserEvent(e);
+
+        Element targetElement = DOM.eventGetTarget(e);
+        CustomMenuItem targetItem = null;
+        for (int i = 0; i < items.size(); i++) {
+            CustomMenuItem item = (CustomMenuItem) items.get(i);
+            if (DOM.isOrHasChild(item.getElement(), targetElement)) {
+                targetItem = item;
+            }
+        }
+
+        if (targetItem != null) {
+            switch (DOM.eventGetType(e)) {
+
+            case Event.ONCLICK:
+                itemClick(targetItem);
+                break;
+
+            case Event.ONMOUSEOVER:
+                itemOver(targetItem);
+                break;
+
+            case Event.ONMOUSEOUT:
+                itemOut(targetItem);
+                break;
+            }
+        }
+    }
+
+    /**
+     * When an item is clicked
+     * 
+     * @param item
+     */
+    public void itemClick(CustomMenuItem item) {
+        if (item.getCommand() != null) {
+            setSelected(null);
+
+            if (visibleChildMenu != null) {
+                visibleChildMenu.hideChildren();
+            }
+
+            hideParents();
+            DeferredCommand.addCommand(item.getCommand());
+
+        } else {
+            if (item.getSubMenu() != null
+                    && item.getSubMenu() != visibleChildMenu) {
+                setSelected(item);
+                showChildMenu(item);
+            }
+        }
+    }
+
+    /**
+     * When the user hovers the mouse over the item
+     * 
+     * @param item
+     */
+    public void itemOver(CustomMenuItem item) {
+        setSelected(item);
+
+        boolean menuWasVisible = visibleChildMenu != null;
+
+        if (menuWasVisible && visibleChildMenu != item.getSubMenu()) {
+            popup.hide();
+            visibleChildMenu = null;
+        }
+
+        if (item.getSubMenu() != null && (parentMenu != null || menuWasVisible)
+                && visibleChildMenu != item.getSubMenu()) {
+            showChildMenu(item);
+        }
+    }
+
+    /**
+     * When the mouse is moved away from an item
+     * 
+     * @param item
+     */
+    public void itemOut(CustomMenuItem item) {
+        if (visibleChildMenu != item.getSubMenu() || visibleChildMenu == null) {
+            hideChildMenu(item);
+            setSelected(null);
+        }
+    }
+
+    /**
+     * Shows the child menu of an item. The caller must ensure that the item has
+     * a submenu.
+     * 
+     * @param item
+     */
+    public void showChildMenu(CustomMenuItem item) {
+        popup = new VToolkitOverlay(true, false, true);
+        popup.setWidget(item.getSubMenu());
+        popup.addPopupListener(this);
+
+        if (subMenu) {
+            popup.setPopupPosition(item.getParentMenu().getAbsoluteLeft()
+                    + item.getParentMenu().getOffsetWidth(), item
+                    .getAbsoluteTop());
+        } else {
+            popup.setPopupPosition(item.getAbsoluteLeft(), item.getParentMenu()
+                    .getAbsoluteTop()
+                    + item.getParentMenu().getOffsetHeight());
+        }
+
+        item.getSubMenu().onShow();
+        visibleChildMenu = item.getSubMenu();
+        item.getSubMenu().setParentMenu(this);
+
+        popup.show();
+    }
+
+    /**
+     * Hides the submenu of an item
+     * 
+     * @param item
+     */
+    public void hideChildMenu(CustomMenuItem item) {
+        if (visibleChildMenu != null
+                && !(visibleChildMenu == item.getSubMenu())) {
+            popup.hide();
+
+        }
+    }
+
+    /**
+     * When the menu is shown.
+     */
+    public void onShow() {
+        if (!items.isEmpty()) {
+            ((CustomMenuItem) items.get(0)).setSelected(true);
+        }
+    }
+
+    /**
+     * Recursively hide all child menus
+     */
+    public void hideChildren() {
+        if (visibleChildMenu != null) {
+            visibleChildMenu.hideChildren();
+            popup.hide();
+        }
+    }
+
+    /**
+     * Recursively hide all parent menus
+     */
+    public void hideParents() {
+
+        if (visibleChildMenu != null) {
+            popup.hide();
+            setSelected(null);
+        }
+
+        if (getParentMenu() != null) {
+            getParentMenu().hideParents();
+        }
+    }
+
+    /**
+     * Returns the parent menu of this menu, or null if this is the top-level
+     * menu
+     * 
+     * @return
+     */
+    public VMenuBar getParentMenu() {
+        return parentMenu;
+    }
+
+    /**
+     * Set the parent menu of this menu
+     * 
+     * @param parent
+     */
+    public void setParentMenu(VMenuBar parent) {
+        parentMenu = parent;
+    }
+
+    /**
+     * Returns the currently selected item of this menu, or null if nothing is
+     * selected
+     * 
+     * @return
+     */
+    public CustomMenuItem getSelected() {
+        return selected;
+    }
+
+    /**
+     * Set the currently selected item of this menu
+     * 
+     * @param item
+     */
+    public void setSelected(CustomMenuItem item) {
+        // If we had something selected, unselect
+        if (item != selected && selected != null) {
+            selected.setSelected(false);
+        }
+        // If we have a valid selection, select it
+        if (item != null) {
+            item.setSelected(true);
+        }
+
+        selected = item;
+    }
+
+    /**
+     * Listener method, fired when this menu is closed
+     */
+    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+        hideChildren();
+        if (autoClosed) {
+            hideParents();
+        }
+        // setSelected(null);
+        visibleChildMenu = null;
+        popup = null;
+
+    }
+
+    /**
+     * 
+     * A class to hold information on menu items
+     * 
+     */
+    private class CustomMenuItem extends UIObject implements HasHTML {
+
+        protected String html = null;
+        protected Command command = null;
+        protected VMenuBar subMenu = null;
+        protected VMenuBar parentMenu = null;
+
+        public CustomMenuItem(String html, Command cmd) {
+            setElement(DOM.createTD());
+
+            setHTML(html);
+            setCommand(cmd);
+            setSelected(false);
+
+            addStyleName("menuitem");
+        }
+
+        public void setSelected(boolean selected) {
+            if (selected) {
+                addStyleDependentName("selected");
+            } else {
+                removeStyleDependentName("selected");
+            }
+        }
+
+        /*
+         * setters and getters for the fields
+         */
+
+        public void setSubMenu(VMenuBar subMenu) {
+            this.subMenu = subMenu;
+        }
+
+        public VMenuBar getSubMenu() {
+            return subMenu;
+        }
+
+        public void setParentMenu(VMenuBar parentMenu) {
+            this.parentMenu = parentMenu;
+        }
+
+        public VMenuBar getParentMenu() {
+            return parentMenu;
+        }
+
+        public void setCommand(Command command) {
+            this.command = command;
+        }
+
+        public Command getCommand() {
+            return command;
+        }
+
+        public String getHTML() {
+            return html;
+        }
+
+        public void setHTML(String html) {
+            this.html = html;
+            DOM.setInnerHTML(getElement(), html);
+        }
+
+        public String getText() {
+            return html;
+        }
+
+        public void setText(String text) {
+            setHTML(text);
+
+        }
+    }
+
+}// class VMenuBar
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VNativeSelect.java
new file mode 100644 (file)
index 0000000..9623c88
--- /dev/null
@@ -0,0 +1,111 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+import java.util.Vector;
+
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VNativeSelect extends VOptionGroupBase implements Field {
+
+    public static final String CLASSNAME = "i-select";
+
+    protected TooltipListBox select;
+
+    public VNativeSelect() {
+        super(new TooltipListBox(false), CLASSNAME);
+        select = (TooltipListBox) optionsContainer;
+        select.setSelect(this);
+        select.setVisibleItemCount(1);
+        select.addChangeListener(this);
+        select.setStyleName(CLASSNAME + "-select");
+
+    }
+
+    @Override
+    protected void buildOptions(UIDL uidl) {
+        select.setClient(client);
+        select.setEnabled(!isDisabled() && !isReadonly());
+        select.clear();
+        if (isNullSelectionAllowed() && !isNullSelectionItemAvailable()) {
+            // can't unselect last item in singleselect mode
+            select.addItem("", null);
+        }
+        boolean selected = false;
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            final UIDL optionUidl = (UIDL) i.next();
+            select.addItem(optionUidl.getStringAttribute("caption"), optionUidl
+                    .getStringAttribute("key"));
+            if (optionUidl.hasAttribute("selected")) {
+                select.setItemSelected(select.getItemCount() - 1, true);
+                selected = true;
+            }
+        }
+        if (!selected && !isNullSelectionAllowed()) {
+            // null-select not allowed, but value not selected yet; add null and
+            // remove when something is selected
+            select.insertItem("", null, 0);
+            select.setItemSelected(0, true);
+        }
+        if (BrowserInfo.get().isIE6()) {
+            // lazy size change - IE6 uses naive dropdown that does not have a
+            // proper size yet
+            Util.notifyParentOfSizeChange(this, true);
+        }
+    }
+
+    @Override
+    protected Object[] getSelectedItems() {
+        final Vector selectedItemKeys = new Vector();
+        for (int i = 0; i < select.getItemCount(); i++) {
+            if (select.isItemSelected(i)) {
+                selectedItemKeys.add(select.getValue(i));
+            }
+        }
+        return selectedItemKeys.toArray();
+    }
+
+    @Override
+    public void onChange(Widget sender) {
+
+        if (select.isMultipleSelect()) {
+            client.updateVariable(id, "selected", getSelectedItems(),
+                    isImmediate());
+        } else {
+            client.updateVariable(id, "selected", new String[] { ""
+                    + getSelectedItem() }, isImmediate());
+        }
+        if (!isNullSelectionAllowed() && "null".equals(select.getValue(0))) {
+            // remove temporary empty item
+            select.removeItem(0);
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        select.setHeight(height);
+        super.setHeight(height);
+    }
+
+    @Override
+    public void setWidth(String width) {
+        select.setWidth(width);
+        super.setWidth(width);
+    }
+
+    @Override
+    protected void setTabIndex(int tabIndex) {
+        ((TooltipListBox) optionsContainer).setTabIndex(tabIndex);
+    }
+
+    public void focus() {
+        select.setFocus(true);
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VNotification.java b/src/com/vaadin/terminal/gwt/client/ui/VNotification.java
new file mode 100644 (file)
index 0000000..2c81cd7
--- /dev/null
@@ -0,0 +1,323 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.EventObject;\r
+import java.util.Iterator;\r
+\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.ui.HTML;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.BrowserInfo;\r
+\r
+public class VNotification extends VToolkitOverlay {\r
+\r
+    public static final int CENTERED = 1;\r
+    public static final int CENTERED_TOP = 2;\r
+    public static final int CENTERED_BOTTOM = 3;\r
+    public static final int TOP_LEFT = 4;\r
+    public static final int TOP_RIGHT = 5;\r
+    public static final int BOTTOM_LEFT = 6;\r
+    public static final int BOTTOM_RIGHT = 7;\r
+\r
+    public static final int DELAY_FOREVER = -1;\r
+    public static final int DELAY_NONE = 0;\r
+\r
+    private static final String STYLENAME = "i-Notification";\r
+    private static final int mouseMoveThreshold = 7;\r
+    private static final int Z_INDEX_BASE = 20000;\r
+    public static final String STYLE_SYSTEM = "system";\r
+    private static final int FADE_ANIMATION_INTERVAL = 50; // == 20 fps\r
+\r
+    private int startOpacity = 90;\r
+    private int fadeMsec = 400;\r
+    private int delayMsec = 1000;\r
+\r
+    private Timer fader;\r
+    private Timer delay;\r
+\r
+    private int x = -1;\r
+    private int y = -1;\r
+\r
+    private String temporaryStyle;\r
+\r
+    private ArrayList<EventListener> listeners;\r
+\r
+    public VNotification() {\r
+        setStylePrimaryName(STYLENAME);\r
+        sinkEvents(Event.ONCLICK);\r
+        DOM.setStyleAttribute(getElement(), "zIndex", "" + Z_INDEX_BASE);\r
+    }\r
+\r
+    public VNotification(int delayMsec) {\r
+        this();\r
+        this.delayMsec = delayMsec;\r
+    }\r
+\r
+    public VNotification(int delayMsec, int fadeMsec, int startOpacity) {\r
+        this(delayMsec);\r
+        this.fadeMsec = fadeMsec;\r
+        this.startOpacity = startOpacity;\r
+    }\r
+\r
+    public void startDelay() {\r
+        DOM.removeEventPreview(this);\r
+        if (delayMsec > 0) {\r
+            if (delay == null) {\r
+                delay = new Timer() {\r
+                    @Override\r
+                    public void run() {\r
+                        fade();\r
+                    }\r
+                };\r
+                delay.schedule(delayMsec);\r
+            }\r
+        } else if (delayMsec == 0) {\r
+            fade();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void show() {\r
+        show(CENTERED);\r
+    }\r
+\r
+    public void show(String style) {\r
+        show(CENTERED, style);\r
+    }\r
+\r
+    public void show(int position) {\r
+        show(position, null);\r
+    }\r
+\r
+    public void show(Widget widget, int position, String style) {\r
+        setWidget(widget);\r
+        show(position, style);\r
+    }\r
+\r
+    public void show(String html, int position, String style) {\r
+        setWidget(new HTML(html));\r
+        show(position, style);\r
+    }\r
+\r
+    public void show(int position, String style) {\r
+        setOpacity(getElement(), startOpacity);\r
+        if (style != null) {\r
+            temporaryStyle = style;\r
+            addStyleName(style);\r
+        }\r
+        super.show();\r
+        setPosition(position);\r
+    }\r
+\r
+    @Override\r
+    public void hide() {\r
+        DOM.removeEventPreview(this);\r
+        cancelDelay();\r
+        cancelFade();\r
+        if (temporaryStyle != null) {\r
+            removeStyleName(temporaryStyle);\r
+            temporaryStyle = null;\r
+        }\r
+        super.hide();\r
+        fireEvent(new HideEvent(this));\r
+    }\r
+\r
+    public void fade() {\r
+        DOM.removeEventPreview(this);\r
+        cancelDelay();\r
+        fader = new Timer() {\r
+            private final long start = new Date().getTime();\r
+\r
+            @Override\r
+            public void run() {\r
+                /*\r
+                 * To make animation smooth, don't count that event happens on\r
+                 * time. Reduce opacity according to the actual time spent\r
+                 * instead of fixed decrement.\r
+                 */\r
+                long now = new Date().getTime();\r
+                long timeEplaced = now - start;\r
+                float remainingFraction = 1 - timeEplaced / (float) fadeMsec;\r
+                int opacity = (int) (startOpacity * remainingFraction);\r
+                if (opacity <= 0) {\r
+                    cancel();\r
+                    hide();\r
+                    if (BrowserInfo.get().isOpera()) {\r
+                        // tray notification on opera needs to explicitly define\r
+                        // size, reset it\r
+                        DOM.setStyleAttribute(getElement(), "width", "");\r
+                        DOM.setStyleAttribute(getElement(), "height", "");\r
+                    }\r
+                } else {\r
+                    setOpacity(getElement(), opacity);\r
+                }\r
+            }\r
+        };\r
+        fader.scheduleRepeating(FADE_ANIMATION_INTERVAL);\r
+    }\r
+\r
+    public void setPosition(int position) {\r
+        final Element el = getElement();\r
+        DOM.setStyleAttribute(el, "top", "");\r
+        DOM.setStyleAttribute(el, "left", "");\r
+        DOM.setStyleAttribute(el, "bottom", "");\r
+        DOM.setStyleAttribute(el, "right", "");\r
+        switch (position) {\r
+        case TOP_LEFT:\r
+            DOM.setStyleAttribute(el, "top", "0px");\r
+            DOM.setStyleAttribute(el, "left", "0px");\r
+            break;\r
+        case TOP_RIGHT:\r
+            DOM.setStyleAttribute(el, "top", "0px");\r
+            DOM.setStyleAttribute(el, "right", "0px");\r
+            break;\r
+        case BOTTOM_RIGHT:\r
+            DOM.setStyleAttribute(el, "position", "absolute");\r
+            if (BrowserInfo.get().isOpera()) {\r
+                // tray notification on opera needs explicitly defined size\r
+                DOM.setStyleAttribute(el, "width", getOffsetWidth() + "px");\r
+                DOM.setStyleAttribute(el, "height", getOffsetHeight() + "px");\r
+            }\r
+            DOM.setStyleAttribute(el, "bottom", "0px");\r
+            DOM.setStyleAttribute(el, "right", "0px");\r
+            break;\r
+        case BOTTOM_LEFT:\r
+            DOM.setStyleAttribute(el, "bottom", "0px");\r
+            DOM.setStyleAttribute(el, "left", "0px");\r
+            break;\r
+        case CENTERED_TOP:\r
+            center();\r
+            DOM.setStyleAttribute(el, "top", "0px");\r
+            break;\r
+        case CENTERED_BOTTOM:\r
+            center();\r
+            DOM.setStyleAttribute(el, "top", "");\r
+            DOM.setStyleAttribute(el, "bottom", "0px");\r
+            break;\r
+        default:\r
+        case CENTERED:\r
+            center();\r
+            break;\r
+        }\r
+    }\r
+\r
+    private void cancelFade() {\r
+        if (fader != null) {\r
+            fader.cancel();\r
+            fader = null;\r
+        }\r
+    }\r
+\r
+    private void cancelDelay() {\r
+        if (delay != null) {\r
+            delay.cancel();\r
+            delay = null;\r
+        }\r
+    }\r
+\r
+    private void setOpacity(Element el, int opacity) {\r
+        DOM.setStyleAttribute(el, "opacity", "" + (opacity / 100.0));\r
+        if (BrowserInfo.get().isIE()) {\r
+            DOM.setStyleAttribute(el, "filter", "Alpha(opacity=" + opacity\r
+                    + ")");\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void onBrowserEvent(Event event) {\r
+        DOM.removeEventPreview(this);\r
+        if (fader == null) {\r
+            fade();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public boolean onEventPreview(Event event) {\r
+        int type = DOM.eventGetType(event);\r
+        // "modal"\r
+        if (delayMsec == -1 || temporaryStyle == STYLE_SYSTEM) {\r
+            if (type == Event.ONCLICK) {\r
+                if (DOM.isOrHasChild(getElement(), DOM.eventGetTarget(event))) {\r
+                    fade();\r
+                    return false;\r
+                }\r
+            }\r
+            if (temporaryStyle == STYLE_SYSTEM) {\r
+                return true;\r
+            } else {\r
+                return false;\r
+            }\r
+        }\r
+        // default\r
+        switch (type) {\r
+        case Event.ONMOUSEMOVE:\r
+\r
+            if (x < 0) {\r
+                x = DOM.eventGetClientX(event);\r
+                y = DOM.eventGetClientY(event);\r
+            } else if (Math.abs(DOM.eventGetClientX(event) - x) > mouseMoveThreshold\r
+                    || Math.abs(DOM.eventGetClientY(event) - y) > mouseMoveThreshold) {\r
+                startDelay();\r
+            }\r
+            break;\r
+        case Event.ONMOUSEDOWN:\r
+        case Event.ONMOUSEWHEEL:\r
+        case Event.ONSCROLL:\r
+            startDelay();\r
+            break;\r
+        case Event.ONKEYDOWN:\r
+            if (event.getRepeat()) {\r
+                return true;\r
+            }\r
+            startDelay();\r
+            break;\r
+        default:\r
+            break;\r
+        }\r
+        return true;\r
+    }\r
+\r
+    public void addEventListener(EventListener listener) {\r
+        if (listeners == null) {\r
+            listeners = new ArrayList<EventListener>();\r
+        }\r
+        listeners.add(listener);\r
+    }\r
+\r
+    public void removeEventListener(EventListener listener) {\r
+        if (listeners == null) {\r
+            return;\r
+        }\r
+        listeners.remove(listener);\r
+    }\r
+\r
+    private void fireEvent(HideEvent event) {\r
+        if (listeners != null) {\r
+            for (Iterator<EventListener> it = listeners.iterator(); it\r
+                    .hasNext();) {\r
+                EventListener l = it.next();\r
+                l.notificationHidden(event);\r
+            }\r
+        }\r
+    }\r
+\r
+    public class HideEvent extends EventObject {\r
+        private static final long serialVersionUID = 4428671753988459560L;\r
+\r
+        public HideEvent(Object source) {\r
+            super(source);\r
+        }\r
+    }\r
+\r
+    public interface EventListener extends java.util.EventListener {\r
+        public void notificationHidden(HideEvent event);\r
+    }\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroup.java
new file mode 100644 (file)
index 0000000..8d2f41f
--- /dev/null
@@ -0,0 +1,102 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+\r
+import com.google.gwt.user.client.ui.CheckBox;\r
+import com.google.gwt.user.client.ui.HasFocus;\r
+import com.google.gwt.user.client.ui.Panel;\r
+import com.google.gwt.user.client.ui.RadioButton;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VOptionGroup extends VOptionGroupBase {\r
+\r
+    public static final String CLASSNAME = "i-select-optiongroup";\r
+\r
+    private final Panel panel;\r
+\r
+    private final Map optionsToKeys;\r
+\r
+    public VOptionGroup() {\r
+        super(CLASSNAME);\r
+        panel = (Panel) optionsContainer;\r
+        optionsToKeys = new HashMap();\r
+    }\r
+\r
+    /*\r
+     * Return true if no elements were changed, false otherwise.\r
+     */\r
+    @Override\r
+    protected void buildOptions(UIDL uidl) {\r
+        panel.clear();\r
+        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {\r
+            final UIDL opUidl = (UIDL) it.next();\r
+            CheckBox op;\r
+            if (isMultiselect()) {\r
+                op = new VCheckBox();\r
+                op.setText(opUidl.getStringAttribute("caption"));\r
+            } else {\r
+                op = new RadioButton(id, opUidl.getStringAttribute("caption"));\r
+                op.setStyleName("i-radiobutton");\r
+            }\r
+            op.addStyleName(CLASSNAME_OPTION);\r
+            op.setChecked(opUidl.getBooleanAttribute("selected"));\r
+            op.setEnabled(!opUidl.getBooleanAttribute("disabled")\r
+                    && !isReadonly() && !isDisabled());\r
+            op.addClickListener(this);\r
+            optionsToKeys.put(op, opUidl.getStringAttribute("key"));\r
+            panel.add(op);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected Object[] getSelectedItems() {\r
+        return selectedKeys.toArray();\r
+    }\r
+\r
+    @Override\r
+    public void onClick(Widget sender) {\r
+        super.onClick(sender);\r
+        if (sender instanceof CheckBox) {\r
+            final boolean selected = ((CheckBox) sender).isChecked();\r
+            final String key = (String) optionsToKeys.get(sender);\r
+            if (!isMultiselect()) {\r
+                selectedKeys.clear();\r
+            }\r
+            if (selected) {\r
+                selectedKeys.add(key);\r
+            } else {\r
+                selectedKeys.remove(key);\r
+            }\r
+            client.updateVariable(id, "selected", getSelectedItems(),\r
+                    isImmediate());\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected void setTabIndex(int tabIndex) {\r
+        for (Iterator iterator = panel.iterator(); iterator.hasNext();) {\r
+            if (isMultiselect()) {\r
+                VCheckBox cb = (VCheckBox) iterator.next();\r
+                cb.setTabIndex(tabIndex);\r
+            } else {\r
+                RadioButton rb = (RadioButton) iterator.next();\r
+                rb.setTabIndex(tabIndex);\r
+            }\r
+        }\r
+    }\r
+\r
+    public void focus() {\r
+        Iterator<Widget> iterator = panel.iterator();\r
+        if (iterator.hasNext()) {\r
+            ((HasFocus) iterator.next()).setFocus(true);\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java b/src/com/vaadin/terminal/gwt/client/ui/VOptionGroupBase.java
new file mode 100644 (file)
index 0000000..9069495
--- /dev/null
@@ -0,0 +1,229 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Set;\r
+\r
+import com.google.gwt.user.client.ui.ChangeListener;\r
+import com.google.gwt.user.client.ui.ClickListener;\r
+import com.google.gwt.user.client.ui.Composite;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.google.gwt.user.client.ui.KeyboardListener;\r
+import com.google.gwt.user.client.ui.Panel;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.Focusable;\r
+import com.vaadin.terminal.gwt.client.Paintable;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+abstract class VOptionGroupBase extends Composite implements Paintable, Field,\r
+        ClickListener, ChangeListener, KeyboardListener, Focusable {\r
+\r
+    public static final String CLASSNAME_OPTION = "i-select-option";\r
+\r
+    protected ApplicationConnection client;\r
+\r
+    protected String id;\r
+\r
+    protected Set selectedKeys;\r
+\r
+    private boolean immediate;\r
+\r
+    private boolean multiselect;\r
+\r
+    private boolean disabled;\r
+\r
+    private boolean readonly;\r
+\r
+    private int cols = 0;\r
+\r
+    private int rows = 0;\r
+\r
+    private boolean nullSelectionAllowed = true;\r
+\r
+    private boolean nullSelectionItemAvailable = false;\r
+\r
+    /**\r
+     * Widget holding the different options (e.g. ListBox or Panel for radio\r
+     * buttons) (optional, fallbacks to container Panel)\r
+     */\r
+    protected Widget optionsContainer;\r
+\r
+    /**\r
+     * Panel containing the component\r
+     */\r
+    private final Panel container;\r
+\r
+    private VTextField newItemField;\r
+\r
+    private VButton newItemButton;\r
+\r
+    public VOptionGroupBase(String classname) {\r
+        container = new FlowPanel();\r
+        initWidget(container);\r
+        optionsContainer = container;\r
+        container.setStyleName(classname);\r
+        immediate = false;\r
+        multiselect = false;\r
+    }\r
+\r
+    /*\r
+     * Call this if you wish to specify your own container for the option\r
+     * elements (e.g. SELECT)\r
+     */\r
+    public VOptionGroupBase(Widget w, String classname) {\r
+        this(classname);\r
+        optionsContainer = w;\r
+        container.add(optionsContainer);\r
+    }\r
+\r
+    protected boolean isImmediate() {\r
+        return immediate;\r
+    }\r
+\r
+    protected boolean isMultiselect() {\r
+        return multiselect;\r
+    }\r
+\r
+    protected boolean isDisabled() {\r
+        return disabled;\r
+    }\r
+\r
+    protected boolean isReadonly() {\r
+        return readonly;\r
+    }\r
+\r
+    protected boolean isNullSelectionAllowed() {\r
+        return nullSelectionAllowed;\r
+    }\r
+\r
+    protected boolean isNullSelectionItemAvailable() {\r
+        return nullSelectionItemAvailable;\r
+    }\r
+\r
+    /**\r
+     * @return "cols" specified in uidl, 0 if not specified\r
+     */\r
+    protected int getColumns() {\r
+        return cols;\r
+    }\r
+\r
+    /**\r
+     * @return "rows" specified in uidl, 0 if not specified\r
+     */\r
+\r
+    protected int getRows() {\r
+        return rows;\r
+    }\r
+\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        this.client = client;\r
+        id = uidl.getId();\r
+\r
+        if (client.updateComponent(this, uidl, true)) {\r
+            return;\r
+        }\r
+\r
+        selectedKeys = uidl.getStringArrayVariableAsSet("selected");\r
+\r
+        readonly = uidl.getBooleanAttribute("readonly");\r
+        disabled = uidl.getBooleanAttribute("disabled");\r
+        multiselect = "multi".equals(uidl.getStringAttribute("selectmode"));\r
+        immediate = uidl.getBooleanAttribute("immediate");\r
+        nullSelectionAllowed = uidl.getBooleanAttribute("nullselect");\r
+        nullSelectionItemAvailable = uidl.getBooleanAttribute("nullselectitem");\r
+\r
+        cols = uidl.getIntAttribute("cols");\r
+        rows = uidl.getIntAttribute("rows");\r
+\r
+        final UIDL ops = uidl.getChildUIDL(0);\r
+\r
+        if (getColumns() > 0) {\r
+            container.setWidth(getColumns() + "em");\r
+            if (container != optionsContainer) {\r
+                optionsContainer.setWidth("100%");\r
+            }\r
+        }\r
+\r
+        buildOptions(ops);\r
+\r
+        if (uidl.getBooleanAttribute("allownewitem")) {\r
+            if (newItemField == null) {\r
+                newItemButton = new VButton();\r
+                newItemButton.setText("+");\r
+                newItemButton.setWidth("1.5em");\r
+                newItemButton.addClickListener(this);\r
+                newItemField = new VTextField();\r
+                newItemField.addKeyboardListener(this);\r
+                // newItemField.setColumns(16);\r
+                if (getColumns() > 0) {\r
+                    newItemField.setWidth((getColumns() - 2) + "em");\r
+                }\r
+            }\r
+            newItemField.setEnabled(!disabled && !readonly);\r
+            newItemButton.setEnabled(!disabled && !readonly);\r
+\r
+            if (newItemField == null || newItemField.getParent() != container) {\r
+                container.add(newItemField);\r
+                container.add(newItemButton);\r
+            }\r
+        } else if (newItemField != null) {\r
+            container.remove(newItemField);\r
+            container.remove(newItemButton);\r
+        }\r
+\r
+        setTabIndex(uidl.hasAttribute("tabindex") ? uidl\r
+                .getIntAttribute("tabindex") : 0);\r
+\r
+    }\r
+\r
+    abstract protected void setTabIndex(int tabIndex);\r
+\r
+    public void onClick(Widget sender) {\r
+        if (sender == newItemButton && !newItemField.getText().equals("")) {\r
+            client.updateVariable(id, "newitem", newItemField.getText(), true);\r
+            newItemField.setText("");\r
+        }\r
+    }\r
+\r
+    public void onChange(Widget sender) {\r
+        if (multiselect) {\r
+            client\r
+                    .updateVariable(id, "selected", getSelectedItems(),\r
+                            immediate);\r
+        } else {\r
+            client.updateVariable(id, "selected", new String[] { ""\r
+                    + getSelectedItem() }, immediate);\r
+        }\r
+    }\r
+\r
+    public void onKeyPress(Widget sender, char keyCode, int modifiers) {\r
+        if (sender == newItemField && keyCode == KeyboardListener.KEY_ENTER) {\r
+            newItemButton.click();\r
+        }\r
+    }\r
+\r
+    public void onKeyUp(Widget sender, char keyCode, int modifiers) {\r
+        // Ignore, subclasses may override\r
+    }\r
+\r
+    public void onKeyDown(Widget sender, char keyCode, int modifiers) {\r
+        // Ignore, subclasses may override\r
+    }\r
+\r
+    protected abstract void buildOptions(UIDL uidl);\r
+\r
+    protected abstract Object[] getSelectedItems();\r
+\r
+    protected Object getSelectedItem() {\r
+        final Object[] sel = getSelectedItems();\r
+        if (sel.length > 0) {\r
+            return sel[0];\r
+        } else {\r
+            return null;\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VOrderedLayout.java
new file mode 100644 (file)
index 0000000..19fadb1
--- /dev/null
@@ -0,0 +1,876 @@
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+\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.Paintable;\r
+import com.vaadin.terminal.gwt.client.RenderSpace;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+import com.vaadin.terminal.gwt.client.Util;\r
+import com.vaadin.terminal.gwt.client.RenderInformation.FloatSize;\r
+import com.vaadin.terminal.gwt.client.RenderInformation.Size;\r
+import com.vaadin.terminal.gwt.client.ui.layout.CellBasedLayout;\r
+import com.vaadin.terminal.gwt.client.ui.layout.ChildComponentContainer;\r
+\r
+public class VOrderedLayout extends CellBasedLayout {\r
+\r
+    public static final String CLASSNAME = "i-orderedlayout";\r
+\r
+    private int orientation;\r
+\r
+    // Can be removed once OrderedLayout is removed\r
+    private boolean allowOrientationUpdate = false;\r
+\r
+    /**\r
+     * Size of the layout excluding any margins.\r
+     */\r
+    private Size activeLayoutSize = new Size(0, 0);\r
+\r
+    private boolean isRendering = false;\r
+\r
+    private String width = "";\r
+\r
+    private boolean sizeHasChangedDuringRendering = false;\r
+\r
+    public VOrderedLayout() {\r
+        this(CLASSNAME, ORIENTATION_VERTICAL);\r
+        allowOrientationUpdate = true;\r
+    }\r
+\r
+    protected VOrderedLayout(String className, int orientation) {\r
+        setStyleName(className);\r
+        this.orientation = orientation;\r
+\r
+        STYLENAME_SPACING = className + "-spacing";\r
+        STYLENAME_MARGIN_TOP = className + "-margin-top";\r
+        STYLENAME_MARGIN_RIGHT = className + "-margin-right";\r
+        STYLENAME_MARGIN_BOTTOM = className + "-margin-bottom";\r
+        STYLENAME_MARGIN_LEFT = className + "-margin-left";\r
+\r
+    }\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        isRendering = true;\r
+        super.updateFromUIDL(uidl, client);\r
+\r
+        // Only non-cached, visible UIDL:s can introduce changes\r
+        if (uidl.getBooleanAttribute("cached")\r
+                || uidl.getBooleanAttribute("invisible")) {\r
+            isRendering = false;\r
+            return;\r
+        }\r
+\r
+        if (allowOrientationUpdate) {\r
+            handleOrientationUpdate(uidl);\r
+        }\r
+\r
+        // IStopWatch w = new IStopWatch("OrderedLayout.updateFromUIDL");\r
+\r
+        ArrayList<Widget> uidlWidgets = new ArrayList<Widget>(uidl\r
+                .getChildCount());\r
+        ArrayList<ChildComponentContainer> relativeSizeComponents = new ArrayList<ChildComponentContainer>();\r
+        ArrayList<UIDL> relativeSizeComponentUIDL = new ArrayList<UIDL>();\r
+\r
+        int pos = 0;\r
+        for (final Iterator<UIDL> it = uidl.getChildIterator(); it.hasNext();) {\r
+            final UIDL childUIDL = it.next();\r
+            final Paintable child = client.getPaintable(childUIDL);\r
+            Widget widget = (Widget) child;\r
+\r
+            // Create container for component\r
+            ChildComponentContainer childComponentContainer = getComponentContainer(widget);\r
+\r
+            if (childComponentContainer == null) {\r
+                // This is a new component\r
+                childComponentContainer = createChildContainer(widget);\r
+            }\r
+\r
+            addOrMoveChild(childComponentContainer, pos++);\r
+\r
+            /*\r
+             * Components which are to be expanded in the same orientation as\r
+             * the layout are rendered later when it is clear how much space\r
+             * they can use\r
+             */\r
+            if (!Util.isCached(childUIDL)) {\r
+                FloatSize relativeSize = Util.parseRelativeSize(childUIDL);\r
+                childComponentContainer.setRelativeSize(relativeSize);\r
+            }\r
+\r
+            if (childComponentContainer.isComponentRelativeSized(orientation)) {\r
+                relativeSizeComponents.add(childComponentContainer);\r
+                relativeSizeComponentUIDL.add(childUIDL);\r
+            } else {\r
+                if (isDynamicWidth()) {\r
+                    childComponentContainer.renderChild(childUIDL, client, 0);\r
+                } else {\r
+                    childComponentContainer.renderChild(childUIDL, client,\r
+                            activeLayoutSize.getWidth());\r
+                }\r
+                if (sizeHasChangedDuringRendering && Util.isCached(childUIDL)) {\r
+                    // notify cached relative sized component about size\r
+                    // chance\r
+                    client.handleComponentRelativeSize(childComponentContainer\r
+                            .getWidget());\r
+                }\r
+            }\r
+\r
+            uidlWidgets.add(widget);\r
+\r
+        }\r
+\r
+        // w.mark("Rendering of "\r
+        // + (uidlWidgets.size() - relativeSizeComponents.size())\r
+        // + " absolute size components done");\r
+\r
+        /*\r
+         * Remove any children after pos. These are the ones that previously\r
+         * were in the layout but have now been removed\r
+         */\r
+        removeChildrenAfter(pos);\r
+\r
+        // w.mark("Old children removed");\r
+\r
+        /* Fetch alignments and expand ratio from UIDL */\r
+        updateAlignmentsAndExpandRatios(uidl, uidlWidgets);\r
+        // w.mark("Alignments and expand ratios updated");\r
+\r
+        /* Fetch widget sizes from rendered components */\r
+        updateWidgetSizes();\r
+        // w.mark("Widget sizes updated");\r
+\r
+        recalculateLayout();\r
+        // w.mark("Layout size calculated (" + activeLayoutSize +\r
+        // ") offsetSize: "\r
+        // + getOffsetWidth() + "," + getOffsetHeight());\r
+\r
+        /* Render relative size components */\r
+        for (int i = 0; i < relativeSizeComponents.size(); i++) {\r
+            ChildComponentContainer childComponentContainer = relativeSizeComponents\r
+                    .get(i);\r
+            UIDL childUIDL = relativeSizeComponentUIDL.get(i);\r
+\r
+            if (isDynamicWidth()) {\r
+                childComponentContainer.renderChild(childUIDL, client, 0);\r
+            } else {\r
+                childComponentContainer.renderChild(childUIDL, client,\r
+                        activeLayoutSize.getWidth());\r
+            }\r
+\r
+            if (Util.isCached(childUIDL)) {\r
+                /*\r
+                 * We must update the size of the relative sized component if\r
+                 * the expand ratio or something else in the layout changes\r
+                 * which affects the size of a relative sized component\r
+                 */\r
+                client.handleComponentRelativeSize(childComponentContainer\r
+                        .getWidget());\r
+            }\r
+\r
+            // childComponentContainer.updateWidgetSize();\r
+        }\r
+\r
+        // w.mark("Rendering of " + (relativeSizeComponents.size())\r
+        // + " relative size components done");\r
+\r
+        /* Fetch widget sizes for relative size components */\r
+        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
+                .values()) {\r
+\r
+            /* Update widget size from DOM */\r
+            childComponentContainer.updateWidgetSize();\r
+        }\r
+\r
+        // w.mark("Widget sizes updated");\r
+\r
+        /*\r
+         * Components with relative size in main direction may affect the layout\r
+         * size in the other direction\r
+         */\r
+        if ((isHorizontal() && isDynamicHeight())\r
+                || (isVertical() && isDynamicWidth())) {\r
+            layoutSizeMightHaveChanged();\r
+        }\r
+        // w.mark("Layout dimensions updated");\r
+\r
+        /* Update component spacing */\r
+        updateContainerMargins();\r
+\r
+        /*\r
+         * Update component sizes for components with relative size in non-main\r
+         * direction\r
+         */\r
+        if (updateRelativeSizesInNonMainDirection()) {\r
+            // Sizes updated - might affect the other dimension so we need to\r
+            // recheck the widget sizes and recalculate layout dimensions\r
+            updateWidgetSizes();\r
+            layoutSizeMightHaveChanged();\r
+        }\r
+        calculateAlignments();\r
+        // w.mark("recalculateComponentSizesAndAlignments done");\r
+\r
+        setRootSize();\r
+\r
+        if (BrowserInfo.get().isIE()) {\r
+            /*\r
+             * This should fix the issue with padding not always taken into\r
+             * account for the containers leading to no spacing between\r
+             * elements.\r
+             */\r
+            root.getStyle().setProperty("zoom", "1");\r
+        }\r
+\r
+        // w.mark("runDescendentsLayout done");\r
+        isRendering = false;\r
+        sizeHasChangedDuringRendering = false;\r
+    }\r
+\r
+    private void layoutSizeMightHaveChanged() {\r
+        Size oldSize = new Size(activeLayoutSize.getWidth(), activeLayoutSize\r
+                .getHeight());\r
+        calculateLayoutDimensions();\r
+\r
+        /*\r
+         * If layout dimension changes we must also update container sizes\r
+         */\r
+        if (!oldSize.equals(activeLayoutSize)) {\r
+            calculateContainerSize();\r
+        }\r
+    }\r
+\r
+    private void updateWidgetSizes() {\r
+        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
+                .values()) {\r
+\r
+            /*\r
+             * Update widget size from DOM\r
+             */\r
+            childComponentContainer.updateWidgetSize();\r
+        }\r
+    }\r
+\r
+    private void recalculateLayout() {\r
+\r
+        /* Calculate space for relative size components */\r
+        int spaceForExpansion = calculateLayoutDimensions();\r
+\r
+        if (!widgetToComponentContainer.isEmpty()) {\r
+            /* Divide expansion space between component containers */\r
+            expandComponentContainers(spaceForExpansion);\r
+\r
+            /* Update container sizes */\r
+            calculateContainerSize();\r
+        }\r
+\r
+    }\r
+\r
+    private void expandComponentContainers(int spaceForExpansion) {\r
+        int remaining = spaceForExpansion;\r
+        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
+                .values()) {\r
+            remaining -= childComponentContainer.expand(orientation,\r
+                    spaceForExpansion);\r
+        }\r
+\r
+        if (remaining > 0) {\r
+            // Some left-over pixels due to rounding errors\r
+\r
+            // Add one pixel to each container until there are no pixels left\r
+\r
+            Iterator<Widget> widgetIterator = iterator();\r
+            while (widgetIterator.hasNext() && remaining-- > 0) {\r
+                ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator\r
+                        .next();\r
+                childComponentContainer.expandExtra(orientation, 1);\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    private void handleOrientationUpdate(UIDL uidl) {\r
+        int newOrientation = ORIENTATION_VERTICAL;\r
+        if ("horizontal".equals(uidl.getStringAttribute("orientation"))) {\r
+            newOrientation = ORIENTATION_HORIZONTAL;\r
+        }\r
+\r
+        if (orientation != newOrientation) {\r
+            orientation = newOrientation;\r
+\r
+            for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
+                    .values()) {\r
+                childComponentContainer.setOrientation(orientation);\r
+            }\r
+        }\r
+\r
+    }\r
+\r
+    /**\r
+     * Updated components with relative height in horizontal layouts and\r
+     * components with relative width in vertical layouts. This is only needed\r
+     * if the height (horizontal layout) or width (vertical layout) has not been\r
+     * specified.\r
+     */\r
+    private boolean updateRelativeSizesInNonMainDirection() {\r
+        int updateDirection = 1 - orientation;\r
+        if ((updateDirection == ORIENTATION_HORIZONTAL && !isDynamicWidth())\r
+                || (updateDirection == ORIENTATION_VERTICAL && !isDynamicHeight())) {\r
+            return false;\r
+        }\r
+\r
+        boolean updated = false;\r
+        for (ChildComponentContainer componentContainer : widgetToComponentContainer\r
+                .values()) {\r
+            if (componentContainer.isComponentRelativeSized(updateDirection)) {\r
+                client.handleComponentRelativeSize(componentContainer\r
+                        .getWidget());\r
+            }\r
+\r
+            updated = true;\r
+        }\r
+\r
+        return updated;\r
+    }\r
+\r
+    private int calculateLayoutDimensions() {\r
+        int summedWidgetWidth = 0;\r
+        int summedWidgetHeight = 0;\r
+\r
+        int maxWidgetWidth = 0;\r
+        int maxWidgetHeight = 0;\r
+\r
+        // Calculate layout dimensions from component dimensions\r
+        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
+                .values()) {\r
+\r
+            int widgetHeight = 0;\r
+            int widgetWidth = 0;\r
+            if (childComponentContainer.isComponentRelativeSized(orientation)) {\r
+                if (orientation == ORIENTATION_HORIZONTAL) {\r
+                    widgetHeight = getWidgetHeight(childComponentContainer);\r
+                } else {\r
+                    widgetWidth = getWidgetWidth(childComponentContainer);\r
+                }\r
+            } else {\r
+                widgetWidth = getWidgetWidth(childComponentContainer);\r
+                widgetHeight = getWidgetHeight(childComponentContainer);\r
+            }\r
+\r
+            summedWidgetWidth += widgetWidth;\r
+            summedWidgetHeight += widgetHeight;\r
+\r
+            maxWidgetHeight = Math.max(maxWidgetHeight, widgetHeight);\r
+            maxWidgetWidth = Math.max(maxWidgetWidth, widgetWidth);\r
+        }\r
+\r
+        if (isHorizontal()) {\r
+            summedWidgetWidth += activeSpacing.hSpacing\r
+                    * (widgetToComponentContainer.size() - 1);\r
+        } else {\r
+            summedWidgetHeight += activeSpacing.vSpacing\r
+                    * (widgetToComponentContainer.size() - 1);\r
+        }\r
+\r
+        Size layoutSize = updateLayoutDimensions(summedWidgetWidth,\r
+                summedWidgetHeight, maxWidgetWidth, maxWidgetHeight);\r
+\r
+        int remainingSpace;\r
+        if (isHorizontal()) {\r
+            remainingSpace = layoutSize.getWidth() - summedWidgetWidth;\r
+        } else {\r
+            remainingSpace = layoutSize.getHeight() - summedWidgetHeight;\r
+        }\r
+        if (remainingSpace < 0) {\r
+            remainingSpace = 0;\r
+        }\r
+\r
+        // ApplicationConnection.getConsole().log(\r
+        // "Layout size: " + activeLayoutSize);\r
+        return remainingSpace;\r
+    }\r
+\r
+    private int getWidgetHeight(ChildComponentContainer childComponentContainer) {\r
+        Size s = childComponentContainer.getWidgetSize();\r
+        return s.getHeight()\r
+                + childComponentContainer.getCaptionHeightAboveComponent();\r
+    }\r
+\r
+    private int getWidgetWidth(ChildComponentContainer childComponentContainer) {\r
+        Size s = childComponentContainer.getWidgetSize();\r
+        int widgetWidth = s.getWidth()\r
+                + childComponentContainer.getCaptionWidthAfterComponent();\r
+\r
+        /*\r
+         * If the component does not have a specified size in the main direction\r
+         * the caption may determine the space used by the component\r
+         */\r
+        if (!childComponentContainer.widgetHasSizeSpecified(orientation)) {\r
+            int captionWidth = childComponentContainer\r
+                    .getCaptionRequiredWidth();\r
+\r
+            if (captionWidth > widgetWidth) {\r
+                widgetWidth = captionWidth;\r
+            }\r
+        }\r
+\r
+        return widgetWidth;\r
+    }\r
+\r
+    private void calculateAlignments() {\r
+        int w = 0;\r
+        int h = 0;\r
+\r
+        if (isHorizontal()) {\r
+            // HORIZONTAL\r
+            h = activeLayoutSize.getHeight();\r
+            if (!isDynamicWidth()) {\r
+                w = -1;\r
+            }\r
+\r
+        } else {\r
+            // VERTICAL\r
+            w = activeLayoutSize.getWidth();\r
+            if (!isDynamicHeight()) {\r
+                h = -1;\r
+            }\r
+        }\r
+\r
+        for (ChildComponentContainer childComponentContainer : widgetToComponentContainer\r
+                .values()) {\r
+            childComponentContainer.updateAlignments(w, h);\r
+        }\r
+\r
+    }\r
+\r
+    private void calculateContainerSize() {\r
+\r
+        /*\r
+         * Container size here means the size the container gets from the\r
+         * component. The expansion size is not include in this but taken\r
+         * separately into account.\r
+         */\r
+        int height = 0, width = 0;\r
+        Iterator<Widget> widgetIterator = iterator();\r
+        if (isHorizontal()) {\r
+            height = activeLayoutSize.getHeight();\r
+            int availableWidth = activeLayoutSize.getWidth();\r
+            boolean first = true;\r
+            while (widgetIterator.hasNext()) {\r
+                ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator\r
+                        .next();\r
+                if (!childComponentContainer\r
+                        .isComponentRelativeSized(ORIENTATION_HORIZONTAL)) {\r
+                    /*\r
+                     * Only components with non-relative size in the main\r
+                     * direction has a container size\r
+                     */\r
+                    width = childComponentContainer.getWidgetSize().getWidth()\r
+                            + childComponentContainer\r
+                                    .getCaptionWidthAfterComponent();\r
+\r
+                    /*\r
+                     * If the component does not have a specified size in the\r
+                     * main direction the caption may determine the space used\r
+                     * by the component\r
+                     */\r
+                    if (!childComponentContainer\r
+                            .widgetHasSizeSpecified(orientation)) {\r
+                        int captionWidth = childComponentContainer\r
+                                .getCaptionRequiredWidth();\r
+                        // ApplicationConnection.getConsole().log(\r
+                        // "Component width: " + width\r
+                        // + ", caption width: " + captionWidth);\r
+                        if (captionWidth > width) {\r
+                            width = captionWidth;\r
+                        }\r
+                    }\r
+                } else {\r
+                    width = 0;\r
+                }\r
+\r
+                if (!isDynamicWidth()) {\r
+                    if (availableWidth == 0) {\r
+                        /*\r
+                         * Let the overflowing components overflow. IE has\r
+                         * problems with zero sizes.\r
+                         */\r
+                        // width = 0;\r
+                        // height = 0;\r
+                    } else if (width > availableWidth) {\r
+                        width = availableWidth;\r
+\r
+                        if (!first) {\r
+                            width -= activeSpacing.hSpacing;\r
+                        }\r
+                        availableWidth = 0;\r
+                    } else {\r
+                        availableWidth -= width;\r
+                        if (!first) {\r
+                            availableWidth -= activeSpacing.hSpacing;\r
+                        }\r
+                    }\r
+\r
+                    first = false;\r
+                }\r
+\r
+                childComponentContainer.setContainerSize(width, height);\r
+            }\r
+        } else {\r
+            width = activeLayoutSize.getWidth();\r
+            while (widgetIterator.hasNext()) {\r
+                ChildComponentContainer childComponentContainer = (ChildComponentContainer) widgetIterator\r
+                        .next();\r
+\r
+                if (!childComponentContainer\r
+                        .isComponentRelativeSized(ORIENTATION_VERTICAL)) {\r
+                    /*\r
+                     * Only components with non-relative size in the main\r
+                     * direction has a container size\r
+                     */\r
+                    height = childComponentContainer.getWidgetSize()\r
+                            .getHeight()\r
+                            + childComponentContainer\r
+                                    .getCaptionHeightAboveComponent();\r
+                } else {\r
+                    height = 0;\r
+                }\r
+\r
+                childComponentContainer.setContainerSize(width, height);\r
+            }\r
+\r
+        }\r
+\r
+    }\r
+\r
+    private Size updateLayoutDimensions(int totalComponentWidth,\r
+            int totalComponentHeight, int maxComponentWidth,\r
+            int maxComponentHeight) {\r
+\r
+        /* Only need to calculate dynamic dimensions */\r
+        if (!isDynamicHeight() && !isDynamicWidth()) {\r
+            return activeLayoutSize;\r
+        }\r
+\r
+        int activeLayoutWidth = 0;\r
+        int activeLayoutHeight = 0;\r
+\r
+        // Update layout dimensions\r
+        if (isHorizontal()) {\r
+            // Horizontal\r
+            if (isDynamicWidth()) {\r
+                activeLayoutWidth = totalComponentWidth;\r
+            }\r
+\r
+            if (isDynamicHeight()) {\r
+                activeLayoutHeight = maxComponentHeight;\r
+            }\r
+\r
+        } else {\r
+            // Vertical\r
+            if (isDynamicWidth()) {\r
+                activeLayoutWidth = maxComponentWidth;\r
+            }\r
+\r
+            if (isDynamicHeight()) {\r
+                activeLayoutHeight = totalComponentHeight;\r
+            }\r
+        }\r
+\r
+        if (isDynamicWidth()) {\r
+            setActiveLayoutWidth(activeLayoutWidth);\r
+            setOuterLayoutWidth(activeLayoutSize.getWidth());\r
+        }\r
+\r
+        if (isDynamicHeight()) {\r
+            setActiveLayoutHeight(activeLayoutHeight);\r
+            setOuterLayoutHeight(activeLayoutSize.getHeight());\r
+        }\r
+\r
+        return activeLayoutSize;\r
+    }\r
+\r
+    private void setActiveLayoutWidth(int activeLayoutWidth) {\r
+        if (activeLayoutWidth < 0) {\r
+            activeLayoutWidth = 0;\r
+        }\r
+        activeLayoutSize.setWidth(activeLayoutWidth);\r
+    }\r
+\r
+    private void setActiveLayoutHeight(int activeLayoutHeight) {\r
+        if (activeLayoutHeight < 0) {\r
+            activeLayoutHeight = 0;\r
+        }\r
+        activeLayoutSize.setHeight(activeLayoutHeight);\r
+\r
+    }\r
+\r
+    private void setOuterLayoutWidth(int activeLayoutWidth) {\r
+        super.setWidth((activeLayoutWidth + activeMargins.getHorizontal())\r
+                + "px");\r
+\r
+    }\r
+\r
+    private void setOuterLayoutHeight(int activeLayoutHeight) {\r
+        super.setHeight((activeLayoutHeight + activeMargins.getVertical())\r
+                + "px");\r
+\r
+    }\r
+\r
+    /**\r
+     * Updates the spacing between components. Needs to be done only when\r
+     * components are added/removed.\r
+     */\r
+    private void updateContainerMargins() {\r
+        ChildComponentContainer firstChildComponent = getFirstChildComponentContainer();\r
+        if (firstChildComponent != null) {\r
+            firstChildComponent.setMarginLeft(0);\r
+            firstChildComponent.setMarginTop(0);\r
+\r
+            for (ChildComponentContainer childComponent : widgetToComponentContainer\r
+                    .values()) {\r
+                if (childComponent == firstChildComponent) {\r
+                    continue;\r
+                }\r
+\r
+                if (isHorizontal()) {\r
+                    childComponent.setMarginLeft(activeSpacing.hSpacing);\r
+                } else {\r
+                    childComponent.setMarginTop(activeSpacing.vSpacing);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    private boolean isHorizontal() {\r
+        return orientation == ORIENTATION_HORIZONTAL;\r
+    }\r
+\r
+    private boolean isVertical() {\r
+        return orientation == ORIENTATION_VERTICAL;\r
+    }\r
+\r
+    private ChildComponentContainer createChildContainer(Widget child) {\r
+\r
+        // Create a container DIV for the child\r
+        ChildComponentContainer childComponent = new ChildComponentContainer(\r
+                child, orientation);\r
+\r
+        return childComponent;\r
+\r
+    }\r
+\r
+    public RenderSpace getAllocatedSpace(Widget child) {\r
+        int width = 0;\r
+        int height = 0;\r
+        ChildComponentContainer childComponentContainer = getComponentContainer(child);\r
+        // WIDTH CALCULATION\r
+        if (isVertical()) {\r
+            width = activeLayoutSize.getWidth();\r
+            width -= childComponentContainer.getCaptionWidthAfterComponent();\r
+        } else if (!isDynamicWidth()) {\r
+            // HORIZONTAL\r
+            width = childComponentContainer.getContSize().getWidth();\r
+            width -= childComponentContainer.getCaptionWidthAfterComponent();\r
+        }\r
+\r
+        // HEIGHT CALCULATION\r
+        if (isHorizontal()) {\r
+            height = activeLayoutSize.getHeight();\r
+            height -= childComponentContainer.getCaptionHeightAboveComponent();\r
+        } else if (!isDynamicHeight()) {\r
+            // VERTICAL\r
+            height = childComponentContainer.getContSize().getHeight();\r
+            height -= childComponentContainer.getCaptionHeightAboveComponent();\r
+        }\r
+\r
+        // ApplicationConnection.getConsole().log(\r
+        // "allocatedSpace for " + Util.getSimpleName(child) + ": "\r
+        // + width + "," + height);\r
+        RenderSpace space = new RenderSpace(width, height);\r
+        return space;\r
+    }\r
+\r
+    private void recalculateLayoutAndComponentSizes() {\r
+        recalculateLayout();\r
+\r
+        if (!(isDynamicHeight() && isDynamicWidth())) {\r
+            /* First update relative sized components */\r
+            for (ChildComponentContainer componentContainer : widgetToComponentContainer\r
+                    .values()) {\r
+                client.handleComponentRelativeSize(componentContainer\r
+                        .getWidget());\r
+\r
+                // Update widget size from DOM\r
+                componentContainer.updateWidgetSize();\r
+            }\r
+        }\r
+\r
+        if (isDynamicHeight()) {\r
+            /*\r
+             * Height is not necessarily correct anymore as the height of\r
+             * components might have changed if the width has changed.\r
+             */\r
+\r
+            /*\r
+             * Get the new widget sizes from DOM and calculate new container\r
+             * sizes\r
+             */\r
+            updateWidgetSizes();\r
+\r
+            /* Update layout dimensions based on widget sizes */\r
+            recalculateLayout();\r
+        }\r
+\r
+        updateRelativeSizesInNonMainDirection();\r
+        calculateAlignments();\r
+\r
+        setRootSize();\r
+    }\r
+\r
+    private void setRootSize() {\r
+        root.getStyle().setPropertyPx("width", activeLayoutSize.getWidth());\r
+        root.getStyle().setPropertyPx("height", activeLayoutSize.getHeight());\r
+    }\r
+\r
+    public boolean requestLayout(Set<Paintable> children) {\r
+        for (Paintable p : children) {\r
+            /* Update widget size from DOM */\r
+            ChildComponentContainer componentContainer = getComponentContainer((Widget) p);\r
+            // This should no longer be needed (after #2563)\r
+            // if (isDynamicWidth()) {\r
+            // componentContainer.setUnlimitedContainerWidth();\r
+            // } else {\r
+            // componentContainer.setLimitedContainerWidth(activeLayoutSize\r
+            // .getWidth());\r
+            // }\r
+\r
+            componentContainer.updateWidgetSize();\r
+\r
+            /*\r
+             * If this is the result of an caption icon onload event the caption\r
+             * size may have changed\r
+             */\r
+            componentContainer.updateCaptionSize();\r
+        }\r
+\r
+        Size sizeBefore = new Size(activeLayoutSize.getWidth(),\r
+                activeLayoutSize.getHeight());\r
+\r
+        recalculateLayoutAndComponentSizes();\r
+        boolean sameSize = (sizeBefore.equals(activeLayoutSize));\r
+        if (!sameSize) {\r
+            /* Must inform child components about possible size updates */\r
+            client.runDescendentsLayout(this);\r
+        }\r
+\r
+        /* Automatically propagated upwards if the size has changed */\r
+\r
+        return sameSize;\r
+    }\r
+\r
+    @Override\r
+    public void setHeight(String height) {\r
+        Size sizeBefore = new Size(activeLayoutSize.getWidth(),\r
+                activeLayoutSize.getHeight());\r
+\r
+        super.setHeight(height);\r
+\r
+        if (height != null && !height.equals("")) {\r
+            setActiveLayoutHeight(getOffsetHeight()\r
+                    - activeMargins.getVertical());\r
+        }\r
+\r
+        if (isRendering) {\r
+            sizeHasChangedDuringRendering = true;\r
+        } else {\r
+            recalculateLayoutAndComponentSizes();\r
+            boolean sameSize = (sizeBefore.equals(activeLayoutSize));\r
+            if (!sameSize) {\r
+                /* Must inform child components about possible size updates */\r
+                client.runDescendentsLayout(this);\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void setWidth(String width) {\r
+        if (this.width.equals(width)) {\r
+            return;\r
+        }\r
+        Size sizeBefore = new Size(activeLayoutSize.getWidth(),\r
+                activeLayoutSize.getHeight());\r
+\r
+        super.setWidth(width);\r
+        this.width = width;\r
+        if (width != null && !width.equals("")) {\r
+            setActiveLayoutWidth(getOffsetWidth()\r
+                    - activeMargins.getHorizontal());\r
+        }\r
+\r
+        if (isRendering) {\r
+            sizeHasChangedDuringRendering = true;\r
+        } else {\r
+            recalculateLayoutAndComponentSizes();\r
+            boolean sameSize = (sizeBefore.equals(activeLayoutSize));\r
+            if (!sameSize) {\r
+                /* Must inform child components about possible size updates */\r
+                client.runDescendentsLayout(this);\r
+            }\r
+            /*\r
+             * If the height changes as a consequence of this we must inform the\r
+             * parent also\r
+             */\r
+            if (isDynamicHeight()\r
+                    && sizeBefore.getHeight() != activeLayoutSize.getHeight()) {\r
+                Util.notifyParentOfSizeChange(this, false);\r
+            }\r
+\r
+        }\r
+    }\r
+\r
+    protected void updateAlignmentsAndExpandRatios(UIDL uidl,\r
+            ArrayList<Widget> renderedWidgets) {\r
+\r
+        /*\r
+         * UIDL contains component alignments as a comma separated list.\r
+         * \r
+         * See com.vaadin.terminal.gwt.client.ui.AlignmentInfo.java for\r
+         * possible values.\r
+         */\r
+        final int[] alignments = uidl.getIntArrayAttribute("alignments");\r
+\r
+        /*\r
+         * UIDL contains normalized expand ratios as a comma separated list.\r
+         */\r
+        final int[] expandRatios = uidl.getIntArrayAttribute("expandRatios");\r
+\r
+        for (int i = 0; i < renderedWidgets.size(); i++) {\r
+            Widget widget = renderedWidgets.get(i);\r
+\r
+            ChildComponentContainer container = getComponentContainer(widget);\r
+\r
+            // Calculate alignment info\r
+            container.setAlignment(new AlignmentInfo(alignments[i]));\r
+\r
+            // Update expand ratio\r
+            container.setExpandRatio(expandRatios[i]);\r
+        }\r
+    }\r
+\r
+    public void updateCaption(Paintable component, UIDL uidl) {\r
+        ChildComponentContainer componentContainer = getComponentContainer((Widget) component);\r
+        componentContainer.updateCaption(uidl, client);\r
+        if (!isRendering) {\r
+            /*\r
+             * This was a component-only update and the possible size change\r
+             * must be propagated to the layout\r
+             */\r
+            client.captionSizeUpdated(component);\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VPanel.java
new file mode 100644 (file)
index 0000000..e146eb7
--- /dev/null
@@ -0,0 +1,516 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Set;
+
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderInformation;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VPanel extends SimplePanel implements Container {
+
+    public static final String CLASSNAME = "i-panel";
+
+    ApplicationConnection client;
+
+    String id;
+
+    private final Element captionNode = DOM.createDiv();
+
+    private final Element captionText = DOM.createSpan();
+
+    private Icon icon;
+
+    private final Element bottomDecoration = DOM.createDiv();
+
+    private final Element contentNode = DOM.createDiv();
+
+    private Element errorIndicatorElement;
+
+    private String height;
+
+    private Paintable layout;
+
+    ShortcutActionHandler shortcutHandler;
+
+    private String width = "";
+
+    private Element geckoCaptionMeter;
+
+    private int scrollTop;
+
+    private int scrollLeft;
+
+    private RenderInformation renderInformation = new RenderInformation();
+
+    private int borderPaddingHorizontal = -1;
+
+    private int borderPaddingVertical = -1;
+
+    private int captionPaddingHorizontal = -1;
+
+    private int captionMarginLeft = -1;
+
+    private boolean rendering;
+
+    private int contentMarginLeft = -1;
+
+    private String previousStyleName;
+
+    public VPanel() {
+        super();
+        DivElement captionWrap = Document.get().createDivElement();
+        captionWrap.appendChild(captionNode);
+        captionNode.appendChild(captionText);
+
+        captionWrap.setClassName(CLASSNAME + "-captionwrap");
+        captionNode.setClassName(CLASSNAME + "-caption");
+        contentNode.setClassName(CLASSNAME + "-content");
+        bottomDecoration.setClassName(CLASSNAME + "-deco");
+
+        getElement().appendChild(captionWrap);
+        getElement().appendChild(contentNode);
+        getElement().appendChild(bottomDecoration);
+        setStyleName(CLASSNAME);
+        DOM.sinkEvents(getElement(), Event.ONKEYDOWN);
+        DOM.sinkEvents(contentNode, Event.ONSCROLL);
+        contentNode.getStyle().setProperty("position", "relative");
+        getElement().getStyle().setProperty("overflow", "hidden");
+    }
+
+    @Override
+    protected Element getContainerElement() {
+        return contentNode;
+    }
+
+    private void setCaption(String text) {
+        DOM.setInnerHTML(captionText, text);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+        if (!uidl.hasAttribute("cached")) {
+            // Handle caption displaying and style names, prior generics.
+            // Affects size
+            // calculations
+
+            // Restore default stylenames
+            contentNode.setClassName(CLASSNAME + "-content");
+            bottomDecoration.setClassName(CLASSNAME + "-deco");
+            captionNode.setClassName(CLASSNAME + "-caption");
+            boolean hasCaption = false;
+            if (uidl.hasAttribute("caption")
+                    && !uidl.getStringAttribute("caption").equals("")) {
+                setCaption(uidl.getStringAttribute("caption"));
+                hasCaption = true;
+            } else {
+                setCaption("");
+                captionNode.setClassName(CLASSNAME + "-nocaption");
+            }
+
+            // Add proper stylenames for all elements. This way we can prevent
+            // unwanted CSS selector inheritance.
+            if (uidl.hasAttribute("style")) {
+                final String[] styles = uidl.getStringAttribute("style").split(
+                        " ");
+                final String captionBaseClass = CLASSNAME
+                        + (hasCaption ? "-caption" : "-nocaption");
+                final String contentBaseClass = CLASSNAME + "-content";
+                final String decoBaseClass = CLASSNAME + "-deco";
+                String captionClass = captionBaseClass;
+                String contentClass = contentBaseClass;
+                String decoClass = decoBaseClass;
+                for (int i = 0; i < styles.length; i++) {
+                    captionClass += " " + captionBaseClass + "-" + styles[i];
+                    contentClass += " " + contentBaseClass + "-" + styles[i];
+                    decoClass += " " + decoBaseClass + "-" + styles[i];
+                }
+                captionNode.setClassName(captionClass);
+                contentNode.setClassName(contentClass);
+                bottomDecoration.setClassName(decoClass);
+
+            }
+        }
+        // Ensure correct implementation
+        if (client.updateComponent(this, uidl, false)) {
+            rendering = false;
+            return;
+        }
+
+        this.client = client;
+        id = uidl.getId();
+
+        setIconUri(uidl, client);
+
+        handleError(uidl);
+
+        // Render content
+        final UIDL layoutUidl = uidl.getChildUIDL(0);
+        final Paintable newLayout = client.getPaintable(layoutUidl);
+        if (newLayout != layout) {
+            if (layout != null) {
+                client.unregisterPaintable(layout);
+            }
+            setWidget((Widget) newLayout);
+            layout = newLayout;
+        }
+        layout.updateFromUIDL(layoutUidl, client);
+
+        runHacks(false);
+        // We may have actions attached to this panel
+        if (uidl.getChildCount() > 1) {
+            final int cnt = uidl.getChildCount();
+            for (int i = 1; i < cnt; i++) {
+                UIDL childUidl = uidl.getChildUIDL(i);
+                if (childUidl.getTag().equals("actions")) {
+                    if (shortcutHandler == null) {
+                        shortcutHandler = new ShortcutActionHandler(id, client);
+                    }
+                    shortcutHandler.updateActionMap(childUidl);
+                }
+            }
+        }
+
+        if (uidl.hasVariable("scrollTop")
+                && uidl.getIntVariable("scrollTop") != scrollTop) {
+            scrollTop = uidl.getIntVariable("scrollTop");
+            DOM.setElementPropertyInt(contentNode, "scrollTop", scrollTop);
+        }
+
+        if (uidl.hasVariable("scrollLeft")
+                && uidl.getIntVariable("scrollLeft") != scrollLeft) {
+            scrollLeft = uidl.getIntVariable("scrollLeft");
+            DOM.setElementPropertyInt(contentNode, "scrollLeft", scrollLeft);
+        }
+
+        rendering = false;
+
+    }
+
+    @Override
+    public void setStyleName(String style) {
+        if (!style.equals(previousStyleName)) {
+            super.setStyleName(style);
+            detectContainerBorders();
+            previousStyleName = style;
+        }
+    }
+
+    private void handleError(UIDL uidl) {
+        if (uidl.hasAttribute("error")) {
+            if (errorIndicatorElement == null) {
+                errorIndicatorElement = DOM.createDiv();
+                DOM.setElementProperty(errorIndicatorElement, "className",
+                        "i-errorindicator");
+                DOM.sinkEvents(errorIndicatorElement, Event.MOUSEEVENTS);
+                sinkEvents(Event.MOUSEEVENTS);
+            }
+            DOM.insertBefore(captionNode, errorIndicatorElement, captionText);
+        } else if (errorIndicatorElement != null) {
+            DOM.removeChild(captionNode, errorIndicatorElement);
+            errorIndicatorElement = null;
+        }
+    }
+
+    private void setIconUri(UIDL uidl, ApplicationConnection client) {
+        final String iconUri = uidl.hasAttribute("icon") ? uidl
+                .getStringAttribute("icon") : null;
+        if (iconUri == null) {
+            if (icon != null) {
+                DOM.removeChild(captionNode, icon.getElement());
+                icon = null;
+            }
+        } else {
+            if (icon == null) {
+                icon = new Icon(client);
+                DOM.insertChild(captionNode, icon.getElement(), 0);
+            }
+            icon.setUri(iconUri);
+        }
+    }
+
+    public void runHacks(boolean runGeckoFix) {
+        if (BrowserInfo.get().isIE6() && width != null && !width.equals("")) {
+            /*
+             * IE6 requires overflow-hidden elements to have a width specified
+             * so we calculate the width of the content and caption nodes when
+             * no width has been specified.
+             */
+            /*
+             * Fixes #1923 VPanel: Horizontal scrollbar does not appear in IE6
+             * with wide content
+             */
+
+            /*
+             * Caption must be shrunk for parent measurements to return correct
+             * result in IE6
+             */
+            DOM.setStyleAttribute(captionNode, "width", "1px");
+
+            int parentPadding = Util.measureHorizontalPaddingAndBorder(
+                    getElement(), 0);
+
+            int parentWidthExcludingPadding = getElement().getOffsetWidth()
+                    - parentPadding;
+
+            Util.setWidthExcludingPaddingAndBorder(captionNode,
+                    parentWidthExcludingPadding - getCaptionMarginLeft(), 26,
+                    false);
+
+            int contentMarginLeft = getContentMarginLeft();
+
+            Util.setWidthExcludingPaddingAndBorder(contentNode,
+                    parentWidthExcludingPadding - contentMarginLeft, 2, false);
+
+        }
+
+        if ((BrowserInfo.get().isIE() || BrowserInfo.get().isFF2())
+                && (width == null || width.equals(""))) {
+            /*
+             * IE and FF2 needs width to be specified for the root DIV so we
+             * calculate that from the sizes of the caption and layout
+             */
+            int captionWidth = captionText.getOffsetWidth()
+                    + getCaptionMarginLeft() + getCaptionPaddingHorizontal();
+            int layoutWidth = ((Widget) layout).getOffsetWidth()
+                    + getContainerBorderWidth();
+            int width = layoutWidth;
+            if (captionWidth > width) {
+                width = captionWidth;
+            }
+
+            if (BrowserInfo.get().isIE7()) {
+                Util.setWidthExcludingPaddingAndBorder(captionNode, width
+                        - getCaptionMarginLeft(), 26, false);
+            }
+
+            super.setWidth(width + "px");
+        }
+
+        if (runGeckoFix && BrowserInfo.get().isGecko()) {
+            // workaround for #1764
+            if (width == null || width.equals("")) {
+                if (geckoCaptionMeter == null) {
+                    geckoCaptionMeter = DOM.createDiv();
+                    DOM.appendChild(captionNode, geckoCaptionMeter);
+                }
+                int captionWidth = DOM.getElementPropertyInt(captionText,
+                        "offsetWidth");
+                int availWidth = DOM.getElementPropertyInt(geckoCaptionMeter,
+                        "offsetWidth");
+                if (captionWidth == availWidth) {
+                    /*
+                     * Caption width defines panel width -> Gecko based browsers
+                     * somehow fails to float things right, without the
+                     * "noncode" below
+                     */
+                    setWidth(getOffsetWidth() + "px");
+                } else {
+                    DOM.setStyleAttribute(captionNode, "width", "");
+                }
+            }
+        }
+
+        client.runDescendentsLayout(this);
+
+        Util.runWebkitOverflowAutoFix(contentNode);
+
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        final Element target = DOM.eventGetTarget(event);
+        final int type = DOM.eventGetType(event);
+        if (type == Event.ONKEYDOWN && shortcutHandler != null) {
+            shortcutHandler.handleKeyboardEvent(event);
+            return;
+        }
+        if (type == Event.ONSCROLL) {
+            int newscrollTop = DOM.getElementPropertyInt(contentNode,
+                    "scrollTop");
+            int newscrollLeft = DOM.getElementPropertyInt(contentNode,
+                    "scrollLeft");
+            if (client != null
+                    && (newscrollLeft != scrollLeft || newscrollTop != scrollTop)) {
+                scrollLeft = newscrollLeft;
+                scrollTop = newscrollTop;
+                client.updateVariable(id, "scrollTop", scrollTop, false);
+                client.updateVariable(id, "scrollLeft", scrollLeft, false);
+            }
+        } else if (captionNode.isOrHasChild(target)) {
+            if (client != null) {
+                client.handleTooltipEvent(event, this);
+            }
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        this.height = height;
+        super.setHeight(height);
+        if (height != null && height != "") {
+            final int targetHeight = getOffsetHeight();
+            int containerHeight = targetHeight - captionNode.getOffsetHeight()
+                    - bottomDecoration.getOffsetHeight()
+                    - getContainerBorderHeight();
+            if (containerHeight < 0) {
+                containerHeight = 0;
+            }
+            DOM
+                    .setStyleAttribute(contentNode, "height", containerHeight
+                            + "px");
+        } else {
+            DOM.setStyleAttribute(contentNode, "height", "");
+        }
+        if (!rendering) {
+            runHacks(true);
+        }
+    }
+
+    private int getCaptionMarginLeft() {
+        if (captionMarginLeft < 0) {
+            detectContainerBorders();
+        }
+        return captionMarginLeft;
+    }
+
+    private int getContentMarginLeft() {
+        if (contentMarginLeft < 0) {
+            detectContainerBorders();
+        }
+        return contentMarginLeft;
+    }
+
+    private int getCaptionPaddingHorizontal() {
+        if (captionPaddingHorizontal < 0) {
+            detectContainerBorders();
+        }
+        return captionPaddingHorizontal;
+    }
+
+    private int getContainerBorderHeight() {
+        if (borderPaddingVertical < 0) {
+            detectContainerBorders();
+        }
+        return borderPaddingVertical;
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (this.width.equals(width)) {
+            return;
+        }
+
+        this.width = width;
+        super.setWidth(width);
+        if (!rendering) {
+            runHacks(true);
+
+            if (height.equals("")) {
+                // Width change may affect height
+                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this);
+            }
+
+        }
+    }
+
+    private int getContainerBorderWidth() {
+        if (borderPaddingHorizontal < 0) {
+            detectContainerBorders();
+        }
+        return borderPaddingHorizontal;
+    }
+
+    private void detectContainerBorders() {
+        DOM.setStyleAttribute(contentNode, "overflow", "hidden");
+
+        borderPaddingHorizontal = Util.measureHorizontalBorder(contentNode);
+        borderPaddingVertical = Util.measureVerticalBorder(contentNode);
+
+        DOM.setStyleAttribute(contentNode, "overflow", "auto");
+
+        captionPaddingHorizontal = Util.measureHorizontalPaddingAndBorder(
+                captionNode, 26);
+
+        captionMarginLeft = Util.measureMarginLeft(captionNode);
+        contentMarginLeft = Util.measureMarginLeft(contentNode);
+
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (component != null && component == layout) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        // TODO This is untested as no layouts require this
+        if (oldComponent != layout) {
+            return;
+        }
+
+        setWidget(newComponent);
+        layout = (Paintable) newComponent;
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        int w = 0;
+        int h = 0;
+
+        if (width != null && !width.equals("")) {
+            w = getOffsetWidth() - getContainerBorderWidth();
+            if (w < 0) {
+                w = 0;
+            }
+        }
+
+        if (height != null && !height.equals("")) {
+            h = contentNode.getOffsetHeight() - getContainerBorderHeight();
+            if (h < 0) {
+                h = 0;
+            }
+        }
+
+        return new RenderSpace(w, h, true);
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        if (height != null && height != "" && width != null && width != "") {
+            /*
+             * If the height and width has been specified the child components
+             * cannot make the size of the layout change
+             */
+            return true;
+        }
+        runHacks(false);
+        return !renderInformation.updateSize(getElement());
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        // NOP: layouts caption, errors etc not rendered in Panel
+    }
+
+    @Override
+    protected void onAttach() {
+        super.onAttach();
+        detectContainerBorders();
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java b/src/com/vaadin/terminal/gwt/client/ui/VPasswordField.java
new file mode 100644 (file)
index 0000000..db863e4
--- /dev/null
@@ -0,0 +1,21 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.user.client.DOM;\r
+\r
+/**\r
+ * This class represents a password field.\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * \r
+ */\r
+public class VPasswordField extends VTextField {\r
+\r
+    public VPasswordField() {\r
+        super(DOM.createInputPassword());\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupCalendar.java
new file mode 100644 (file)
index 0000000..31004be
--- /dev/null
@@ -0,0 +1,130 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.user.client.DOM;\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.ClickListener;\r
+import com.google.gwt.user.client.ui.PopupListener;\r
+import com.google.gwt.user.client.ui.PopupPanel;\r
+import com.google.gwt.user.client.ui.Widget;\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.Paintable;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VPopupCalendar extends VTextualDate implements Paintable, Field,\r
+        ClickListener, PopupListener {\r
+\r
+    private final Button calendarToggle;\r
+\r
+    private final VCalendarPanel calendar;\r
+\r
+    private final VToolkitOverlay popup;\r
+    private boolean open = false;\r
+\r
+    public VPopupCalendar() {\r
+        super();\r
+\r
+        calendarToggle = new Button();\r
+        calendarToggle.setStyleName(CLASSNAME + "-button");\r
+        calendarToggle.setText("");\r
+        calendarToggle.addClickListener(this);\r
+        add(calendarToggle);\r
+\r
+        calendar = new VCalendarPanel(this);\r
+        popup = new VToolkitOverlay(true, true, true);\r
+        popup.setStyleName(VDateField.CLASSNAME + "-popup");\r
+        popup.setWidget(calendar);\r
+        popup.addPopupListener(this);\r
+\r
+        DOM.setElementProperty(calendar.getElement(), "id",\r
+                "PID_TOOLKIT_POPUPCAL");\r
+\r
+    }\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        super.updateFromUIDL(uidl, client);\r
+        if (date != null) {\r
+            calendar.updateCalendar();\r
+        }\r
+        calendarToggle.setEnabled(enabled);\r
+    }\r
+\r
+    public void onClick(Widget sender) {\r
+        if (sender == calendarToggle && !open) {\r
+            open = true;\r
+            calendar.updateCalendar();\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
+                    int t = calendarToggle.getAbsoluteTop();\r
+                    int l = calendarToggle.getAbsoluteLeft();\r
+                    if (l + w > Window.getClientWidth()\r
+                            + Window.getScrollLeft()) {\r
+                        l = Window.getClientWidth() + Window.getScrollLeft()\r
+                                - w;\r
+                    }\r
+                    if (t + h + calendarToggle.getOffsetHeight() + 30 > Window\r
+                            .getClientHeight()\r
+                            + Window.getScrollTop()) {\r
+                        t = Window.getClientHeight() + Window.getScrollTop()\r
+                                - h - calendarToggle.getOffsetHeight() - 30;\r
+                        l += calendarToggle.getOffsetWidth();\r
+                    }\r
+\r
+                    // fix size\r
+                    popup.setWidth(w + "px");\r
+                    popup.setHeight(h + "px");\r
+\r
+                    popup.setPopupPosition(l, t\r
+                            + calendarToggle.getOffsetHeight() + 2);\r
+\r
+                    setFocus(true);\r
+                }\r
+            });\r
+        }\r
+    }\r
+\r
+    public void onPopupClosed(PopupPanel sender, boolean autoClosed) {\r
+        if (sender == popup) {\r
+            buildDate();\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
+    @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
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java b/src/com/vaadin/terminal/gwt/client/ui/VPopupView.java
new file mode 100644 (file)
index 0000000..c890665
--- /dev/null
@@ -0,0 +1,417 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HasFocus;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.PopupListener;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.VCaptionWrapper;
+import com.vaadin.terminal.gwt.client.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.RenderInformation.Size;
+
+public class VPopupView extends HTML implements Container {
+
+    public static final String CLASSNAME = "i-popupview";
+
+    /** For server-client communication */
+    private String uidlId;
+    private ApplicationConnection client;
+
+    /** This variable helps to communicate popup visibility to the server */
+    private boolean hostPopupVisible;
+
+    private final CustomPopup popup;
+    private final Label loading = new Label("Loading...");
+
+    /**
+     * loading constructor
+     */
+    public VPopupView() {
+        super();
+        popup = new CustomPopup();
+
+        setStyleName(CLASSNAME);
+        popup.setStylePrimaryName(CLASSNAME + "-popup");
+
+        setHTML("(No HTML defined for PopupView)");
+        popup.setWidget(loading);
+
+        // When we click to open the popup...
+        addClickListener(new ClickListener() {
+            public void onClick(Widget sender) {
+                updateState(true);
+            }
+        });
+
+        // ..and when we close it
+        popup.addPopupListener(new PopupListener() {
+            public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+                updateState(false);
+            }
+        });
+
+        popup.setAnimationEnabled(true);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+    }
+
+    /**
+     * 
+     * 
+     * @see com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal.gwt.client.UIDL,
+     *      com.vaadin.terminal.gwt.client.ApplicationConnection)
+     */
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // This call should be made first. Ensure correct implementation,
+        // and don't let the containing layout manage caption.
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+        // These are for future server connections
+        this.client = client;
+        uidlId = uidl.getId();
+
+        hostPopupVisible = uidl.getBooleanVariable("popupVisibility");
+
+        setHTML(uidl.getStringAttribute("html"));
+
+        if (uidl.hasAttribute("hideOnMouseOut")) {
+            popup.setHideOnMouseOut(uidl.getBooleanAttribute("hideOnMouseOut"));
+        }
+
+        // Render the popup if visible and show it.
+        if (hostPopupVisible) {
+            UIDL popupUIDL = uidl.getChildUIDL(0);
+
+            // showPopupOnTop(popup, hostReference);
+            preparePopup(popup);
+            popup.updateFromUIDL(popupUIDL, client);
+            if (uidl.hasAttribute("style")) {
+                final String[] styles = uidl.getStringAttribute("style").split(
+                        " ");
+                final StringBuffer styleBuf = new StringBuffer();
+                final String primaryName = popup.getStylePrimaryName();
+                styleBuf.append(primaryName);
+                for (int i = 0; i < styles.length; i++) {
+                    styleBuf.append(" ");
+                    styleBuf.append(primaryName);
+                    styleBuf.append("-");
+                    styleBuf.append(styles[i]);
+                }
+                popup.setStyleName(styleBuf.toString());
+            } else {
+                popup.setStyleName(popup.getStylePrimaryName());
+            }
+            showPopup(popup);
+
+            // The popup shouldn't be visible, try to hide it.
+        } else {
+            popup.hide();
+        }
+    }// updateFromUIDL
+
+    /**
+     * Update popup visibility to server
+     * 
+     * @param visibility
+     */
+    private void updateState(boolean visible) {
+        // If we know the server connection
+        // then update the current situation
+        if (uidlId != null && client != null && isAttached()) {
+            client.updateVariable(uidlId, "popupVisibility", visible, true);
+        }
+    }
+
+    private void preparePopup(final CustomPopup popup) {
+        popup.setVisible(false);
+        popup.show();
+    }
+
+    private void showPopup(final CustomPopup popup) {
+        int windowTop = RootPanel.get().getAbsoluteTop();
+        int windowLeft = RootPanel.get().getAbsoluteLeft();
+        int windowRight = windowLeft + RootPanel.get().getOffsetWidth();
+        int windowBottom = windowTop + RootPanel.get().getOffsetHeight();
+
+        int offsetWidth = popup.getOffsetWidth();
+        int offsetHeight = popup.getOffsetHeight();
+
+        int hostHorizontalCenter = VPopupView.this.getAbsoluteLeft()
+                + VPopupView.this.getOffsetWidth() / 2;
+        int hostVerticalCenter = VPopupView.this.getAbsoluteTop()
+                + VPopupView.this.getOffsetHeight() / 2;
+
+        int left = hostHorizontalCenter - offsetWidth / 2;
+        int top = hostVerticalCenter - offsetHeight / 2;
+
+        // Superclass takes care of top and left
+        if ((left + offsetWidth) > windowRight) {
+            left -= (left + offsetWidth) - windowRight;
+        }
+
+        if ((top + offsetHeight) > windowBottom) {
+            top -= (top + offsetHeight) - windowBottom;
+        }
+
+        popup.setPopupPosition(left, top);
+
+        popup.setVisible(true);
+    }
+
+    /**
+     * Make sure that we remove the popup when the main widget is removed.
+     * 
+     * @see com.google.gwt.user.client.ui.Widget#onUnload()
+     */
+    @Override
+    protected void onDetach() {
+        popup.hide();
+        super.onDetach();
+    }
+
+    private static native void nativeBlur(Element e)
+    /*-{ 
+        if(e && e.blur) {
+            e.blur();
+        }
+    }-*/;
+
+    private class CustomPopup extends VToolkitOverlay {
+
+        private Paintable popupComponentPaintable = null;
+        private Widget popupComponentWidget = null;
+        private VCaptionWrapper captionWrapper = null;
+
+        private boolean hasHadMouseOver = false;
+        private boolean hideOnMouseOut = true;
+        private final Set<Element> activeChildren = new HashSet<Element>();
+        private boolean hiding = false;
+
+        public CustomPopup() {
+            super(true, false, true); // autoHide, not modal, dropshadow
+        }
+
+        // For some reason ONMOUSEOUT events are not always received, so we have
+        // to use ONMOUSEMOVE that doesn't target the popup
+        @Override
+        public boolean onEventPreview(Event event) {
+            Element target = DOM.eventGetTarget(event);
+            boolean eventTargetsPopup = DOM.isOrHasChild(getElement(), target);
+            int type = DOM.eventGetType(event);
+
+            // Catch children that use keyboard, so we can unfocus them when
+            // hiding
+            if (eventTargetsPopup && type == Event.ONKEYPRESS) {
+                activeChildren.add(target);
+            }
+
+            if (eventTargetsPopup && type == Event.ONMOUSEMOVE) {
+                hasHadMouseOver = true;
+            }
+
+            if (!eventTargetsPopup && type == Event.ONMOUSEMOVE) {
+
+                if (hasHadMouseOver && hideOnMouseOut) {
+                    hide();
+                    return true;
+                }
+            }
+
+            return super.onEventPreview(event);
+        }
+
+        @Override
+        public void hide(boolean autoClosed) {
+            hiding = true;
+            syncChildren();
+            unregisterPaintables();
+            if (popupComponentWidget != null && popupComponentWidget != loading) {
+                remove(popupComponentWidget);
+            }
+            hasHadMouseOver = false;
+            super.hide(autoClosed);
+        }
+
+        @Override
+        public void show() {
+            hiding = false;
+            super.show();
+        }
+
+        /**
+         * Try to sync all known active child widgets to server
+         */
+        public void syncChildren() {
+            // Notify children with focus
+            if ((popupComponentWidget instanceof HasFocus)) {
+                ((HasFocus) popupComponentWidget).setFocus(false);
+            }
+
+            // Notify children that have used the keyboard
+            for (Element e : activeChildren) {
+                try {
+                    nativeBlur(e);
+                } catch (Exception ignored) {
+                }
+            }
+            activeChildren.clear();
+        }
+
+        @Override
+        public boolean remove(Widget w) {
+
+            popupComponentPaintable = null;
+            popupComponentWidget = null;
+            captionWrapper = null;
+
+            return super.remove(w);
+        }
+
+        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+
+            Paintable newPopupComponent = client.getPaintable(uidl
+                    .getChildUIDL(0));
+
+            if (newPopupComponent != popupComponentPaintable) {
+
+                setWidget((Widget) newPopupComponent);
+
+                popupComponentWidget = (Widget) newPopupComponent;
+
+                popupComponentPaintable = newPopupComponent;
+            }
+
+            popupComponentPaintable
+                    .updateFromUIDL(uidl.getChildUIDL(0), client);
+
+        }
+
+        public void unregisterPaintables() {
+            if (popupComponentPaintable != null) {
+                client.unregisterPaintable(popupComponentPaintable);
+            }
+        }
+
+        public void setHideOnMouseOut(boolean hideOnMouseOut) {
+            this.hideOnMouseOut = hideOnMouseOut;
+        }
+
+        /*
+         * 
+         * We need a hack make popup act as a child of VPopupView in toolkits
+         * component tree, but work in default GWT manner when closing or
+         * opening.
+         * 
+         * (non-Javadoc)
+         * 
+         * @see com.google.gwt.user.client.ui.Widget#getParent()
+         */
+        @Override
+        public Widget getParent() {
+            if (!isAttached() || hiding) {
+                return super.getParent();
+            } else {
+                return VPopupView.this;
+            }
+        }
+
+        @Override
+        protected void onDetach() {
+            super.onDetach();
+            hiding = false;
+        }
+
+        @Override
+        public Element getContainerElement() {
+            return super.getContainerElement();
+        }
+
+    }// class CustomPopup
+
+    // Container methods
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        Size popupExtra = calculatePopupExtra();
+
+        return new RenderSpace(RootPanel.get().getOffsetWidth()
+                - popupExtra.getWidth(), RootPanel.get().getOffsetHeight()
+                - popupExtra.getHeight());
+    }
+
+    /**
+     * Calculate extra space taken by the popup decorations
+     * 
+     * @return
+     */
+    protected Size calculatePopupExtra() {
+        Element pe = popup.getElement();
+        Element ipe = popup.getContainerElement();
+
+        // border + padding
+        int width = Util.getRequiredWidth(pe) - Util.getRequiredWidth(ipe);
+        int height = Util.getRequiredHeight(pe) - Util.getRequiredHeight(ipe);
+
+        return new Size(width, height);
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (popup.popupComponentWidget != null) {
+            return popup.popupComponentWidget == component;
+        } else {
+            return false;
+        }
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        popup.setWidget(newComponent);
+        popup.popupComponentWidget = newComponent;
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        return true;
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        if (VCaption.isNeeded(uidl)) {
+            if (popup.captionWrapper != null) {
+                popup.captionWrapper.updateCaption(uidl);
+            } else {
+                popup.captionWrapper = new VCaptionWrapper(component, client);
+                popup.setWidget(popup.captionWrapper);
+                popup.captionWrapper.updateCaption(uidl);
+            }
+        } else {
+            if (popup.captionWrapper != null) {
+                popup.setWidget(popup.popupComponentWidget);
+            }
+        }
+
+        popup.popupComponentWidget = (Widget) component;
+        popup.popupComponentPaintable = component;
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (client != null) {
+            client.handleTooltipEvent(event, this);
+        }
+    }
+
+}// class VPopupView
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java b/src/com/vaadin/terminal/gwt/client/ui/VProgressIndicator.java
new file mode 100644 (file)
index 0000000..5da78be
--- /dev/null
@@ -0,0 +1,100 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VProgressIndicator extends Widget implements Paintable {
+
+    private static final String CLASSNAME = "i-progressindicator";
+    Element wrapper = DOM.createDiv();
+    Element indicator = DOM.createDiv();
+    private ApplicationConnection client;
+    private final Poller poller;
+    private boolean indeterminate = false;
+    private boolean pollerSuspendedDueDetach;
+
+    public VProgressIndicator() {
+        setElement(DOM.createDiv());
+        getElement().appendChild(wrapper);
+        setStyleName(CLASSNAME);
+        wrapper.appendChild(indicator);
+        indicator.setClassName(CLASSNAME + "-indicator");
+        wrapper.setClassName(CLASSNAME + "-wrapper");
+        poller = new Poller();
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        poller.cancel();
+        this.client = client;
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        indeterminate = uidl.getBooleanAttribute("indeterminate");
+
+        if (indeterminate) {
+            String basename = CLASSNAME + "-indeterminate";
+            VProgressIndicator.setStyleName(getElement(), basename, true);
+            VProgressIndicator.setStyleName(getElement(), basename
+                    + "-disabled", uidl.getBooleanAttribute("disabled"));
+        } else {
+            try {
+                final float f = Float.parseFloat(uidl
+                        .getStringAttribute("state"));
+                final int size = Math.round(100 * f);
+                DOM.setStyleAttribute(indicator, "width", size + "%");
+            } catch (final Exception e) {
+            }
+        }
+
+        if (!uidl.getBooleanAttribute("disabled")) {
+            poller.scheduleRepeating(uidl.getIntAttribute("pollinginterval"));
+        }
+    }
+
+    @Override
+    protected void onAttach() {
+        super.onAttach();
+        if (pollerSuspendedDueDetach) {
+            poller.run();
+        }
+    }
+
+    @Override
+    protected void onDetach() {
+        super.onDetach();
+        poller.cancel();
+        pollerSuspendedDueDetach = true;
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        super.setVisible(visible);
+        if (!visible) {
+            poller.cancel();
+        }
+    }
+
+    class Poller extends Timer {
+
+        @Override
+        public void run() {
+            client.sendPendingVariableChanges();
+        }
+
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
new file mode 100644 (file)
index 0000000..a1efd5d
--- /dev/null
@@ -0,0 +1,2841 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.NodeList;
+import com.google.gwt.dom.client.TableCellElement;
+import com.google.gwt.dom.client.TableRowElement;
+import com.google.gwt.dom.client.TableSectionElement;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+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.FlowPanel;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.ScrollListener;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.MouseEventDetails;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;
+
+/**
+ * VScrollTable
+ * 
+ * VScrollTable is a FlowPanel having two widgets in it: * TableHead component *
+ * ScrollPanel
+ * 
+ * TableHead contains table's header and widgets + logic for resizing,
+ * reordering and hiding columns.
+ * 
+ * ScrollPanel contains VScrollTableBody object which handles content. To save
+ * some bandwidth and to improve clients responsiveness with loads of data, in
+ * VScrollTableBody all rows are not necessary rendered. There are "spacers" in
+ * VScrollTableBody to use the exact same space as non-rendered rows would use.
+ * This way we can use seamlessly traditional scrollbars and scrolling to fetch
+ * more rows instead of "paging".
+ * 
+ * In VScrollTable we listen to scroll events. On horizontal scrolling we also
+ * update TableHeads scroll position which has its scrollbars hidden. On
+ * vertical scroll events we will check if we are reaching the end of area where
+ * we have rows rendered and
+ * 
+ * TODO implement unregistering for child components in Cells
+ */
+public class VScrollTable extends FlowPanel implements Table, ScrollListener {
+
+    public static final String CLASSNAME = "i-table";
+    /**
+     * multiple of pagelength which component will cache when requesting more
+     * rows
+     */
+    private static final double CACHE_RATE = 2;
+    /**
+     * fraction of pageLenght which can be scrolled without making new request
+     */
+    private static final double CACHE_REACT_RATE = 1.5;
+
+    public static final char ALIGN_CENTER = 'c';
+    public static final char ALIGN_LEFT = 'b';
+    public static final char ALIGN_RIGHT = 'e';
+    private int firstRowInViewPort = 0;
+    private int pageLength = 15;
+    private int lastRequestedFirstvisible = 0; // to detect "serverside scroll"
+
+    private boolean showRowHeaders = false;
+
+    private String[] columnOrder;
+
+    private ApplicationConnection client;
+    private String paintableId;
+
+    private boolean immediate;
+
+    private int selectMode = Table.SELECT_MODE_NONE;
+
+    private final HashSet<String> selectedRowKeys = new HashSet<String>();
+
+    private boolean initializedAndAttached = false;
+
+    /**
+     * Flag to indicate if a column width recalculation is needed due update.
+     */
+    private boolean headerChangedDuringUpdate = false;
+
+    private final TableHead tHead = new TableHead();
+
+    private final ScrollPanel bodyContainer = new ScrollPanel();
+
+    private int totalRows;
+
+    private Set<String> collapsedColumns;
+
+    private final RowRequestHandler rowRequestHandler;
+    private VScrollTableBody tBody;
+    private int firstvisible = 0;
+    private boolean sortAscending;
+    private String sortColumn;
+    private boolean columnReordering;
+
+    /**
+     * This map contains captions and icon urls for actions like: * "33_c" ->
+     * "Edit" * "33_i" -> "http://dom.com/edit.png"
+     */
+    private final HashMap<Object, String> actionMap = new HashMap<Object, String>();
+    private String[] visibleColOrder;
+    private boolean initialContentReceived = false;
+    private Element scrollPositionElement;
+    private boolean enabled;
+    private boolean showColHeaders;
+
+    /** flag to indicate that table body has changed */
+    private boolean isNewBody = true;
+
+    private boolean emitClickEvents;
+
+    /*
+     * Read from the "recalcWidths" -attribute. When it is true, the table will
+     * recalculate the widths for columns - desirable in some cases. For #1983,
+     * marked experimental.
+     */
+    boolean recalcWidths = false;
+
+    private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>();
+    private String height;
+    private String width = "";
+    private boolean rendering = false;
+
+    public VScrollTable() {
+        bodyContainer.addScrollListener(this);
+        bodyContainer.setStyleName(CLASSNAME + "-body");
+
+        setStyleName(CLASSNAME);
+        add(tHead);
+        add(bodyContainer);
+
+        rowRequestHandler = new RowRequestHandler();
+
+    }
+
+    @SuppressWarnings("unchecked")
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+        if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
+            return;
+        }
+
+        // we may have pending cache row fetch, cancel it. See #2136
+        rowRequestHandler.cancel();
+
+        enabled = !uidl.hasAttribute("disabled");
+
+        this.client = client;
+        paintableId = uidl.getStringAttribute("id");
+        immediate = uidl.getBooleanAttribute("immediate");
+        emitClickEvents = uidl.getBooleanAttribute("listenClicks");
+        final int newTotalRows = uidl.getIntAttribute("totalrows");
+        if (newTotalRows != totalRows) {
+            if (tBody != null) {
+                if (totalRows == 0) {
+                    tHead.clear();
+                }
+                initializedAndAttached = false;
+                initialContentReceived = false;
+                isNewBody = true;
+            }
+            totalRows = newTotalRows;
+        }
+
+        recalcWidths = uidl.hasAttribute("recalcWidths");
+
+        pageLength = uidl.getIntAttribute("pagelength");
+        if (pageLength == 0) {
+            pageLength = totalRows;
+        }
+        firstvisible = uidl.hasVariable("firstvisible") ? uidl
+                .getIntVariable("firstvisible") : 0;
+        if (firstvisible != lastRequestedFirstvisible && tBody != null) {
+            // received 'surprising' firstvisible from server: scroll there
+            firstRowInViewPort = firstvisible;
+            bodyContainer
+                    .setScrollPosition(firstvisible * tBody.getRowHeight());
+        }
+
+        showRowHeaders = uidl.getBooleanAttribute("rowheaders");
+        showColHeaders = uidl.getBooleanAttribute("colheaders");
+
+        if (uidl.hasVariable("sortascending")) {
+            sortAscending = uidl.getBooleanVariable("sortascending");
+            sortColumn = uidl.getStringVariable("sortcolumn");
+        }
+
+        if (uidl.hasVariable("selected")) {
+            final Set<String> selectedKeys = uidl
+                    .getStringArrayVariableAsSet("selected");
+            selectedRowKeys.clear();
+            for (String string : selectedKeys) {
+                selectedRowKeys.add(string);
+            }
+        }
+
+        if (uidl.hasAttribute("selectmode")) {
+            if (uidl.getBooleanAttribute("readonly")) {
+                selectMode = Table.SELECT_MODE_NONE;
+            } else if (uidl.getStringAttribute("selectmode").equals("multi")) {
+                selectMode = Table.SELECT_MODE_MULTI;
+            } else if (uidl.getStringAttribute("selectmode").equals("single")) {
+                selectMode = Table.SELECT_MODE_SINGLE;
+            } else {
+                selectMode = Table.SELECT_MODE_NONE;
+            }
+        }
+
+        if (uidl.hasVariable("columnorder")) {
+            columnReordering = true;
+            columnOrder = uidl.getStringArrayVariable("columnorder");
+        }
+
+        if (uidl.hasVariable("collapsedcolumns")) {
+            tHead.setColumnCollapsingAllowed(true);
+            collapsedColumns = uidl
+                    .getStringArrayVariableAsSet("collapsedcolumns");
+        } else {
+            tHead.setColumnCollapsingAllowed(false);
+        }
+
+        UIDL rowData = null;
+        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
+            final UIDL c = (UIDL) it.next();
+            if (c.getTag().equals("rows")) {
+                rowData = c;
+            } else if (c.getTag().equals("actions")) {
+                updateActionMap(c);
+            } else if (c.getTag().equals("visiblecolumns")) {
+                tHead.updateCellsFromUIDL(c);
+            }
+        }
+        updateHeader(uidl.getStringArrayAttribute("vcolorder"));
+
+        if (!recalcWidths && initializedAndAttached) {
+            updateBody(rowData, uidl.getIntAttribute("firstrow"), uidl
+                    .getIntAttribute("rows"));
+            if (headerChangedDuringUpdate) {
+                lazyAdjustColumnWidths.schedule(1);
+            }
+        } else {
+            if (tBody != null) {
+                tBody.removeFromParent();
+                lazyUnregistryBag.add(tBody);
+            }
+            tBody = new VScrollTableBody();
+
+            tBody.renderInitialRows(rowData, uidl.getIntAttribute("firstrow"),
+                    uidl.getIntAttribute("rows"));
+            bodyContainer.add(tBody);
+            initialContentReceived = true;
+            if (isAttached()) {
+                sizeInit();
+            }
+        }
+        hideScrollPositionAnnotation();
+        purgeUnregistryBag();
+        rendering = false;
+        headerChangedDuringUpdate = false;
+    }
+
+    /**
+     * Unregisters Paintables in "trashed" HasWidgets (IScrollTableBodys or
+     * IScrollTableRows). This is done lazily as Table must survive from
+     * "subtreecaching" logic.
+     */
+    private void purgeUnregistryBag() {
+        for (Iterator<Panel> iterator = lazyUnregistryBag.iterator(); iterator
+                .hasNext();) {
+            client.unregisterChildPaintables(iterator.next());
+        }
+        lazyUnregistryBag.clear();
+    }
+
+    private void updateActionMap(UIDL c) {
+        final Iterator<?> it = c.getChildIterator();
+        while (it.hasNext()) {
+            final UIDL action = (UIDL) it.next();
+            final String key = action.getStringAttribute("key");
+            final String caption = action.getStringAttribute("caption");
+            actionMap.put(key + "_c", caption);
+            if (action.hasAttribute("icon")) {
+                // TODO need some uri handling ??
+                actionMap.put(key + "_i", client.translateToolkitUri(action
+                        .getStringAttribute("icon")));
+            }
+        }
+
+    }
+
+    public String getActionCaption(String actionKey) {
+        return actionMap.get(actionKey + "_c");
+    }
+
+    public String getActionIcon(String actionKey) {
+        return actionMap.get(actionKey + "_i");
+    }
+
+    private void updateHeader(String[] strings) {
+        if (strings == null) {
+            return;
+        }
+
+        int visibleCols = strings.length;
+        int colIndex = 0;
+        if (showRowHeaders) {
+            tHead.enableColumn("0", colIndex);
+            visibleCols++;
+            visibleColOrder = new String[visibleCols];
+            visibleColOrder[colIndex] = "0";
+            colIndex++;
+        } else {
+            visibleColOrder = new String[visibleCols];
+            tHead.removeCell("0");
+        }
+
+        int i;
+        for (i = 0; i < strings.length; i++) {
+            final String cid = strings[i];
+            visibleColOrder[colIndex] = cid;
+            tHead.enableColumn(cid, colIndex);
+            colIndex++;
+        }
+
+        tHead.setVisible(showColHeaders);
+
+    }
+
+    /**
+     * @param uidl
+     *            which contains row data
+     * @param firstRow
+     *            first row in data set
+     * @param reqRows
+     *            amount of rows in data set
+     */
+    private void updateBody(UIDL uidl, int firstRow, int reqRows) {
+        if (uidl == null || reqRows < 1) {
+            // container is empty, remove possibly existing rows
+            if (firstRow < 0) {
+                while (tBody.getLastRendered() > tBody.firstRendered) {
+                    tBody.unlinkRow(false);
+                }
+                tBody.unlinkRow(false);
+            }
+            return;
+        }
+
+        tBody.renderRows(uidl, firstRow, reqRows);
+
+        final int optimalFirstRow = (int) (firstRowInViewPort - pageLength
+                * CACHE_RATE);
+        boolean cont = true;
+        while (cont && tBody.getLastRendered() > optimalFirstRow
+                && tBody.getFirstRendered() < optimalFirstRow) {
+            // client.console.log("removing row from start");
+            cont = tBody.unlinkRow(true);
+        }
+        final int optimalLastRow = (int) (firstRowInViewPort + pageLength + pageLength
+                * CACHE_RATE);
+        cont = true;
+        while (cont && tBody.getLastRendered() > optimalLastRow) {
+            // client.console.log("removing row from the end");
+            cont = tBody.unlinkRow(false);
+        }
+        tBody.fixSpacers();
+
+    }
+
+    /**
+     * Gives correct column index for given column key ("cid" in UIDL).
+     * 
+     * @param colKey
+     * @return column index of visible columns, -1 if column not visible
+     */
+    private int getColIndexByKey(String colKey) {
+        // return 0 if asked for rowHeaders
+        if ("0".equals(colKey)) {
+            return 0;
+        }
+        for (int i = 0; i < visibleColOrder.length; i++) {
+            if (visibleColOrder[i].equals(colKey)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private boolean isCollapsedColumn(String colKey) {
+        if (collapsedColumns == null) {
+            return false;
+        }
+        if (collapsedColumns.contains(colKey)) {
+            return true;
+        }
+        return false;
+    }
+
+    private String getColKeyByIndex(int index) {
+        return tHead.getHeaderCell(index).getColKey();
+    }
+
+    private void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
+        final HeaderCell cell = tHead.getHeaderCell(colIndex);
+        cell.setWidth(w, isDefinedWidth);
+        tBody.setColWidth(colIndex, w);
+    }
+
+    private int getColWidth(String colKey) {
+        return tHead.getHeaderCell(colKey).getWidth();
+    }
+
+    private VScrollTableRow getRenderedRowByKey(String key) {
+        final Iterator<Widget> it = tBody.iterator();
+        VScrollTableRow r = null;
+        while (it.hasNext()) {
+            r = (VScrollTableRow) it.next();
+            if (r.getKey().equals(key)) {
+                return r;
+            }
+        }
+        return null;
+    }
+
+    private void reOrderColumn(String columnKey, int newIndex) {
+
+        final int oldIndex = getColIndexByKey(columnKey);
+
+        // Change header order
+        tHead.moveCell(oldIndex, newIndex);
+
+        // Change body order
+        tBody.moveCol(oldIndex, newIndex);
+
+        /*
+         * Build new columnOrder and update it to server Note that columnOrder
+         * also contains collapsed columns so we cannot directly build it from
+         * cells vector Loop the old columnOrder and append in order to new
+         * array unless on moved columnKey. On new index also put the moved key
+         * i == index on columnOrder, j == index on newOrder
+         */
+        final String oldKeyOnNewIndex = visibleColOrder[newIndex];
+        if (showRowHeaders) {
+            newIndex--; // columnOrder don't have rowHeader
+        }
+        // add back hidden rows,
+        for (int i = 0; i < columnOrder.length; i++) {
+            if (columnOrder[i].equals(oldKeyOnNewIndex)) {
+                break; // break loop at target
+            }
+            if (isCollapsedColumn(columnOrder[i])) {
+                newIndex++;
+            }
+        }
+        // finally we can build the new columnOrder for server
+        final String[] newOrder = new String[columnOrder.length];
+        for (int i = 0, j = 0; j < newOrder.length; i++) {
+            if (j == newIndex) {
+                newOrder[j] = columnKey;
+                j++;
+            }
+            if (i == columnOrder.length) {
+                break;
+            }
+            if (columnOrder[i].equals(columnKey)) {
+                continue;
+            }
+            newOrder[j] = columnOrder[i];
+            j++;
+        }
+        columnOrder = newOrder;
+        // also update visibleColumnOrder
+        int i = showRowHeaders ? 1 : 0;
+        for (int j = 0; j < newOrder.length; j++) {
+            final String cid = newOrder[j];
+            if (!isCollapsedColumn(cid)) {
+                visibleColOrder[i++] = cid;
+            }
+        }
+        client.updateVariable(paintableId, "columnorder", columnOrder, false);
+    }
+
+    @Override
+    protected void onAttach() {
+        super.onAttach();
+        if (initialContentReceived) {
+            sizeInit();
+        }
+    }
+
+    @Override
+    protected void onDetach() {
+        rowRequestHandler.cancel();
+        super.onDetach();
+        // ensure that scrollPosElement will be detached
+        if (scrollPositionElement != null) {
+            final Element parent = DOM.getParent(scrollPositionElement);
+            if (parent != null) {
+                DOM.removeChild(parent, scrollPositionElement);
+            }
+        }
+    }
+
+    /**
+     * Run only once when component is attached and received its initial
+     * content. This function : * Syncs headers and bodys "natural widths and
+     * saves the values. * Sets proper width and height * Makes deferred request
+     * to get some cache rows
+     */
+    private void sizeInit() {
+        /*
+         * We will use browsers table rendering algorithm to find proper column
+         * widths. If content and header take less space than available, we will
+         * divide extra space relatively to each column which has not width set.
+         * 
+         * Overflow pixels are added to last column.
+         */
+
+        Iterator<Widget> headCells = tHead.iterator();
+        int i = 0;
+        int totalExplicitColumnsWidths = 0;
+        int total = 0;
+        float expandRatioDivider = 0;
+
+        final int[] widths = new int[tHead.visibleCells.size()];
+
+        tHead.enableBrowserIntelligence();
+        // first loop: collect natural widths
+        while (headCells.hasNext()) {
+            final HeaderCell hCell = (HeaderCell) headCells.next();
+            int w = hCell.getWidth();
+            if (hCell.isDefinedWidth()) {
+                // server has defined column width explicitly
+                totalExplicitColumnsWidths += w;
+            } else {
+                if (hCell.getExpandRatio() > 0) {
+                    expandRatioDivider += hCell.getExpandRatio();
+                    w = 0;
+                } else {
+                    // get and store greater of header width and column width,
+                    // and
+                    // store it as a minimumn natural col width
+                    w = hCell.getNaturalColumnWidth(i);
+                }
+                hCell.setNaturalMinimumColumnWidth(w);
+            }
+            widths[i] = w;
+            total += w;
+            i++;
+        }
+
+        tHead.disableBrowserIntelligence();
+
+        boolean willHaveScrollbarz = willHaveScrollbars();
+
+        // fix "natural" width if width not set
+        if (width == null || "".equals(width)) {
+            int w = total;
+            w += tBody.getCellExtraWidth() * visibleColOrder.length;
+            if (willHaveScrollbarz) {
+                w += Util.getNativeScrollbarSize();
+            }
+            setContentWidth(w);
+        }
+
+        int availW = tBody.getAvailableWidth();
+        if (BrowserInfo.get().isIE()) {
+            // Hey IE, are you really sure about this?
+            availW = tBody.getAvailableWidth();
+        }
+        availW -= tBody.getCellExtraWidth() * visibleColOrder.length;
+
+        if (willHaveScrollbarz) {
+            availW -= Util.getNativeScrollbarSize();
+        }
+
+        boolean needsReLayout = false;
+
+        if (availW > total) {
+            // natural size is smaller than available space
+            final int extraSpace = availW - total;
+            final int totalWidthR = total - totalExplicitColumnsWidths;
+            if (totalWidthR > 0) {
+                needsReLayout = true;
+
+                if (expandRatioDivider > 0) {
+                    // visible columns have some active expand ratios, excess
+                    // space is divided according to them
+                    headCells = tHead.iterator();
+                    i = 0;
+                    while (headCells.hasNext()) {
+                        HeaderCell hCell = (HeaderCell) headCells.next();
+                        if (hCell.getExpandRatio() > 0) {
+                            int w = widths[i];
+                            final int newSpace = (int) (extraSpace * (hCell
+                                    .getExpandRatio() / expandRatioDivider));
+                            w += newSpace;
+                            widths[i] = w;
+                        }
+                        i++;
+                    }
+                } else {
+                    // now we will share this sum relatively to those without
+                    // explicit width
+                    headCells = tHead.iterator();
+                    i = 0;
+                    while (headCells.hasNext()) {
+                        HeaderCell hCell = (HeaderCell) headCells.next();
+                        if (!hCell.isDefinedWidth()) {
+                            int w = widths[i];
+                            final int newSpace = extraSpace * w / totalWidthR;
+                            w += newSpace;
+                            widths[i] = w;
+                        }
+                        i++;
+                    }
+                }
+            }
+
+        } else {
+            // bodys size will be more than available and scrollbar will appear
+        }
+
+        // last loop: set possibly modified values or reset if new tBody
+        i = 0;
+        headCells = tHead.iterator();
+        while (headCells.hasNext()) {
+            final HeaderCell hCell = (HeaderCell) headCells.next();
+            if (isNewBody || hCell.getWidth() == -1) {
+                final int w = widths[i];
+                setColWidth(i, w, false);
+            }
+            i++;
+        }
+        if (needsReLayout) {
+            tBody.reLayoutComponents();
+        }
+
+        /*
+         * Fix "natural" height if height is not set. This must be after width
+         * fixing so the components' widths have been adjusted.
+         */
+        if (height == null || "".equals(height)) {
+            /*
+             * We must force an update of the row height as this point as it
+             * might have been (incorrectly) calculated earlier
+             */
+            if (pageLength == totalRows) {
+                /*
+                 * A hack to support variable height rows when paging is off.
+                 * Generally this is not supported by scrolltable. We want to
+                 * show all rows so the bodyHeight should be equal to the table
+                 * height.
+                 */
+                int bodyHeight = tBody.getOffsetHeight();
+                bodyContainer.setHeight(bodyHeight + "px");
+                Util.runWebkitOverflowAutoFix(bodyContainer.getElement());
+            } else {
+                int bodyHeight = (tBody.getRowHeight(true) * pageLength);
+                bodyContainer.setHeight(bodyHeight + "px");
+            }
+        }
+
+        isNewBody = false;
+
+        if (firstvisible > 0) {
+            // Deferred due some Firefox oddities. IE & Safari could survive
+            // without
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    bodyContainer.setScrollPosition(firstvisible
+                            * tBody.getRowHeight());
+                    firstRowInViewPort = firstvisible;
+                }
+            });
+        }
+
+        if (enabled) {
+            // Do we need cache rows
+            if (tBody.getLastRendered() + 1 < firstRowInViewPort + pageLength
+                    + CACHE_REACT_RATE * pageLength) {
+                if (totalRows - 1 > tBody.getLastRendered()) {
+                    // fetch cache rows
+                    rowRequestHandler
+                            .setReqFirstRow(tBody.getLastRendered() + 1);
+                    rowRequestHandler
+                            .setReqRows((int) (pageLength * CACHE_RATE));
+                    rowRequestHandler.deferRowFetch(1);
+                }
+            }
+        }
+        initializedAndAttached = true;
+    }
+
+    private boolean willHaveScrollbars() {
+        if (!(height != null && !height.equals(""))) {
+            if (pageLength < totalRows) {
+                return true;
+            }
+        } else {
+            int fakeheight = tBody.getRowHeight() * totalRows;
+            int availableHeight = bodyContainer.getElement().getPropertyInt(
+                    "clientHeight");
+            if (fakeheight > availableHeight) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This method has logic which rows needs to be requested from server when
+     * user scrolls
+     */
+    public void onScroll(Widget widget, int scrollLeft, int scrollTop) {
+        if (!initializedAndAttached) {
+            return;
+        }
+        if (!enabled) {
+            bodyContainer.setScrollPosition(firstRowInViewPort
+                    * tBody.getRowHeight());
+            return;
+        }
+
+        rowRequestHandler.cancel();
+
+        // fix headers horizontal scrolling
+        tHead.setHorizontalScrollPosition(scrollLeft);
+
+        firstRowInViewPort = (int) Math.ceil(scrollTop
+                / (double) tBody.getRowHeight());
+
+        int postLimit = (int) (firstRowInViewPort + pageLength + pageLength
+                * CACHE_REACT_RATE);
+        if (postLimit > totalRows - 1) {
+            postLimit = totalRows - 1;
+        }
+        int preLimit = (int) (firstRowInViewPort - pageLength
+                * CACHE_REACT_RATE);
+        if (preLimit < 0) {
+            preLimit = 0;
+        }
+        final int lastRendered = tBody.getLastRendered();
+        final int firstRendered = tBody.getFirstRendered();
+
+        if (postLimit <= lastRendered && preLimit >= firstRendered) {
+            // remember which firstvisible we requested, in case the server has
+            // a differing opinion
+            lastRequestedFirstvisible = firstRowInViewPort;
+            client.updateVariable(paintableId, "firstvisible",
+                    firstRowInViewPort, false);
+            return; // scrolled withing "non-react area"
+        }
+
+        if (firstRowInViewPort - pageLength * CACHE_RATE > lastRendered
+                || firstRowInViewPort + pageLength + pageLength * CACHE_RATE < firstRendered) {
+            // need a totally new set
+            rowRequestHandler
+                    .setReqFirstRow((int) (firstRowInViewPort - pageLength
+                            * CACHE_RATE));
+            int last = firstRowInViewPort + (int) CACHE_RATE * pageLength
+                    + pageLength;
+            if (last > totalRows) {
+                last = totalRows - 1;
+            }
+            rowRequestHandler.setReqRows(last
+                    - rowRequestHandler.getReqFirstRow() + 1);
+            rowRequestHandler.deferRowFetch();
+            return;
+        }
+        if (preLimit < firstRendered) {
+            // need some rows to the beginning of the rendered area
+            rowRequestHandler
+                    .setReqFirstRow((int) (firstRowInViewPort - pageLength
+                            * CACHE_RATE));
+            rowRequestHandler.setReqRows(firstRendered
+                    - rowRequestHandler.getReqFirstRow());
+            rowRequestHandler.deferRowFetch();
+
+            return;
+        }
+        if (postLimit > lastRendered) {
+            // need some rows to the end of the rendered area
+            rowRequestHandler.setReqFirstRow(lastRendered + 1);
+            rowRequestHandler.setReqRows((int) ((firstRowInViewPort
+                    + pageLength + pageLength * CACHE_RATE) - lastRendered));
+            rowRequestHandler.deferRowFetch();
+        }
+
+    }
+
+    private void announceScrollPosition() {
+        if (scrollPositionElement == null) {
+            scrollPositionElement = DOM.createDiv();
+            DOM.setElementProperty(scrollPositionElement, "className",
+                    "i-table-scrollposition");
+            DOM.appendChild(getElement(), scrollPositionElement);
+        }
+
+        DOM.setStyleAttribute(scrollPositionElement, "position", "absolute");
+        DOM.setStyleAttribute(scrollPositionElement, "marginLeft", (DOM
+                .getElementPropertyInt(getElement(), "offsetWidth") / 2 - 80)
+                + "px");
+        DOM.setStyleAttribute(scrollPositionElement, "marginTop", -(DOM
+                .getElementPropertyInt(getElement(), "offsetHeight") - 2)
+                + "px");
+
+        // indexes go from 1-totalRows, as rowheaders in index-mode indicate
+        int last = (firstRowInViewPort + (bodyContainer.getOffsetHeight() / tBody
+                .getRowHeight()));
+        if (last > totalRows) {
+            last = totalRows;
+        }
+        DOM.setInnerHTML(scrollPositionElement, "<span>"
+                + (firstRowInViewPort + 1) + " &ndash; " + last + "..."
+                + "</span>");
+        DOM.setStyleAttribute(scrollPositionElement, "display", "block");
+    }
+
+    private void hideScrollPositionAnnotation() {
+        if (scrollPositionElement != null) {
+            DOM.setStyleAttribute(scrollPositionElement, "display", "none");
+        }
+    }
+
+    private class RowRequestHandler extends Timer {
+
+        private int reqFirstRow = 0;
+        private int reqRows = 0;
+
+        public void deferRowFetch() {
+            deferRowFetch(250);
+        }
+
+        public void deferRowFetch(int msec) {
+            if (reqRows > 0 && reqFirstRow < totalRows) {
+                schedule(msec);
+
+                // tell scroll position to user if currently "visible" rows are
+                // not rendered
+                if ((firstRowInViewPort + pageLength > tBody.getLastRendered())
+                        || (firstRowInViewPort < tBody.getFirstRendered())) {
+                    announceScrollPosition();
+                } else {
+                    hideScrollPositionAnnotation();
+                }
+            }
+        }
+
+        public void setReqFirstRow(int reqFirstRow) {
+            if (reqFirstRow < 0) {
+                reqFirstRow = 0;
+            } else if (reqFirstRow >= totalRows) {
+                reqFirstRow = totalRows - 1;
+            }
+            this.reqFirstRow = reqFirstRow;
+        }
+
+        public void setReqRows(int reqRows) {
+            this.reqRows = reqRows;
+        }
+
+        @Override
+        public void run() {
+            if (client.hasActiveRequest()) {
+                // if client connection is busy, don't bother loading it more
+                schedule(250);
+
+            } else {
+
+                int firstToBeRendered = tBody.firstRendered;
+                if (reqFirstRow < firstToBeRendered) {
+                    firstToBeRendered = reqFirstRow;
+                } else if (firstRowInViewPort - (int) (CACHE_RATE * pageLength) > firstToBeRendered) {
+                    firstToBeRendered = firstRowInViewPort
+                            - (int) (CACHE_RATE * pageLength);
+                    if (firstToBeRendered < 0) {
+                        firstToBeRendered = 0;
+                    }
+                }
+
+                int lastToBeRendered = tBody.lastRendered;
+
+                if (reqFirstRow + reqRows - 1 > lastToBeRendered) {
+                    lastToBeRendered = reqFirstRow + reqRows - 1;
+                } else if (firstRowInViewPort + pageLength + pageLength
+                        * CACHE_RATE < lastToBeRendered) {
+                    lastToBeRendered = (firstRowInViewPort + pageLength + (int) (pageLength * CACHE_RATE));
+                    if (lastToBeRendered >= totalRows) {
+                        lastToBeRendered = totalRows - 1;
+                    }
+                    // due Safari 3.1 bug (see #2607), verify reqrows, original
+                    // problem unknown, but this should catch the issue
+                    if (reqFirstRow + reqRows - 1 > lastToBeRendered) {
+                        reqRows = lastToBeRendered - reqFirstRow;
+                    }
+                }
+
+                client.updateVariable(paintableId, "firstToBeRendered",
+                        firstToBeRendered, false);
+
+                client.updateVariable(paintableId, "lastToBeRendered",
+                        lastToBeRendered, false);
+                // remember which firstvisible we requested, in case the server
+                // has
+                // a differing opinion
+                lastRequestedFirstvisible = firstRowInViewPort;
+                client.updateVariable(paintableId, "firstvisible",
+                        firstRowInViewPort, false);
+                client.updateVariable(paintableId, "reqfirstrow", reqFirstRow,
+                        false);
+                client.updateVariable(paintableId, "reqrows", reqRows, true);
+
+            }
+        }
+
+        public int getReqFirstRow() {
+            return reqFirstRow;
+        }
+
+        public int getReqRows() {
+            return reqRows;
+        }
+
+        /**
+         * Sends request to refresh content at this position.
+         */
+        public void refreshContent() {
+            int first = (int) (firstRowInViewPort - pageLength * CACHE_RATE);
+            int reqRows = (int) (2 * pageLength * CACHE_RATE + pageLength);
+            if (first < 0) {
+                reqRows = reqRows + first;
+                first = 0;
+            }
+            setReqFirstRow(first);
+            setReqRows(reqRows);
+            run();
+        }
+    }
+
+    public class HeaderCell extends Widget {
+
+        Element td = DOM.createTD();
+
+        Element captionContainer = DOM.createDiv();
+
+        Element colResizeWidget = DOM.createDiv();
+
+        Element floatingCopyOfHeaderCell;
+
+        private boolean sortable = false;
+        private final String cid;
+        private boolean dragging;
+
+        private int dragStartX;
+        private int colIndex;
+        private int originalWidth;
+
+        private boolean isResizing;
+
+        private int headerX;
+
+        private boolean moved;
+
+        private int closestSlot;
+
+        private int width = -1;
+
+        private int naturalWidth = -1;
+
+        private char align = ALIGN_LEFT;
+
+        boolean definedWidth = false;
+
+        private float expandRatio = 0;
+
+        public void setSortable(boolean b) {
+            sortable = b;
+        }
+
+        public void setNaturalMinimumColumnWidth(int w) {
+            naturalWidth = w;
+        }
+
+        public HeaderCell(String colId, String headerText) {
+            cid = colId;
+
+            DOM.setElementProperty(colResizeWidget, "className", CLASSNAME
+                    + "-resizer");
+            DOM.sinkEvents(colResizeWidget, Event.MOUSEEVENTS);
+
+            setText(headerText);
+
+            DOM.appendChild(td, colResizeWidget);
+
+            DOM.setElementProperty(captionContainer, "className", CLASSNAME
+                    + "-caption-container");
+
+            // ensure no clipping initially (problem on column additions)
+            DOM.setStyleAttribute(captionContainer, "overflow", "visible");
+
+            DOM.sinkEvents(captionContainer, Event.MOUSEEVENTS);
+
+            DOM.appendChild(td, captionContainer);
+
+            DOM.sinkEvents(td, Event.MOUSEEVENTS);
+
+            setElement(td);
+        }
+
+        public void setWidth(int w, boolean ensureDefinedWidth) {
+            if (ensureDefinedWidth) {
+                definedWidth = true;
+                // on column resize expand ratio becomes zero
+                expandRatio = 0;
+            }
+            if (width == w) {
+                return;
+            }
+            if (width == -1) {
+                // go to default mode, clip content if necessary
+                DOM.setStyleAttribute(captionContainer, "overflow", "");
+            }
+            width = w;
+            if (w == -1) {
+                DOM.setStyleAttribute(captionContainer, "width", "");
+                setWidth("");
+            } else {
+
+                captionContainer.getStyle().setPropertyPx("width", w);
+
+                /*
+                 * if we already have tBody, set the header width properly, if
+                 * not defer it. IE will fail with complex float in table header
+                 * unless TD width is not explicitly set.
+                 */
+                if (tBody != null) {
+                    int tdWidth = width + tBody.getCellExtraWidth();
+                    setWidth(tdWidth + "px");
+                } else {
+                    DeferredCommand.addCommand(new Command() {
+                        public void execute() {
+                            int tdWidth = width + tBody.getCellExtraWidth();
+                            setWidth(tdWidth + "px");
+                        }
+                    });
+                }
+            }
+        }
+
+        public void setUndefinedWidth() {
+            definedWidth = false;
+            setWidth(-1, false);
+        }
+
+        /**
+         * Detects if width is fixed by developer on server side or resized to
+         * current width by user.
+         * 
+         * @return true if defined, false if "natural" width
+         */
+        public boolean isDefinedWidth() {
+            return definedWidth;
+        }
+
+        public int getWidth() {
+            return width;
+        }
+
+        public void setText(String headerText) {
+            DOM.setInnerHTML(captionContainer, headerText);
+        }
+
+        public String getColKey() {
+            return cid;
+        }
+
+        private void setSorted(boolean sorted) {
+            if (sorted) {
+                if (sortAscending) {
+                    this.setStyleName(CLASSNAME + "-header-cell-asc");
+                } else {
+                    this.setStyleName(CLASSNAME + "-header-cell-desc");
+                }
+            } else {
+                this.setStyleName(CLASSNAME + "-header-cell");
+            }
+        }
+
+        /**
+         * Handle column reordering.
+         */
+        @Override
+        public void onBrowserEvent(Event event) {
+            if (enabled && event != null) {
+                if (isResizing || event.getTarget() == colResizeWidget) {
+                    onResizeEvent(event);
+                } else {
+                    handleCaptionEvent(event);
+                }
+            }
+        }
+
+        private void createFloatingCopy() {
+            floatingCopyOfHeaderCell = DOM.createDiv();
+            DOM.setInnerHTML(floatingCopyOfHeaderCell, DOM.getInnerHTML(td));
+            floatingCopyOfHeaderCell = DOM
+                    .getChild(floatingCopyOfHeaderCell, 1);
+            DOM.setElementProperty(floatingCopyOfHeaderCell, "className",
+                    CLASSNAME + "-header-drag");
+            updateFloatingCopysPosition(DOM.getAbsoluteLeft(td), DOM
+                    .getAbsoluteTop(td));
+            DOM.appendChild(RootPanel.get().getElement(),
+                    floatingCopyOfHeaderCell);
+        }
+
+        private void updateFloatingCopysPosition(int x, int y) {
+            x -= DOM.getElementPropertyInt(floatingCopyOfHeaderCell,
+                    "offsetWidth") / 2;
+            DOM.setStyleAttribute(floatingCopyOfHeaderCell, "left", x + "px");
+            if (y > 0) {
+                DOM.setStyleAttribute(floatingCopyOfHeaderCell, "top", (y + 7)
+                        + "px");
+            }
+        }
+
+        private void hideFloatingCopy() {
+            DOM.removeChild(RootPanel.get().getElement(),
+                    floatingCopyOfHeaderCell);
+            floatingCopyOfHeaderCell = null;
+        }
+
+        protected void handleCaptionEvent(Event event) {
+            switch (DOM.eventGetType(event)) {
+            case Event.ONMOUSEDOWN:
+                if (columnReordering) {
+                    dragging = true;
+                    moved = false;
+                    colIndex = getColIndexByKey(cid);
+                    DOM.setCapture(getElement());
+                    headerX = tHead.getAbsoluteLeft();
+                    DOM.eventPreventDefault(event); // prevent selecting text
+                }
+                break;
+            case Event.ONMOUSEUP:
+                if (columnReordering) {
+                    dragging = false;
+                    DOM.releaseCapture(getElement());
+                    if (moved) {
+                        hideFloatingCopy();
+                        tHead.removeSlotFocus();
+                        if (closestSlot != colIndex
+                                && closestSlot != (colIndex + 1)) {
+                            if (closestSlot > colIndex) {
+                                reOrderColumn(cid, closestSlot - 1);
+                            } else {
+                                reOrderColumn(cid, closestSlot);
+                            }
+                        }
+                    }
+                }
+
+                if (!moved) {
+                    // mouse event was a click to header -> sort column
+                    if (sortable) {
+                        if (sortColumn.equals(cid)) {
+                            // just toggle order
+                            client.updateVariable(paintableId, "sortascending",
+                                    !sortAscending, false);
+                        } else {
+                            // set table scrolled by this column
+                            client.updateVariable(paintableId, "sortcolumn",
+                                    cid, false);
+                        }
+                        // get also cache columns at the same request
+                        bodyContainer.setScrollPosition(0);
+                        firstvisible = 0;
+                        rowRequestHandler.setReqFirstRow(0);
+                        rowRequestHandler.setReqRows((int) (2 * pageLength
+                                * CACHE_RATE + pageLength));
+                        rowRequestHandler.deferRowFetch();
+                    }
+                    break;
+                }
+                break;
+            case Event.ONMOUSEMOVE:
+                if (dragging) {
+                    if (!moved) {
+                        createFloatingCopy();
+                        moved = true;
+                    }
+                    final int x = DOM.eventGetClientX(event)
+                            + DOM.getElementPropertyInt(tHead.hTableWrapper,
+                                    "scrollLeft");
+                    int slotX = headerX;
+                    closestSlot = colIndex;
+                    int closestDistance = -1;
+                    int start = 0;
+                    if (showRowHeaders) {
+                        start++;
+                    }
+                    final int visibleCellCount = tHead.getVisibleCellCount();
+                    for (int i = start; i <= visibleCellCount; i++) {
+                        if (i > 0) {
+                            final String colKey = getColKeyByIndex(i - 1);
+                            slotX += getColWidth(colKey);
+                        }
+                        final int dist = Math.abs(x - slotX);
+                        if (closestDistance == -1 || dist < closestDistance) {
+                            closestDistance = dist;
+                            closestSlot = i;
+                        }
+                    }
+                    tHead.focusSlot(closestSlot);
+
+                    updateFloatingCopysPosition(DOM.eventGetClientX(event), -1);
+                }
+                break;
+            default:
+                break;
+            }
+        }
+
+        private void onResizeEvent(Event event) {
+            switch (DOM.eventGetType(event)) {
+            case Event.ONMOUSEDOWN:
+                isResizing = true;
+                DOM.setCapture(getElement());
+                dragStartX = DOM.eventGetClientX(event);
+                colIndex = getColIndexByKey(cid);
+                originalWidth = getWidth();
+                DOM.eventPreventDefault(event);
+                break;
+            case Event.ONMOUSEUP:
+                isResizing = false;
+                DOM.releaseCapture(getElement());
+                // readjust undefined width columns
+                lazyAdjustColumnWidths.cancel();
+                lazyAdjustColumnWidths.schedule(1);
+                break;
+            case Event.ONMOUSEMOVE:
+                if (isResizing) {
+                    final int deltaX = DOM.eventGetClientX(event) - dragStartX;
+                    if (deltaX == 0) {
+                        return;
+                    }
+
+                    int newWidth = originalWidth + deltaX;
+                    if (newWidth < tBody.getCellExtraWidth()) {
+                        newWidth = tBody.getCellExtraWidth();
+                    }
+                    setColWidth(colIndex, newWidth, true);
+                }
+                break;
+            default:
+                break;
+            }
+        }
+
+        public String getCaption() {
+            return DOM.getInnerText(captionContainer);
+        }
+
+        public boolean isEnabled() {
+            return getParent() != null;
+        }
+
+        public void setAlign(char c) {
+            if (align != c) {
+                switch (c) {
+                case ALIGN_CENTER:
+                    DOM.setStyleAttribute(captionContainer, "textAlign",
+                            "center");
+                    break;
+                case ALIGN_RIGHT:
+                    DOM.setStyleAttribute(captionContainer, "textAlign",
+                            "right");
+                    break;
+                default:
+                    DOM.setStyleAttribute(captionContainer, "textAlign", "");
+                    break;
+                }
+            }
+            align = c;
+        }
+
+        public char getAlign() {
+            return align;
+        }
+
+        /**
+         * Detects the natural minimum width for the column of this header cell.
+         * If column is resized by user or the width is defined by server the
+         * actual width is returned. Else the natural min width is returned.
+         * 
+         * @param columnIndex
+         *            column index hint, if -1 (unknown) it will be detected
+         * 
+         * @return
+         */
+        public int getNaturalColumnWidth(int columnIndex) {
+            if (isDefinedWidth()) {
+                return width;
+            } else {
+                if (naturalWidth < 0) {
+                    // This is recently revealed column. Try to detect a proper
+                    // value (greater of header and data
+                    // cols)
+
+                    final int hw = ((Element) getElement().getLastChild())
+                            .getOffsetWidth()
+                            + tBody.getCellExtraWidth();
+                    if (columnIndex < 0) {
+                        columnIndex = 0;
+                        for (Iterator<Widget> it = tHead.iterator(); it
+                                .hasNext(); columnIndex++) {
+                            if (it.next() == this) {
+                                break;
+                            }
+                        }
+                    }
+                    final int cw = tBody.getColWidth(columnIndex);
+                    naturalWidth = (hw > cw ? hw : cw);
+                }
+                return naturalWidth;
+            }
+        }
+
+        public void setExpandRatio(float floatAttribute) {
+            expandRatio = floatAttribute;
+        }
+
+        public float getExpandRatio() {
+            return expandRatio;
+        }
+
+    }
+
+    /**
+     * HeaderCell that is header cell for row headers.
+     * 
+     * Reordering disabled and clicking on it resets sorting.
+     */
+    public class RowHeadersHeaderCell extends HeaderCell {
+
+        RowHeadersHeaderCell() {
+            super("0", "");
+        }
+
+        @Override
+        protected void handleCaptionEvent(Event event) {
+            // NOP: RowHeaders cannot be reordered
+            // TODO It'd be nice to reset sorting here
+        }
+    }
+
+    public class TableHead extends Panel implements ActionOwner {
+
+        private static final int WRAPPER_WIDTH = 9000;
+
+        Vector<Widget> visibleCells = new Vector<Widget>();
+
+        HashMap<String, HeaderCell> availableCells = new HashMap<String, HeaderCell>();
+
+        Element div = DOM.createDiv();
+        Element hTableWrapper = DOM.createDiv();
+        Element hTableContainer = DOM.createDiv();
+        Element table = DOM.createTable();
+        Element headerTableBody = DOM.createTBody();
+        Element tr = DOM.createTR();
+
+        private final Element columnSelector = DOM.createDiv();
+
+        private int focusedSlot = -1;
+
+        public TableHead() {
+            if (BrowserInfo.get().isIE()) {
+                table.setPropertyInt("cellSpacing", 0);
+            }
+
+            DOM.setStyleAttribute(hTableWrapper, "overflow", "hidden");
+            DOM.setElementProperty(hTableWrapper, "className", CLASSNAME
+                    + "-header");
+
+            // TODO move styles to CSS
+            DOM.setElementProperty(columnSelector, "className", CLASSNAME
+                    + "-column-selector");
+            DOM.setStyleAttribute(columnSelector, "display", "none");
+
+            DOM.appendChild(table, headerTableBody);
+            DOM.appendChild(headerTableBody, tr);
+            DOM.appendChild(hTableContainer, table);
+            DOM.appendChild(hTableWrapper, hTableContainer);
+            DOM.appendChild(div, hTableWrapper);
+            DOM.appendChild(div, columnSelector);
+            setElement(div);
+
+            setStyleName(CLASSNAME + "-header-wrap");
+
+            DOM.sinkEvents(columnSelector, Event.ONCLICK);
+
+            availableCells.put("0", new RowHeadersHeaderCell());
+        }
+
+        @Override
+        public void clear() {
+            for (String cid : availableCells.keySet()) {
+                removeCell(cid);
+            }
+            availableCells.clear();
+            availableCells.put("0", new RowHeadersHeaderCell());
+        }
+
+        public void updateCellsFromUIDL(UIDL uidl) {
+            Iterator<?> it = uidl.getChildIterator();
+            HashSet<String> updated = new HashSet<String>();
+            updated.add("0");
+            while (it.hasNext()) {
+                final UIDL col = (UIDL) it.next();
+                final String cid = col.getStringAttribute("cid");
+                updated.add(cid);
+
+                String caption = buildCaptionHtmlSnippet(col);
+                HeaderCell c = getHeaderCell(cid);
+                if (c == null) {
+                    c = new HeaderCell(cid, caption);
+                    availableCells.put(cid, c);
+                    if (initializedAndAttached) {
+                        // we will need a column width recalculation
+                        initializedAndAttached = false;
+                        initialContentReceived = false;
+                        isNewBody = true;
+                    }
+                } else {
+                    c.setText(caption);
+                }
+
+                if (col.hasAttribute("sortable")) {
+                    c.setSortable(true);
+                    if (cid.equals(sortColumn)) {
+                        c.setSorted(true);
+                    } else {
+                        c.setSorted(false);
+                    }
+                } else {
+                    c.setSortable(false);
+                }
+
+                if (col.hasAttribute("align")) {
+                    c.setAlign(col.getStringAttribute("align").charAt(0));
+                }
+                if (col.hasAttribute("width")) {
+                    final String width = col.getStringAttribute("width");
+                    c.setWidth(Integer.parseInt(width), true);
+                } else if (recalcWidths) {
+                    c.setUndefinedWidth();
+                }
+                if (col.hasAttribute("er")) {
+                    c.setExpandRatio(col.getFloatAttribute("er"));
+                }
+            }
+            // check for orphaned header cells
+            for (String cid : availableCells.keySet()) {
+                if (!updated.contains(cid)) {
+                    removeCell(cid);
+                    it.remove();
+                }
+            }
+
+        }
+
+        public void enableColumn(String cid, int index) {
+            final HeaderCell c = getHeaderCell(cid);
+            if (!c.isEnabled() || getHeaderCell(index) != c) {
+                setHeaderCell(index, c);
+                if (initializedAndAttached) {
+                    headerChangedDuringUpdate = true;
+                }
+            }
+        }
+
+        public int getVisibleCellCount() {
+            return visibleCells.size();
+        }
+
+        public void setHorizontalScrollPosition(int scrollLeft) {
+            DOM.setElementPropertyInt(hTableWrapper, "scrollLeft", scrollLeft);
+        }
+
+        public void setColumnCollapsingAllowed(boolean cc) {
+            if (cc) {
+                DOM.setStyleAttribute(columnSelector, "display", "block");
+            } else {
+                DOM.setStyleAttribute(columnSelector, "display", "none");
+            }
+        }
+
+        public void disableBrowserIntelligence() {
+            DOM.setStyleAttribute(hTableContainer, "width", WRAPPER_WIDTH
+                    + "px");
+        }
+
+        public void enableBrowserIntelligence() {
+            DOM.setStyleAttribute(hTableContainer, "width", "");
+        }
+
+        public void setHeaderCell(int index, HeaderCell cell) {
+            if (cell.isEnabled()) {
+                // we're moving the cell
+                DOM.removeChild(tr, cell.getElement());
+                orphan(cell);
+            }
+            if (index < visibleCells.size()) {
+                // insert to right slot
+                DOM.insertChild(tr, cell.getElement(), index);
+                adopt(cell);
+                visibleCells.insertElementAt(cell, index);
+
+            } else if (index == visibleCells.size()) {
+                // simply append
+                DOM.appendChild(tr, cell.getElement());
+                adopt(cell);
+                visibleCells.add(cell);
+            } else {
+                throw new RuntimeException(
+                        "Header cells must be appended in order");
+            }
+        }
+
+        public HeaderCell getHeaderCell(int index) {
+            if (index < visibleCells.size()) {
+                return (HeaderCell) visibleCells.get(index);
+            } else {
+                return null;
+            }
+        }
+
+        /**
+         * Get's HeaderCell by it's column Key.
+         * 
+         * Note that this returns HeaderCell even if it is currently collapsed.
+         * 
+         * @param cid
+         *            Column key of accessed HeaderCell
+         * @return HeaderCell
+         */
+        public HeaderCell getHeaderCell(String cid) {
+            return availableCells.get(cid);
+        }
+
+        public void moveCell(int oldIndex, int newIndex) {
+            final HeaderCell hCell = getHeaderCell(oldIndex);
+            final Element cell = hCell.getElement();
+
+            visibleCells.remove(oldIndex);
+            DOM.removeChild(tr, cell);
+
+            DOM.insertChild(tr, cell, newIndex);
+            visibleCells.insertElementAt(hCell, newIndex);
+        }
+
+        public Iterator<Widget> iterator() {
+            return visibleCells.iterator();
+        }
+
+        @Override
+        public boolean remove(Widget w) {
+            if (visibleCells.contains(w)) {
+                visibleCells.remove(w);
+                orphan(w);
+                DOM.removeChild(DOM.getParent(w.getElement()), w.getElement());
+                return true;
+            }
+            return false;
+        }
+
+        public void removeCell(String colKey) {
+            final HeaderCell c = getHeaderCell(colKey);
+            remove(c);
+        }
+
+        private void focusSlot(int index) {
+            removeSlotFocus();
+            if (index > 0) {
+                DOM.setElementProperty(DOM.getFirstChild(DOM.getChild(tr,
+                        index - 1)), "className", CLASSNAME + "-resizer "
+                        + CLASSNAME + "-focus-slot-right");
+            } else {
+                DOM.setElementProperty(DOM.getFirstChild(DOM
+                        .getChild(tr, index)), "className", CLASSNAME
+                        + "-resizer " + CLASSNAME + "-focus-slot-left");
+            }
+            focusedSlot = index;
+        }
+
+        private void removeSlotFocus() {
+            if (focusedSlot < 0) {
+                return;
+            }
+            if (focusedSlot == 0) {
+                DOM.setElementProperty(DOM.getFirstChild(DOM.getChild(tr,
+                        focusedSlot)), "className", CLASSNAME + "-resizer");
+            } else if (focusedSlot > 0) {
+                DOM.setElementProperty(DOM.getFirstChild(DOM.getChild(tr,
+                        focusedSlot - 1)), "className", CLASSNAME + "-resizer");
+            }
+            focusedSlot = -1;
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            if (enabled) {
+                if (event.getTarget() == columnSelector) {
+                    final int left = DOM.getAbsoluteLeft(columnSelector);
+                    final int top = DOM.getAbsoluteTop(columnSelector)
+                            + DOM.getElementPropertyInt(columnSelector,
+                                    "offsetHeight");
+                    client.getContextMenu().showAt(this, left, top);
+                }
+            }
+        }
+
+        class VisibleColumnAction extends Action {
+
+            String colKey;
+            private boolean collapsed;
+
+            public VisibleColumnAction(String colKey) {
+                super(VScrollTable.TableHead.this);
+                this.colKey = colKey;
+                caption = tHead.getHeaderCell(colKey).getCaption();
+            }
+
+            @Override
+            public void execute() {
+                client.getContextMenu().hide();
+                // toggle selected column
+                if (collapsedColumns.contains(colKey)) {
+                    collapsedColumns.remove(colKey);
+                } else {
+                    tHead.removeCell(colKey);
+                    collapsedColumns.add(colKey);
+                    lazyAdjustColumnWidths.schedule(1);
+                }
+
+                // update variable to server
+                client.updateVariable(paintableId, "collapsedcolumns",
+                        collapsedColumns.toArray(), false);
+                // let rowRequestHandler determine proper rows
+                rowRequestHandler.refreshContent();
+            }
+
+            public void setCollapsed(boolean b) {
+                collapsed = b;
+            }
+
+            /**
+             * Override default method to distinguish on/off columns
+             */
+            @Override
+            public String getHTML() {
+                final StringBuffer buf = new StringBuffer();
+                if (collapsed) {
+                    buf.append("<span class=\"i-off\">");
+                } else {
+                    buf.append("<span class=\"i-on\">");
+                }
+                buf.append(super.getHTML());
+                buf.append("</span>");
+
+                return buf.toString();
+            }
+
+        }
+
+        /*
+         * Returns columns as Action array for column select popup
+         */
+        public Action[] getActions() {
+            Object[] cols;
+            if (columnReordering) {
+                cols = columnOrder;
+            } else {
+                // if columnReordering is disabled, we need different way to get
+                // all available columns
+                cols = visibleColOrder;
+                cols = new Object[visibleColOrder.length
+                        + collapsedColumns.size()];
+                int i;
+                for (i = 0; i < visibleColOrder.length; i++) {
+                    cols[i] = visibleColOrder[i];
+                }
+                for (final Iterator<String> it = collapsedColumns.iterator(); it
+                        .hasNext();) {
+                    cols[i++] = it.next();
+                }
+            }
+            final Action[] actions = new Action[cols.length];
+
+            for (int i = 0; i < cols.length; i++) {
+                final String cid = (String) cols[i];
+                final HeaderCell c = getHeaderCell(cid);
+                final VisibleColumnAction a = new VisibleColumnAction(c
+                        .getColKey());
+                a.setCaption(c.getCaption());
+                if (!c.isEnabled()) {
+                    a.setCollapsed(true);
+                }
+                actions[i] = a;
+            }
+            return actions;
+        }
+
+        public ApplicationConnection getClient() {
+            return client;
+        }
+
+        public String getPaintableId() {
+            return paintableId;
+        }
+
+        /**
+         * Returns column alignments for visible columns
+         */
+        public char[] getColumnAlignments() {
+            final Iterator<Widget> it = visibleCells.iterator();
+            final char[] aligns = new char[visibleCells.size()];
+            int colIndex = 0;
+            while (it.hasNext()) {
+                aligns[colIndex++] = ((HeaderCell) it.next()).getAlign();
+            }
+            return aligns;
+        }
+
+    }
+
+    /**
+     * This Panel can only contain VScrollTableRow type of widgets. This
+     * "simulates" very large table, keeping spacers which take room of
+     * unrendered rows.
+     * 
+     */
+    public class VScrollTableBody extends Panel {
+
+        public static final int DEFAULT_ROW_HEIGHT = 24;
+
+        private int rowHeight = -1;
+
+        private final List<Widget> renderedRows = new Vector<Widget>();
+
+        /**
+         * Due some optimizations row height measuring is deferred and initial
+         * set of rows is rendered detached. Flag set on when table body has
+         * been attached in dom and rowheight has been measured.
+         */
+        private boolean tBodyMeasurementsDone = false;
+
+        Element preSpacer = DOM.createDiv();
+        Element postSpacer = DOM.createDiv();
+
+        Element container = DOM.createDiv();
+
+        TableSectionElement tBodyElement = Document.get().createTBodyElement();
+        Element table = DOM.createTable();
+
+        private int firstRendered;
+
+        private int lastRendered;
+
+        private char[] aligns;
+
+        VScrollTableBody() {
+            constructDOM();
+
+            setElement(container);
+        }
+
+        private void constructDOM() {
+            DOM.setElementProperty(table, "className", CLASSNAME + "-table");
+            if (BrowserInfo.get().isIE()) {
+                table.setPropertyInt("cellSpacing", 0);
+            }
+            DOM.setElementProperty(preSpacer, "className", CLASSNAME
+                    + "-row-spacer");
+            DOM.setElementProperty(postSpacer, "className", CLASSNAME
+                    + "-row-spacer");
+
+            table.appendChild(tBodyElement);
+            DOM.appendChild(container, preSpacer);
+            DOM.appendChild(container, table);
+            DOM.appendChild(container, postSpacer);
+
+        }
+
+        public int getAvailableWidth() {
+            int availW = bodyContainer.getOffsetWidth() - getBorderWidth();
+            return availW;
+        }
+
+        public void renderInitialRows(UIDL rowData, int firstIndex, int rows) {
+            firstRendered = firstIndex;
+            lastRendered = firstIndex + rows - 1;
+            final Iterator<?> it = rowData.getChildIterator();
+            aligns = tHead.getColumnAlignments();
+            while (it.hasNext()) {
+                final VScrollTableRow row = new VScrollTableRow((UIDL) it
+                        .next(), aligns);
+                addRow(row);
+            }
+            if (isAttached()) {
+                fixSpacers();
+            }
+        }
+
+        public void renderRows(UIDL rowData, int firstIndex, int rows) {
+            // FIXME REVIEW
+            aligns = tHead.getColumnAlignments();
+            final Iterator<?> it = rowData.getChildIterator();
+            if (firstIndex == lastRendered + 1) {
+                while (it.hasNext()) {
+                    final VScrollTableRow row = createRow((UIDL) it.next());
+                    addRow(row);
+                    lastRendered++;
+                }
+                fixSpacers();
+            } else if (firstIndex + rows == firstRendered) {
+                final VScrollTableRow[] rowArray = new VScrollTableRow[rows];
+                int i = rows;
+                while (it.hasNext()) {
+                    i--;
+                    rowArray[i] = createRow((UIDL) it.next());
+                }
+                for (i = 0; i < rows; i++) {
+                    addRowBeforeFirstRendered(rowArray[i]);
+                    firstRendered--;
+                }
+            } else {
+                // completely new set of rows
+                while (lastRendered + 1 > firstRendered) {
+                    unlinkRow(false);
+                }
+                final VScrollTableRow row = createRow((UIDL) it.next());
+                firstRendered = firstIndex;
+                lastRendered = firstIndex - 1;
+                addRow(row);
+                lastRendered++;
+                setContainerHeight();
+                fixSpacers();
+                while (it.hasNext()) {
+                    addRow(createRow((UIDL) it.next()));
+                    lastRendered++;
+                }
+                fixSpacers();
+            }
+            // this may be a new set of rows due content change,
+            // ensure we have proper cache rows
+            int reactFirstRow = (int) (firstRowInViewPort - pageLength
+                    * CACHE_REACT_RATE);
+            int reactLastRow = (int) (firstRowInViewPort + pageLength + pageLength
+                    * CACHE_REACT_RATE);
+            if (reactFirstRow < 0) {
+                reactFirstRow = 0;
+            }
+            if (reactLastRow > totalRows) {
+                reactLastRow = totalRows - 1;
+            }
+            if (lastRendered < reactLastRow) {
+                // get some cache rows below visible area
+                rowRequestHandler.setReqFirstRow(lastRendered + 1);
+                rowRequestHandler.setReqRows(reactLastRow - lastRendered - 1);
+                rowRequestHandler.deferRowFetch(1);
+            } else if (tBody.getFirstRendered() > reactFirstRow) {
+                /*
+                 * Branch for fetching cache above visible area.
+                 * 
+                 * If cache needed for both before and after visible area, this
+                 * will be rendered after-cache is reveived and rendered. So in
+                 * some rare situations table may take two cache visits to
+                 * server.
+                 */
+                rowRequestHandler.setReqFirstRow(reactFirstRow);
+                rowRequestHandler.setReqRows(firstRendered - reactFirstRow);
+                rowRequestHandler.deferRowFetch(1);
+            }
+        }
+
+        /**
+         * This method is used to instantiate new rows for this table. It
+         * automatically sets correct widths to rows cells and assigns correct
+         * client reference for child widgets.
+         * 
+         * This method can be called only after table has been initialized
+         * 
+         * @param uidl
+         */
+        private VScrollTableRow createRow(UIDL uidl) {
+            final VScrollTableRow row = new VScrollTableRow(uidl, aligns);
+            final int cells = DOM.getChildCount(row.getElement());
+            for (int i = 0; i < cells; i++) {
+                final Element cell = DOM.getChild(row.getElement(), i);
+                int w = VScrollTable.this.getColWidth(getColKeyByIndex(i));
+                if (w < 0) {
+                    w = 0;
+                }
+                cell.getFirstChildElement().getStyle()
+                        .setPropertyPx("width", w);
+                cell.getStyle().setPropertyPx("width", w);
+            }
+            return row;
+        }
+
+        private void addRowBeforeFirstRendered(VScrollTableRow row) {
+            VScrollTableRow first = null;
+            if (renderedRows.size() > 0) {
+                first = (VScrollTableRow) renderedRows.get(0);
+            }
+            if (first != null && first.getStyleName().indexOf("-odd") == -1) {
+                row.addStyleName(CLASSNAME + "-row-odd");
+            } else {
+                row.addStyleName(CLASSNAME + "-row");
+            }
+            if (row.isSelected()) {
+                row.addStyleName("i-selected");
+            }
+            tBodyElement.insertBefore(row.getElement(), tBodyElement
+                    .getFirstChild());
+            adopt(row);
+            renderedRows.add(0, row);
+        }
+
+        private void addRow(VScrollTableRow row) {
+            VScrollTableRow last = null;
+            if (renderedRows.size() > 0) {
+                last = (VScrollTableRow) renderedRows
+                        .get(renderedRows.size() - 1);
+            }
+            if (last != null && last.getStyleName().indexOf("-odd") == -1) {
+                row.addStyleName(CLASSNAME + "-row-odd");
+            } else {
+                row.addStyleName(CLASSNAME + "-row");
+            }
+            if (row.isSelected()) {
+                row.addStyleName("i-selected");
+            }
+            tBodyElement.appendChild(row.getElement());
+            adopt(row);
+            renderedRows.add(row);
+        }
+
+        public Iterator<Widget> iterator() {
+            return renderedRows.iterator();
+        }
+
+        /**
+         * @return false if couldn't remove row
+         */
+        public boolean unlinkRow(boolean fromBeginning) {
+            if (lastRendered - firstRendered < 0) {
+                return false;
+            }
+            int index;
+            if (fromBeginning) {
+                index = 0;
+                firstRendered++;
+            } else {
+                index = renderedRows.size() - 1;
+                lastRendered--;
+            }
+            if (index >= 0) {
+                final VScrollTableRow toBeRemoved = (VScrollTableRow) renderedRows
+                        .get(index);
+                lazyUnregistryBag.add(toBeRemoved);
+                tBodyElement.removeChild(toBeRemoved.getElement());
+                orphan(toBeRemoved);
+                renderedRows.remove(index);
+                fixSpacers();
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        @Override
+        public boolean remove(Widget w) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        protected void onAttach() {
+            super.onAttach();
+            setContainerHeight();
+        }
+
+        /**
+         * Fix container blocks height according to totalRows to avoid
+         * "bouncing" when scrolling
+         */
+        private void setContainerHeight() {
+            fixSpacers();
+            DOM.setStyleAttribute(container, "height", totalRows
+                    * getRowHeight() + "px");
+        }
+
+        private void fixSpacers() {
+            int prepx = getRowHeight() * firstRendered;
+            if (prepx < 0) {
+                prepx = 0;
+            }
+            DOM.setStyleAttribute(preSpacer, "height", prepx + "px");
+            int postpx = getRowHeight() * (totalRows - 1 - lastRendered);
+            if (postpx < 0) {
+                postpx = 0;
+            }
+            DOM.setStyleAttribute(postSpacer, "height", postpx + "px");
+        }
+
+        public int getRowHeight() {
+            return getRowHeight(false);
+        }
+
+        public int getRowHeight(boolean forceUpdate) {
+            if (tBodyMeasurementsDone && !forceUpdate) {
+                return rowHeight;
+            } else {
+
+                if (tBodyElement.getRows().getLength() > 0) {
+                    rowHeight = getTableHeight()
+                            / tBodyElement.getRows().getLength();
+                } else {
+                    if (isAttached()) {
+                        // measure row height by adding a dummy row
+                        VScrollTableRow scrollTableRow = new VScrollTableRow();
+                        tBodyElement.appendChild(scrollTableRow.getElement());
+                        getRowHeight(forceUpdate);
+                        tBodyElement.removeChild(scrollTableRow.getElement());
+                    } else {
+                        // TODO investigate if this can never happen anymore
+                        return DEFAULT_ROW_HEIGHT;
+                    }
+                }
+                tBodyMeasurementsDone = true;
+                return rowHeight;
+            }
+        }
+
+        public int getTableHeight() {
+            return table.getOffsetHeight();
+        }
+
+        /**
+         * Returns the width available for column content.
+         * 
+         * @param columnIndex
+         * @return
+         */
+        public int getColWidth(int columnIndex) {
+            if (tBodyMeasurementsDone) {
+                NodeList<TableRowElement> rows = tBodyElement.getRows();
+                if (rows.getLength() == 0) {
+                    // no rows yet rendered
+                    return 0;
+                } else {
+                    com.google.gwt.dom.client.Element wrapperdiv = rows
+                            .getItem(0).getCells().getItem(columnIndex)
+                            .getFirstChildElement();
+                    return wrapperdiv.getOffsetWidth();
+                }
+            } else {
+                return 0;
+            }
+        }
+
+        /**
+         * Sets the content width of a column.
+         * 
+         * Due IE limitation, we must set the width to a wrapper elements inside
+         * table cells (with overflow hidden, which does not work on td
+         * elements).
+         * 
+         * To get this work properly crossplatform, we will also set the width
+         * of td.
+         * 
+         * @param colIndex
+         * @param w
+         */
+        public void setColWidth(int colIndex, int w) {
+            NodeList<TableRowElement> rows2 = tBodyElement.getRows();
+            final int rows = rows2.getLength();
+            for (int i = 0; i < rows; i++) {
+                TableRowElement row = rows2.getItem(i);
+                TableCellElement cell = row.getCells().getItem(colIndex);
+                cell.getFirstChildElement().getStyle()
+                        .setPropertyPx("width", w);
+                cell.getStyle().setPropertyPx("width", w);
+            }
+        }
+
+        private int cellExtraWidth = -1;
+
+        /**
+         * Method to return the space used for cell paddings + border.
+         */
+        private int getCellExtraWidth() {
+            if (cellExtraWidth < 0) {
+                detectExtrawidth();
+            }
+            return cellExtraWidth;
+        }
+
+        private void detectExtrawidth() {
+            NodeList<TableRowElement> rows = tBodyElement.getRows();
+            if (rows.getLength() == 0) {
+                /* need to temporary add empty row and detect */
+                VScrollTableRow scrollTableRow = new VScrollTableRow();
+                tBodyElement.appendChild(scrollTableRow.getElement());
+                detectExtrawidth();
+                tBodyElement.removeChild(scrollTableRow.getElement());
+            } else {
+                TableRowElement item = rows.getItem(0);
+                TableCellElement firstTD = item.getCells().getItem(0);
+                com.google.gwt.dom.client.Element wrapper = firstTD
+                        .getFirstChildElement();
+                cellExtraWidth = firstTD.getOffsetWidth()
+                        - wrapper.getOffsetWidth();
+            }
+        }
+
+        private void reLayoutComponents() {
+            for (Widget w : this) {
+                VScrollTableRow r = (VScrollTableRow) w;
+                for (Widget widget : r) {
+                    client.handleComponentRelativeSize(widget);
+                }
+            }
+        }
+
+        public int getLastRendered() {
+            return lastRendered;
+        }
+
+        public int getFirstRendered() {
+            return firstRendered;
+        }
+
+        public void moveCol(int oldIndex, int newIndex) {
+
+            // loop all rows and move given index to its new place
+            final Iterator<?> rows = iterator();
+            while (rows.hasNext()) {
+                final VScrollTableRow row = (VScrollTableRow) rows.next();
+
+                final Element td = DOM.getChild(row.getElement(), oldIndex);
+                DOM.removeChild(row.getElement(), td);
+
+                DOM.insertChild(row.getElement(), td, newIndex);
+
+            }
+
+        }
+
+        public class VScrollTableRow extends Panel implements ActionOwner,
+                Container {
+
+            Vector<Widget> childWidgets = new Vector<Widget>();
+            private boolean selected = false;
+            private final int rowKey;
+            private List<UIDL> pendingComponentPaints;
+
+            private String[] actionKeys = null;
+            private TableRowElement rowElement;
+
+            private VScrollTableRow(int rowKey) {
+                this.rowKey = rowKey;
+                rowElement = Document.get().createTRElement();
+                setElement(rowElement);
+                DOM.sinkEvents(getElement(), Event.ONCLICK | Event.ONDBLCLICK
+                        | Event.ONCONTEXTMENU);
+            }
+
+            private void paintComponent(Paintable p, UIDL uidl) {
+                if (isAttached()) {
+                    p.updateFromUIDL(uidl, client);
+                } else {
+                    if (pendingComponentPaints == null) {
+                        pendingComponentPaints = new LinkedList<UIDL>();
+                    }
+                    pendingComponentPaints.add(uidl);
+                }
+            }
+
+            @Override
+            protected void onAttach() {
+                super.onAttach();
+                if (pendingComponentPaints != null) {
+                    for (UIDL uidl : pendingComponentPaints) {
+                        Paintable paintable = client.getPaintable(uidl);
+                        paintable.updateFromUIDL(uidl, client);
+                    }
+                }
+            }
+
+            public String getKey() {
+                return String.valueOf(rowKey);
+            }
+
+            public VScrollTableRow(UIDL uidl, char[] aligns) {
+                this(uidl.getIntAttribute("key"));
+
+                String rowStyle = uidl.getStringAttribute("rowstyle");
+                if (rowStyle != null) {
+                    addStyleName(CLASSNAME + "-row-" + rowStyle);
+                }
+
+                tHead.getColumnAlignments();
+                int col = 0;
+                int visibleColumnIndex = -1;
+
+                // row header
+                if (showRowHeaders) {
+                    addCell(buildCaptionHtmlSnippet(uidl), aligns[col++], "",
+                            true);
+                }
+
+                if (uidl.hasAttribute("al")) {
+                    actionKeys = uidl.getStringArrayAttribute("al");
+                }
+
+                final Iterator<?> cells = uidl.getChildIterator();
+                while (cells.hasNext()) {
+                    final Object cell = cells.next();
+                    visibleColumnIndex++;
+
+                    String columnId = visibleColOrder[visibleColumnIndex];
+
+                    String style = "";
+                    if (uidl.hasAttribute("style-" + columnId)) {
+                        style = uidl.getStringAttribute("style-" + columnId);
+                    }
+
+                    if (cell instanceof String) {
+                        addCell(cell.toString(), aligns[col++], style, false);
+                    } else {
+                        final Paintable cellContent = client
+                                .getPaintable((UIDL) cell);
+
+                        addCell((Widget) cellContent, aligns[col++], style);
+                        paintComponent(cellContent, (UIDL) cell);
+                    }
+                }
+                if (uidl.hasAttribute("selected") && !isSelected()) {
+                    toggleSelection();
+                }
+            }
+
+            /**
+             * Add a dummy row, used for measurements if Table is empty.
+             */
+            public VScrollTableRow() {
+                this(0);
+                addStyleName(CLASSNAME + "-row");
+                addCell("_", 'b', "", true);
+            }
+
+            public void addCell(String text, char align, String style,
+                    boolean textIsHTML) {
+                // String only content is optimized by not using Label widget
+                final Element td = DOM.createTD();
+                final Element container = DOM.createDiv();
+                String className = CLASSNAME + "-cell-content";
+                if (style != null && !style.equals("")) {
+                    className += " " + CLASSNAME + "-cell-content-" + style;
+                }
+                td.setClassName(className);
+                container.setClassName(CLASSNAME + "-cell-wrapper");
+                if (textIsHTML) {
+                    container.setInnerHTML(text);
+                } else {
+                    container.setInnerText(text);
+                }
+                if (align != ALIGN_LEFT) {
+                    switch (align) {
+                    case ALIGN_CENTER:
+                        container.getStyle().setProperty("textAlign", "center");
+                        break;
+                    case ALIGN_RIGHT:
+                    default:
+                        container.getStyle().setProperty("textAlign", "right");
+                        break;
+                    }
+                }
+                td.appendChild(container);
+                getElement().appendChild(td);
+            }
+
+            public void addCell(Widget w, char align, String style) {
+                final Element td = DOM.createTD();
+                final Element container = DOM.createDiv();
+                String className = CLASSNAME + "-cell-content";
+                if (style != null && !style.equals("")) {
+                    className += " " + CLASSNAME + "-cell-content-" + style;
+                }
+                td.setClassName(className);
+                container.setClassName(CLASSNAME + "-cell-wrapper");
+                // TODO most components work with this, but not all (e.g.
+                // Select)
+                // Old comment: make widget cells respect align.
+                // text-align:center for IE, margin: auto for others
+                if (align != ALIGN_LEFT) {
+                    switch (align) {
+                    case ALIGN_CENTER:
+                        container.getStyle().setProperty("textAlign", "center");
+                        break;
+                    case ALIGN_RIGHT:
+                    default:
+                        container.getStyle().setProperty("textAlign", "right");
+                        break;
+                    }
+                }
+                td.appendChild(container);
+                getElement().appendChild(td);
+                // ensure widget not attached to another element (possible tBody
+                // change)
+                w.removeFromParent();
+                container.appendChild(w.getElement());
+                adopt(w);
+                childWidgets.add(w);
+            }
+
+            public Iterator<Widget> iterator() {
+                return childWidgets.iterator();
+            }
+
+            @Override
+            public boolean remove(Widget w) {
+                if (childWidgets.contains(w)) {
+                    orphan(w);
+                    DOM.removeChild(DOM.getParent(w.getElement()), w
+                            .getElement());
+                    childWidgets.remove(w);
+                    return true;
+                } else {
+                    return false;
+                }
+            }
+
+            private void handleClickEvent(Event event, Element targetTdOrTr) {
+                if (emitClickEvents) {
+                    boolean doubleClick = (DOM.eventGetType(event) == Event.ONDBLCLICK);
+
+                    /* This row was clicked */
+                    client.updateVariable(paintableId, "clickedKey", ""
+                            + rowKey, false);
+
+                    if (getElement() == targetTdOrTr.getParentElement()) {
+                        /* A specific column was clicked */
+                        int childIndex = DOM.getChildIndex(getElement(),
+                                targetTdOrTr);
+                        String colKey = null;
+                        colKey = tHead.getHeaderCell(childIndex).getColKey();
+                        client.updateVariable(paintableId, "clickedColKey",
+                                colKey, false);
+                    }
+
+                    MouseEventDetails details = new MouseEventDetails(event);
+                    // Note: the 'immediate' logic would need to be more
+                    // involved (see #2104), but iscrolltable always sends
+                    // select event, even though nullselectionallowed wont let
+                    // the change trough. Will need to be updated if that is
+                    // changed.
+                    client
+                            .updateVariable(
+                                    paintableId,
+                                    "clickEvent",
+                                    details.toString(),
+                                    !(!doubleClick
+                                            && selectMode > Table.SELECT_MODE_NONE && immediate));
+                }
+            }
+
+            /*
+             * React on click that occur on content cells only
+             */
+            @Override
+            public void onBrowserEvent(Event event) {
+                if (enabled) {
+                    Element targetTdOrTr = getEventTargetTdOrTr(event);
+                    if (targetTdOrTr != null) {
+                        switch (DOM.eventGetType(event)) {
+                        case Event.ONCLICK:
+                            handleClickEvent(event, targetTdOrTr);
+                            if (selectMode > Table.SELECT_MODE_NONE) {
+                                toggleSelection();
+                                // Note: changing the immediateness of this
+                                // might
+                                // require changes to "clickEvent" immediateness
+                                // also.
+                                client.updateVariable(paintableId, "selected",
+                                        selectedRowKeys.toArray(), immediate);
+                            }
+                            break;
+                        case Event.ONDBLCLICK:
+                            handleClickEvent(event, targetTdOrTr);
+                            break;
+                        case Event.ONCONTEXTMENU:
+                            showContextMenu(event);
+                            break;
+                        default:
+                            break;
+                        }
+                    }
+                }
+                super.onBrowserEvent(event);
+            }
+
+            /**
+             * Finds the TD that the event interacts with. Returns null if the
+             * target of the event should not be handled. If the event target is
+             * the row directly this method returns the TR element instead of
+             * the TD.
+             * 
+             * @param event
+             * @return TD or TR element that the event targets (the actual event
+             *         target is this element or a child of it)
+             */
+            private Element getEventTargetTdOrTr(Event event) {
+                Element targetTdOrTr = null;
+
+                final Element eventTarget = DOM.eventGetTarget(event);
+                final Element eventTargetParent = DOM.getParent(eventTarget);
+                final Element eventTargetGrandParent = DOM
+                        .getParent(eventTargetParent);
+
+                final Element thisTrElement = getElement();
+
+                if (eventTarget == thisTrElement) {
+                    // This was a click on the TR element
+                    targetTdOrTr = eventTarget;
+                    // rowTarget = true;
+                } else if (thisTrElement == eventTargetParent) {
+                    // Target parent is the TR, so the actual target is the TD
+                    targetTdOrTr = eventTarget;
+                } else if (thisTrElement == eventTargetGrandParent) {
+                    // Target grand parent is the TR, so the parent is the TD
+                    targetTdOrTr = eventTargetParent;
+                } else {
+                    /*
+                     * This is a workaround to make Labels and Embedded in a
+                     * Table clickable (see #2688). It is really not a fix as it
+                     * does not work for a custom component (not extending
+                     * VLabel/VEmbedded) or for read only textfields etc.
+                     */
+                    Element tdElement = eventTargetParent;
+                    while (DOM.getParent(tdElement) != thisTrElement) {
+                        tdElement = DOM.getParent(tdElement);
+                    }
+
+                    Element componentElement = tdElement.getFirstChildElement()
+                            .getFirstChildElement().cast();
+                    Widget widget = (Widget) client
+                            .getPaintable(componentElement);
+                    if (widget instanceof VLabel || widget instanceof VEmbedded) {
+                        targetTdOrTr = tdElement;
+                    }
+                }
+
+                return targetTdOrTr;
+            }
+
+            public void showContextMenu(Event event) {
+                if (enabled && actionKeys != null) {
+                    int left = event.getClientX();
+                    int top = event.getClientY();
+                    top += Window.getScrollTop();
+                    left += Window.getScrollLeft();
+                    client.getContextMenu().showAt(this, left, top);
+                }
+                event.cancelBubble(true);
+                event.preventDefault();
+            }
+
+            public boolean isSelected() {
+                return selected;
+            }
+
+            private void toggleSelection() {
+                selected = !selected;
+                if (selected) {
+                    if (selectMode == Table.SELECT_MODE_SINGLE) {
+                        deselectAll();
+                    }
+                    selectedRowKeys.add(String.valueOf(rowKey));
+                    addStyleName("i-selected");
+                } else {
+                    selectedRowKeys.remove(String.valueOf(rowKey));
+                    removeStyleName("i-selected");
+                }
+            }
+
+            /*
+             * (non-Javadoc)
+             * 
+             * @see
+             * com.vaadin.terminal.gwt.client.ui.IActionOwner#getActions
+             * ()
+             */
+            public Action[] getActions() {
+                if (actionKeys == null) {
+                    return new Action[] {};
+                }
+                final Action[] actions = new Action[actionKeys.length];
+                for (int i = 0; i < actions.length; i++) {
+                    final String actionKey = actionKeys[i];
+                    final TreeAction a = new TreeAction(this, String
+                            .valueOf(rowKey), actionKey);
+                    a.setCaption(getActionCaption(actionKey));
+                    a.setIconUrl(getActionIcon(actionKey));
+                    actions[i] = a;
+                }
+                return actions;
+            }
+
+            public ApplicationConnection getClient() {
+                return client;
+            }
+
+            public String getPaintableId() {
+                return paintableId;
+            }
+
+            public RenderSpace getAllocatedSpace(Widget child) {
+                int w = 0;
+                int i = getColIndexOf(child);
+                HeaderCell headerCell = tHead.getHeaderCell(i);
+                if (headerCell != null) {
+                    if (initializedAndAttached) {
+                        w = headerCell.getWidth();
+                    } else {
+                        // header offset width is not absolutely correct value,
+                        // but a best guess (expecting similar content in all
+                        // columns ->
+                        // if one component is relative width so are others)
+                        w = headerCell.getOffsetWidth() - getCellExtraWidth();
+                    }
+                }
+                return new RenderSpace(w, getRowHeight());
+            }
+
+            private int getColIndexOf(Widget child) {
+                com.google.gwt.dom.client.Element widgetCell = child
+                        .getElement().getParentElement().getParentElement();
+                NodeList<TableCellElement> cells = rowElement.getCells();
+                for (int i = 0; i < cells.getLength(); i++) {
+                    if (cells.getItem(i) == widgetCell) {
+                        return i;
+                    }
+                }
+                return -1;
+            }
+
+            public boolean hasChildComponent(Widget component) {
+                return childWidgets.contains(component);
+            }
+
+            public void replaceChildComponent(Widget oldComponent,
+                    Widget newComponent) {
+                com.google.gwt.dom.client.Element parentElement = oldComponent
+                        .getElement().getParentElement();
+                int index = childWidgets.indexOf(oldComponent);
+                oldComponent.removeFromParent();
+
+                parentElement.appendChild(newComponent.getElement());
+                childWidgets.insertElementAt(newComponent, index);
+                adopt(newComponent);
+
+            }
+
+            public boolean requestLayout(Set<Paintable> children) {
+                // row size should never change and system wouldn't event
+                // survive as this is a kind of fake paitable
+                return true;
+            }
+
+            public void updateCaption(Paintable component, UIDL uidl) {
+                // NOP, not rendered
+            }
+
+            public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+                // Should never be called,
+                // Component container interface faked here to get layouts
+                // render properly
+            }
+        }
+    }
+
+    public void deselectAll() {
+        final Object[] keys = selectedRowKeys.toArray();
+        for (int i = 0; i < keys.length; i++) {
+            final VScrollTableRow row = getRenderedRowByKey((String) keys[i]);
+            if (row != null && row.isSelected()) {
+                row.toggleSelection();
+            }
+        }
+        // still ensure all selects are removed from (not necessary rendered)
+        selectedRowKeys.clear();
+
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (this.width.equals(width)) {
+            return;
+        }
+
+        this.width = width;
+        if (width != null && !"".equals(width)) {
+            super.setWidth(width);
+            int innerPixels = getOffsetWidth() - getBorderWidth();
+            if (innerPixels < 0) {
+                innerPixels = 0;
+            }
+            setContentWidth(innerPixels);
+
+            if (!rendering) {
+                // readjust undefined width columns
+                lazyAdjustColumnWidths.cancel();
+                lazyAdjustColumnWidths.schedule(LAZY_COLUMN_ADJUST_TIMEOUT);
+            }
+
+        } else {
+            super.setWidth("");
+        }
+
+    }
+
+    private static final int LAZY_COLUMN_ADJUST_TIMEOUT = 300;
+
+    private final Timer lazyAdjustColumnWidths = new Timer() {
+        /**
+         * Check for column widths, and available width, to see if we can fix
+         * column widths "optimally". Doing this lazily to avoid expensive
+         * calculation when resizing is not yet finished.
+         */
+        @Override
+        public void run() {
+
+            Iterator<Widget> headCells = tHead.iterator();
+            int usedMinimumWidth = 0;
+            int totalExplicitColumnsWidths = 0;
+            float expandRatioDivider = 0;
+            int colIndex = 0;
+            while (headCells.hasNext()) {
+                final HeaderCell hCell = (HeaderCell) headCells.next();
+                if (hCell.isDefinedWidth()) {
+                    totalExplicitColumnsWidths += hCell.getWidth();
+                    usedMinimumWidth += hCell.getWidth();
+                } else {
+                    usedMinimumWidth += hCell.getNaturalColumnWidth(colIndex);
+                    expandRatioDivider += hCell.getExpandRatio();
+                }
+                colIndex++;
+            }
+
+            int availW = tBody.getAvailableWidth();
+            // Hey IE, are you really sure about this?
+            availW = tBody.getAvailableWidth();
+            availW -= tBody.getCellExtraWidth() * visibleColOrder.length;
+            if (willHaveScrollbars()) {
+                availW -= Util.getNativeScrollbarSize();
+            }
+
+            int extraSpace = availW - usedMinimumWidth;
+            if (extraSpace < 0) {
+                extraSpace = 0;
+            }
+
+            int totalUndefinedNaturaWidths = usedMinimumWidth
+                    - totalExplicitColumnsWidths;
+
+            // we have some space that can be divided optimally
+            HeaderCell hCell;
+            colIndex = 0;
+            headCells = tHead.iterator();
+            while (headCells.hasNext()) {
+                hCell = (HeaderCell) headCells.next();
+                if (!hCell.isDefinedWidth()) {
+                    int w = hCell.getNaturalColumnWidth(colIndex);
+                    int newSpace;
+                    if (expandRatioDivider > 0) {
+                        // divide excess space by expand ratios
+                        newSpace = (int) (w + extraSpace
+                                * hCell.getExpandRatio() / expandRatioDivider);
+                    } else {
+                        if (totalUndefinedNaturaWidths != 0) {
+                            // divide relatively to natural column widths
+                            newSpace = w + extraSpace * w
+                                    / totalUndefinedNaturaWidths;
+                        } else {
+                            newSpace = w;
+                        }
+                    }
+                    setColWidth(colIndex, newSpace, false);
+                }
+                colIndex++;
+            }
+            Util.runWebkitOverflowAutoFix(bodyContainer.getElement());
+            tBody.reLayoutComponents();
+        }
+    };
+
+    /**
+     * helper to set pixel size of head and body part
+     * 
+     * @param pixels
+     */
+    private void setContentWidth(int pixels) {
+        tHead.setWidth(pixels + "px");
+        bodyContainer.setWidth(pixels + "px");
+    }
+
+    private int borderWidth = -1;
+
+    /**
+     * @return border left + border right
+     */
+    private int getBorderWidth() {
+        if (borderWidth < 0) {
+            borderWidth = Util.measureHorizontalPaddingAndBorder(bodyContainer
+                    .getElement(), 2);
+            if (borderWidth < 0) {
+                borderWidth = 0;
+            }
+        }
+        return borderWidth;
+    }
+
+    /**
+     * Ensures scrollable area is properly sized.
+     */
+    private void setContainerHeight() {
+        if (height != null && !"".equals(height)) {
+            int contentH = getOffsetHeight() - tHead.getOffsetHeight();
+            contentH -= getContentAreaBorderHeight();
+            if (contentH < 0) {
+                contentH = 0;
+            }
+            bodyContainer.setHeight(contentH + "px");
+        }
+    }
+
+    private int contentAreaBorderHeight = -1;
+
+    /**
+     * @return border top + border bottom of the scrollable area of table
+     */
+    private int getContentAreaBorderHeight() {
+        if (contentAreaBorderHeight < 0) {
+            DOM.setStyleAttribute(bodyContainer.getElement(), "overflow",
+                    "hidden");
+            contentAreaBorderHeight = bodyContainer.getOffsetHeight()
+                    - bodyContainer.getElement().getPropertyInt("clientHeight");
+            DOM.setStyleAttribute(bodyContainer.getElement(), "overflow",
+                    "auto");
+        }
+        return contentAreaBorderHeight;
+    }
+
+    @Override
+    public void setHeight(String height) {
+        this.height = height;
+        super.setHeight(height);
+        setContainerHeight();
+    }
+
+    /*
+     * Overridden due Table might not survive of visibility change (scroll pos
+     * lost). Example ITabPanel just set contained components invisible and back
+     * when changing tabs.
+     */
+    @Override
+    public void setVisible(boolean visible) {
+        if (isVisible() != visible) {
+            super.setVisible(visible);
+            if (initializedAndAttached) {
+                if (visible) {
+                    DeferredCommand.addCommand(new Command() {
+                        public void execute() {
+                            bodyContainer.setScrollPosition(firstRowInViewPort
+                                    * tBody.getRowHeight());
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    /**
+     * Helper function to build html snippet for column or row headers
+     * 
+     * @param uidl
+     *            possibly with values caption and icon
+     * @return html snippet containing possibly an icon + caption text
+     */
+    private String buildCaptionHtmlSnippet(UIDL uidl) {
+        String s = uidl.getStringAttribute("caption");
+        if (uidl.hasAttribute("icon")) {
+            s = "<img src=\""
+                    + client.translateToolkitUri(uidl
+                            .getStringAttribute("icon"))
+                    + "\" alt=\"icon\" class=\"i-icon\">" + s;
+        }
+        return s;
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSlider.java b/src/com/vaadin/terminal/gwt/client/ui/VSlider.java
new file mode 100644 (file)
index 0000000..a54e22b
--- /dev/null
@@ -0,0 +1,436 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+// \r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.user.client.Command;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.DeferredCommand;\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.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.UIDL;\r
+\r
+public class VSlider extends Widget implements Paintable, Field,\r
+        ContainerResizedListener {\r
+\r
+    public static final String CLASSNAME = "i-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 handleSize;\r
+    private double min;\r
+    private double max;\r
+    private int resolution;\r
+    private Double value;\r
+    private boolean vertical;\r
+    private int size = -1;\r
+    private boolean arrows;\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
+    public VSlider() {\r
+        super();\r
+\r
+        setElement(DOM.createDiv());\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
+        DOM.sinkEvents(getElement(), Event.MOUSEEVENTS | Event.ONMOUSEWHEEL);\r
+        DOM.sinkEvents(base, Event.ONCLICK);\r
+        DOM.sinkEvents(handle, Event.MOUSEEVENTS);\r
+        DOM.sinkEvents(smaller, Event.ONMOUSEDOWN | Event.ONMOUSEUP\r
+                | Event.ONMOUSEOUT);\r
+        DOM.sinkEvents(bigger, Event.ONMOUSEDOWN | Event.ONMOUSEUP\r
+                | Event.ONMOUSEOUT);\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
+        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
+            DeferredCommand.addCommand(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 buildBase() {\r
+        final String styleAttribute = vertical ? "height" : "width";\r
+        final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
+\r
+        if (size == -1) {\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
+                DeferredCommand.addCommand(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
+        } else {\r
+            DOM.setStyleAttribute(base, styleAttribute, size + "px");\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.doubleValue() < min) {\r
+            value = new Double(min);\r
+        } else if (value.doubleValue() > max) {\r
+            value = new Double(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))\r
+                - (2 * BASE_BORDER_WIDTH);\r
+\r
+        final int range = baseSize - handleSize;\r
+        double v = value.doubleValue();\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
+        }\r
+        final double pos = p;\r
+\r
+        DOM.setStyleAttribute(handle, styleAttribute, (Math.round(pos)) + "px");\r
+\r
+        // TODO give more detailed info when dragging and do roundup\r
+        DOM.setElementAttribute(handle, "title", "" + v);\r
+\r
+        // Update value\r
+        this.value = new Double(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 {\r
+            processBaseEvent(event);\r
+        }\r
+    }\r
+\r
+    private Timer scrollTimer;\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
+        if (scrollTimer != null) {\r
+            scrollTimer.cancel();\r
+        }\r
+        scrollTimer = new Timer() {\r
+            @Override\r
+            public void run() {\r
+                updateValueToServer();\r
+            }\r
+        };\r
+        scrollTimer.schedule(100);\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
+            if (!disabled && !readonly) {\r
+                dragging = true;\r
+                DOM.setCapture(getElement());\r
+                DOM.eventPreventDefault(event); // prevent selecting text\r
+                DOM.eventCancelBubble(event, true);\r
+            }\r
+            break;\r
+        case Event.ONMOUSEMOVE:\r
+            if (dragging) {\r
+                // DOM.setCapture(getElement());\r
+                setValueByEvent(event, false);\r
+            }\r
+            break;\r
+        case Event.ONMOUSEUP:\r
+            dragging = false;\r
+            DOM.releaseCapture(getElement());\r
+            setValueByEvent(event, true);\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
+        } else if (DOM.eventGetType(event) == Event.ONMOUSEDOWN && dragging) {\r
+            dragging = false;\r
+            DOM.releaseCapture(getElement());\r
+            setValueByEvent(event, true);\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 = vertical ? DOM.eventGetClientY(event) : DOM\r
+                .eventGetClientX(event);\r
+        final String domProperty = vertical ? "offsetHeight" : "offsetWidth";\r
+\r
+        final double handleSize = Integer.parseInt(DOM.getElementProperty(\r
+                handle, domProperty));\r
+        final double baseSize = Integer.parseInt(DOM.getElementProperty(base,\r
+                domProperty));\r
+        final double baseOffset = vertical ? DOM.getAbsoluteTop(base)\r
+                - handleSize / 2 : DOM.getAbsoluteLeft(base) + handleSize / 2;\r
+\r
+        if (vertical) {\r
+            v = ((baseSize - (coord - baseOffset)) / (baseSize - handleSize))\r
+                    * (max - min) + min;\r
+        } else {\r
+            v = ((coord - baseOffset) / (baseSize - handleSize)) * (max - min)\r
+                    + min;\r
+        }\r
+\r
+        if (v < min) {\r
+            v = min;\r
+        } else if (v > max) {\r
+            v = max;\r
+        }\r
+\r
+        setValue(new Double(v), updateToServer);\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
+        if (size == -1) {\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
+        } else {\r
+            DOM.setStyleAttribute(base, "height", size + "px");\r
+        }\r
+        DOM.setStyleAttribute(base, "overflow", "");\r
+    }\r
+\r
+    private void updateValueToServer() {\r
+        client.updateVariable(id, "value", value.doubleValue(), immediate);\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
new file mode 100644 (file)
index 0000000..f359156
--- /dev/null
@@ -0,0 +1,584 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Set;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderInformation;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VSplitPanel extends ComplexPanel implements Container,
+        ContainerResizedListener {
+    public static final String CLASSNAME = "i-splitpanel";
+
+    public static final int ORIENTATION_HORIZONTAL = 0;
+
+    public static final int ORIENTATION_VERTICAL = 1;
+
+    private static final int MIN_SIZE = 30;
+
+    private int orientation = ORIENTATION_HORIZONTAL;
+
+    private Widget firstChild;
+
+    private Widget secondChild;
+
+    private final Element wrapper = DOM.createDiv();
+
+    private final Element firstContainer = DOM.createDiv();
+
+    private final Element secondContainer = DOM.createDiv();
+
+    private final Element splitter = DOM.createDiv();
+
+    private boolean resizing;
+
+    private int origX;
+
+    private int origY;
+
+    private int origMouseX;
+
+    private int origMouseY;
+
+    private boolean locked = false;
+
+    private String[] componentStyleNames;
+
+    private Element draggingCurtain;
+
+    private ApplicationConnection client;
+
+    private String width = "";
+
+    private String height = "";
+
+    private RenderSpace firstRenderSpace = new RenderSpace(0, 0, true);
+    private RenderSpace secondRenderSpace = new RenderSpace(0, 0, true);
+
+    RenderInformation renderInformation = new RenderInformation();
+
+    private String id;
+
+    private boolean immediate;
+
+    private boolean rendering = false;
+
+    public VSplitPanel() {
+        this(ORIENTATION_HORIZONTAL);
+    }
+
+    public VSplitPanel(int orientation) {
+        setElement(DOM.createDiv());
+        switch (orientation) {
+        case ORIENTATION_HORIZONTAL:
+            setStyleName(CLASSNAME + "-horizontal");
+            break;
+        case ORIENTATION_VERTICAL:
+        default:
+            setStyleName(CLASSNAME + "-vertical");
+            break;
+        }
+        // size below will be overridden in update from uidl, initial size
+        // needed to keep IE alive
+        setWidth(MIN_SIZE + "px");
+        setHeight(MIN_SIZE + "px");
+        constructDom();
+        setOrientation(orientation);
+        DOM.sinkEvents(splitter, (Event.MOUSEEVENTS));
+        DOM.sinkEvents(getElement(), (Event.MOUSEEVENTS));
+    }
+
+    protected void constructDom() {
+        DOM.appendChild(splitter, DOM.createDiv()); // for styling
+        DOM.appendChild(getElement(), wrapper);
+        DOM.setStyleAttribute(wrapper, "position", "relative");
+        DOM.setStyleAttribute(wrapper, "width", "100%");
+        DOM.setStyleAttribute(wrapper, "height", "100%");
+
+        DOM.appendChild(wrapper, secondContainer);
+        DOM.appendChild(wrapper, firstContainer);
+        DOM.appendChild(wrapper, splitter);
+
+        DOM.setStyleAttribute(splitter, "position", "absolute");
+        DOM.setStyleAttribute(secondContainer, "position", "absolute");
+
+        DOM.setStyleAttribute(firstContainer, "overflow", "auto");
+        DOM.setStyleAttribute(secondContainer, "overflow", "auto");
+
+    }
+
+    private void setOrientation(int orientation) {
+        this.orientation = orientation;
+        if (orientation == ORIENTATION_HORIZONTAL) {
+            DOM.setStyleAttribute(splitter, "height", "100%");
+            DOM.setStyleAttribute(splitter, "top", "0");
+            DOM.setStyleAttribute(firstContainer, "height", "100%");
+            DOM.setStyleAttribute(secondContainer, "height", "100%");
+        } else {
+            DOM.setStyleAttribute(splitter, "width", "100%");
+            DOM.setStyleAttribute(splitter, "left", "0");
+            DOM.setStyleAttribute(firstContainer, "width", "100%");
+            DOM.setStyleAttribute(secondContainer, "width", "100%");
+        }
+
+        DOM.setElementProperty(firstContainer, "className", CLASSNAME
+                + "-first-container");
+        DOM.setElementProperty(secondContainer, "className", CLASSNAME
+                + "-second-container");
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        this.client = client;
+        id = uidl.getId();
+        rendering = true;
+
+        immediate = uidl.hasAttribute("immediate");
+
+        if (client.updateComponent(this, uidl, true)) {
+            rendering = false;
+            return;
+        }
+
+        if (uidl.hasAttribute("style")) {
+            componentStyleNames = uidl.getStringAttribute("style").split(" ");
+        } else {
+            componentStyleNames = new String[0];
+        }
+
+        setLocked(uidl.getBooleanAttribute("locked"));
+
+        setStylenames();
+
+        setSplitPosition(uidl.getStringAttribute("position"));
+
+        final Paintable newFirstChild = client.getPaintable(uidl
+                .getChildUIDL(0));
+        final Paintable newSecondChild = client.getPaintable(uidl
+                .getChildUIDL(1));
+        if (firstChild != newFirstChild) {
+            if (firstChild != null) {
+                client.unregisterPaintable((Paintable) firstChild);
+            }
+            setFirstWidget((Widget) newFirstChild);
+        }
+        if (secondChild != newSecondChild) {
+            if (secondChild != null) {
+                client.unregisterPaintable((Paintable) secondChild);
+            }
+            setSecondWidget((Widget) newSecondChild);
+        }
+        newFirstChild.updateFromUIDL(uidl.getChildUIDL(0), client);
+        newSecondChild.updateFromUIDL(uidl.getChildUIDL(1), client);
+
+        renderInformation.updateSize(getElement());
+
+        if (BrowserInfo.get().isIE7()) {
+            // Part III of IE7 hack
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    iLayout();
+                }
+            });
+        }
+        rendering = false;
+
+    }
+
+    private void setLocked(boolean newValue) {
+        if (locked != newValue) {
+            locked = newValue;
+            splitterSize = -1;
+            setStylenames();
+        }
+    }
+
+    private void setSplitPosition(String pos) {
+        if (orientation == ORIENTATION_HORIZONTAL) {
+            DOM.setStyleAttribute(splitter, "left", pos);
+        } else {
+            DOM.setStyleAttribute(splitter, "top", pos);
+        }
+        iLayout();
+        client.runDescendentsLayout(this);
+
+    }
+
+    /*
+     * Calculates absolutely positioned container places/sizes (non-Javadoc)
+     * 
+     * @see com.vaadin.terminal.gwt.client.NeedsLayout#layout()
+     */
+    public void iLayout() {
+        if (!isAttached()) {
+            return;
+        }
+
+        renderInformation.updateSize(getElement());
+
+        int wholeSize;
+        int pixelPosition;
+
+        switch (orientation) {
+        case ORIENTATION_HORIZONTAL:
+            wholeSize = DOM.getElementPropertyInt(wrapper, "clientWidth");
+            pixelPosition = DOM.getElementPropertyInt(splitter, "offsetLeft");
+
+            // reposition splitter in case it is out of box
+            if (pixelPosition > 0
+                    && pixelPosition + getSplitterSize() > wholeSize) {
+                pixelPosition = wholeSize - getSplitterSize();
+                if (pixelPosition < 0) {
+                    pixelPosition = 0;
+                }
+                setSplitPosition(pixelPosition + "px");
+                return;
+            }
+
+            DOM
+                    .setStyleAttribute(firstContainer, "width", pixelPosition
+                            + "px");
+            int secondContainerWidth = (wholeSize - pixelPosition - getSplitterSize());
+            if (secondContainerWidth < 0) {
+                secondContainerWidth = 0;
+            }
+            DOM.setStyleAttribute(secondContainer, "width",
+                    secondContainerWidth + "px");
+            DOM.setStyleAttribute(secondContainer, "left",
+                    (pixelPosition + getSplitterSize()) + "px");
+
+            int contentHeight = renderInformation.getRenderedSize().getHeight();
+            firstRenderSpace.setHeight(contentHeight);
+            firstRenderSpace.setWidth(pixelPosition);
+            secondRenderSpace.setHeight(contentHeight);
+            secondRenderSpace.setWidth(secondContainerWidth);
+
+            break;
+        case ORIENTATION_VERTICAL:
+            wholeSize = DOM.getElementPropertyInt(wrapper, "clientHeight");
+            pixelPosition = DOM.getElementPropertyInt(splitter, "offsetTop");
+
+            // reposition splitter in case it is out of box
+            if (pixelPosition > 0
+                    && pixelPosition + getSplitterSize() > wholeSize) {
+                pixelPosition = wholeSize - getSplitterSize();
+                if (pixelPosition < 0) {
+                    pixelPosition = 0;
+                }
+                setSplitPosition(pixelPosition + "px");
+                return;
+            }
+
+            DOM.setStyleAttribute(firstContainer, "height", pixelPosition
+                    + "px");
+            int secondContainerHeight = (wholeSize - pixelPosition - getSplitterSize());
+            if (secondContainerHeight < 0) {
+                secondContainerHeight = 0;
+            }
+            DOM.setStyleAttribute(secondContainer, "height",
+                    secondContainerHeight + "px");
+            DOM.setStyleAttribute(secondContainer, "top",
+                    (pixelPosition + getSplitterSize()) + "px");
+
+            int contentWidth = renderInformation.getRenderedSize().getWidth();
+            firstRenderSpace.setHeight(pixelPosition);
+            firstRenderSpace.setWidth(contentWidth);
+            secondRenderSpace.setHeight(secondContainerHeight);
+            secondRenderSpace.setWidth(contentWidth);
+
+            break;
+        }
+
+        // fixes scrollbars issues on webkit based browsers
+        Util.runWebkitOverflowAutoFix(secondContainer);
+        Util.runWebkitOverflowAutoFix(firstContainer);
+
+    }
+
+    private void setFirstWidget(Widget w) {
+        if (firstChild != null) {
+            firstChild.removeFromParent();
+        }
+        super.add(w, firstContainer);
+        firstChild = w;
+    }
+
+    private void setSecondWidget(Widget w) {
+        if (secondChild != null) {
+            secondChild.removeFromParent();
+        }
+        super.add(w, secondContainer);
+        secondChild = w;
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        switch (DOM.eventGetType(event)) {
+        case Event.ONMOUSEMOVE:
+            if (resizing) {
+                onMouseMove(event);
+            }
+            break;
+        case Event.ONMOUSEDOWN:
+            onMouseDown(event);
+            break;
+        case Event.ONMOUSEUP:
+            if (resizing) {
+                onMouseUp(event);
+            }
+            break;
+        case Event.ONCLICK:
+            resizing = false;
+            break;
+        }
+    }
+
+    public void onMouseDown(Event event) {
+        if (locked) {
+            return;
+        }
+        final Element trg = DOM.eventGetTarget(event);
+        if (trg == splitter || trg == DOM.getChild(splitter, 0)) {
+            resizing = true;
+            if (BrowserInfo.get().isGecko()) {
+                showDraggingCurtain();
+            }
+            DOM.setCapture(getElement());
+            origX = DOM.getElementPropertyInt(splitter, "offsetLeft");
+            origY = DOM.getElementPropertyInt(splitter, "offsetTop");
+            origMouseX = DOM.eventGetClientX(event);
+            origMouseY = DOM.eventGetClientY(event);
+            DOM.eventCancelBubble(event, true);
+            DOM.eventPreventDefault(event);
+        }
+    }
+
+    public void onMouseMove(Event event) {
+        switch (orientation) {
+        case ORIENTATION_HORIZONTAL:
+            final int x = DOM.eventGetClientX(event);
+            onHorizontalMouseMove(x);
+            break;
+        case ORIENTATION_VERTICAL:
+        default:
+            final int y = DOM.eventGetClientY(event);
+            onVerticalMouseMove(y);
+            break;
+        }
+        iLayout();
+        // TODO Check if this is needed
+        client.runDescendentsLayout(this);
+
+    }
+
+    private void onHorizontalMouseMove(int x) {
+        int newX = origX + x - origMouseX;
+        if (newX < 0) {
+            newX = 0;
+        }
+        if (newX + getSplitterSize() > getOffsetWidth()) {
+            newX = getOffsetWidth() - getSplitterSize();
+        }
+        DOM.setStyleAttribute(splitter, "left", newX + "px");
+        updateSplitPosition(newX);
+    }
+
+    private void onVerticalMouseMove(int y) {
+        int newY = origY + y - origMouseY;
+        if (newY < 0) {
+            newY = 0;
+        }
+
+        if (newY + getSplitterSize() > getOffsetHeight()) {
+            newY = getOffsetHeight() - getSplitterSize();
+        }
+        DOM.setStyleAttribute(splitter, "top", newY + "px");
+        updateSplitPosition(newY);
+    }
+
+    public void onMouseUp(Event event) {
+        DOM.releaseCapture(getElement());
+        if (BrowserInfo.get().isGecko()) {
+            hideDraggingCurtain();
+        }
+        resizing = false;
+        onMouseMove(event);
+    }
+
+    /**
+     * Used in FF to avoid losing mouse capture when pointer is moved on an
+     * iframe.
+     */
+    private void showDraggingCurtain() {
+        if (draggingCurtain == null) {
+            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", ""
+                    + VToolkitOverlay.Z_INDEX);
+            DOM.appendChild(RootPanel.getBodyElement(), draggingCurtain);
+        }
+    }
+
+    /**
+     * Hides dragging curtain
+     */
+    private void hideDraggingCurtain() {
+        if (draggingCurtain != null) {
+            DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain);
+            draggingCurtain = null;
+        }
+    }
+
+    private int splitterSize = -1;
+
+    private int getSplitterSize() {
+        if (splitterSize < 0) {
+            if (isAttached()) {
+                switch (orientation) {
+                case ORIENTATION_HORIZONTAL:
+                    splitterSize = DOM.getElementPropertyInt(splitter,
+                            "offsetWidth");
+                    break;
+
+                default:
+                    splitterSize = DOM.getElementPropertyInt(splitter,
+                            "offsetHeight");
+                    break;
+                }
+            }
+        }
+        return splitterSize;
+    }
+
+    @Override
+    public void setHeight(String height) {
+        if (this.height.equals(height)) {
+            return;
+        }
+
+        this.height = height;
+        super.setHeight(height);
+        if (!rendering && client != null) {
+            iLayout();
+            client.runDescendentsLayout(this);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (this.width.equals(width)) {
+            return;
+        }
+
+        this.width = width;
+        super.setWidth(width);
+        if (!rendering && client != null) {
+            iLayout();
+            client.runDescendentsLayout(this);
+        }
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        if (child == firstChild) {
+            return firstRenderSpace;
+        } else if (child == secondChild) {
+            return secondRenderSpace;
+        }
+
+        return null;
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        return (component != null && (component == firstChild || component == secondChild));
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        if (oldComponent == firstChild) {
+            setFirstWidget(newComponent);
+        } else if (oldComponent == secondChild) {
+            setSecondWidget(newComponent);
+        }
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        if (height != null && width != null) {
+            /*
+             * If the height and width has been specified the child components
+             * cannot make the size of the layout change
+             */
+
+            return true;
+        }
+
+        if (renderInformation.updateSize(getElement())) {
+            return false;
+        } else {
+            return true;
+        }
+
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        // TODO Implement caption handling
+    }
+
+    /**
+     * Updates the new split position back to server.
+     * 
+     * @param pos
+     *            The new position of the split handle.
+     */
+    private void updateSplitPosition(int pos) {
+        // We always send pixel values to server
+        client.updateVariable(id, "position", pos, immediate);
+    }
+
+    private void setStylenames() {
+        final String splitterSuffix = (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter"
+                : "-vsplitter");
+        final String firstContainerSuffix = "-first-container";
+        final String secondContainerSuffix = "-second-container";
+        String lockedSuffix = "";
+
+        String splitterStyle = CLASSNAME + splitterSuffix;
+        String firstStyle = CLASSNAME + firstContainerSuffix;
+        String secondStyle = CLASSNAME + secondContainerSuffix;
+
+        if (locked) {
+            splitterStyle = CLASSNAME + splitterSuffix + "-locked";
+            lockedSuffix = "-locked";
+        }
+        for (int i = 0; i < componentStyleNames.length; i++) {
+            splitterStyle += " " + CLASSNAME + splitterSuffix + "-"
+                    + componentStyleNames[i] + lockedSuffix;
+            firstStyle += " " + CLASSNAME + firstContainerSuffix + "-"
+                    + componentStyleNames[i];
+            secondStyle += " " + CLASSNAME + secondContainerSuffix + "-"
+                    + componentStyleNames[i];
+        }
+        DOM.setElementProperty(splitter, "className", splitterStyle);
+        DOM.setElementProperty(firstContainer, "className", firstStyle);
+        DOM.setElementProperty(secondContainer, "className", secondStyle);
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelHorizontal.java
new file mode 100644 (file)
index 0000000..98002e9
--- /dev/null
@@ -0,0 +1,12 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+public class VSplitPanelHorizontal extends VSplitPanel {
+
+    public VSplitPanelHorizontal() {
+        super(VSplitPanel.ORIENTATION_HORIZONTAL);
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanelVertical.java
new file mode 100644 (file)
index 0000000..4bbf662
--- /dev/null
@@ -0,0 +1,12 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+public class VSplitPanelVertical extends VSplitPanel {
+
+    public VSplitPanelVertical() {
+        super(VSplitPanel.ORIENTATION_VERTICAL);
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java b/src/com/vaadin/terminal/gwt/client/ui/VTablePaging.java
new file mode 100644 (file)
index 0000000..3db1ce8
--- /dev/null
@@ -0,0 +1,439 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Grid;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+/**
+ * TODO make this work (just an early prototype). We may want to have paging
+ * style table which will be much lighter than VScrollTable is.
+ */
+public class VTablePaging extends Composite implements Table, Paintable,
+        ClickListener {
+
+    private final Grid tBody = new Grid();
+    private final Button nextPage = new Button("&gt;");
+    private final Button prevPage = new Button("&lt;");
+    private final Button firstPage = new Button("&lt;&lt;");
+    private final Button lastPage = new Button("&gt;&gt;");
+
+    private int pageLength = 15;
+
+    private boolean rowHeaders = false;
+
+    private ApplicationConnection client;
+    private String id;
+
+    private boolean immediate = false;
+
+    private int selectMode = Table.SELECT_MODE_NONE;
+
+    private final Vector selectedRowKeys = new Vector();
+
+    private int totalRows;
+
+    private final HashMap visibleColumns = new HashMap();
+
+    private int rows;
+
+    private int firstRow;
+    private boolean sortAscending = true;
+    private final HorizontalPanel pager;
+
+    public HashMap rowKeysToTableRows = new HashMap();
+
+    public VTablePaging() {
+
+        tBody.setStyleName("itable-tbody");
+
+        final VerticalPanel panel = new VerticalPanel();
+
+        pager = new HorizontalPanel();
+        pager.add(firstPage);
+        firstPage.addClickListener(this);
+        pager.add(prevPage);
+        prevPage.addClickListener(this);
+        pager.add(nextPage);
+        nextPage.addClickListener(this);
+        pager.add(lastPage);
+        lastPage.addClickListener(this);
+
+        panel.add(pager);
+        panel.add(tBody);
+
+        initWidget(panel);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        this.client = client;
+        id = uidl.getStringAttribute("id");
+        immediate = uidl.getBooleanAttribute("immediate");
+        totalRows = uidl.getIntAttribute("totalrows");
+        pageLength = uidl.getIntAttribute("pagelength");
+        firstRow = uidl.getIntAttribute("firstrow");
+        rows = uidl.getIntAttribute("rows");
+
+        if (uidl.hasAttribute("selectmode")) {
+            if (uidl.getStringAttribute("selectmode").equals("multi")) {
+                selectMode = Table.SELECT_MODE_MULTI;
+            } else {
+                selectMode = Table.SELECT_MODE_SINGLE;
+            }
+
+            if (uidl.hasAttribute("selected")) {
+                final Set selectedKeys = uidl
+                        .getStringArrayVariableAsSet("selected");
+                selectedRowKeys.clear();
+                for (final Iterator it = selectedKeys.iterator(); it.hasNext();) {
+                    selectedRowKeys.add(it.next());
+                }
+            }
+        }
+
+        if (uidl.hasVariable("sortascending")) {
+            sortAscending = uidl.getBooleanVariable("sortascending");
+        }
+
+        if (uidl.hasAttribute("rowheaders")) {
+            rowHeaders = true;
+        }
+
+        UIDL rowData = null;
+        UIDL visibleColumns = null;
+        for (final Iterator it = uidl.getChildIterator(); it.hasNext();) {
+            final UIDL c = (UIDL) it.next();
+            if (c.getTag().equals("rows")) {
+                rowData = c;
+            } else if (c.getTag().equals("actions")) {
+                updateActionMap(c);
+            } else if (c.getTag().equals("visiblecolumns")) {
+                visibleColumns = c;
+            }
+        }
+        tBody.resize(rows + 1, uidl.getIntAttribute("cols")
+                + (rowHeaders ? 1 : 0));
+        updateHeader(visibleColumns);
+        updateBody(rowData);
+
+        updatePager();
+    }
+
+    private void updateHeader(UIDL c) {
+        final Iterator it = c.getChildIterator();
+        visibleColumns.clear();
+        int colIndex = (rowHeaders ? 1 : 0);
+        while (it.hasNext()) {
+            final UIDL col = (UIDL) it.next();
+            final String cid = col.getStringAttribute("cid");
+            if (!col.hasAttribute("collapsed")) {
+                tBody.setWidget(0, colIndex, new HeaderCell(cid, col
+                        .getStringAttribute("caption")));
+
+            }
+            colIndex++;
+        }
+    }
+
+    private void updateActionMap(UIDL c) {
+        // TODO Auto-generated method stub
+
+    }
+
+    /**
+     * Updates row data from uidl. UpdateFromUIDL delegates updating tBody to
+     * this method.
+     * 
+     * Updates may be to different part of tBody, depending on update type. It
+     * can be initial row data, scroll up, scroll down...
+     * 
+     * @param uidl
+     *            which contains row data
+     */
+    private void updateBody(UIDL uidl) {
+        final Iterator it = uidl.getChildIterator();
+
+        int curRowIndex = 1;
+        while (it.hasNext()) {
+            final UIDL rowUidl = (UIDL) it.next();
+            final TableRow row = new TableRow(curRowIndex, String
+                    .valueOf(rowUidl.getIntAttribute("key")), rowUidl
+                    .hasAttribute("selected"));
+            int colIndex = 0;
+            if (rowHeaders) {
+                tBody.setWidget(curRowIndex, colIndex, new BodyCell(row,
+                        rowUidl.getStringAttribute("caption")));
+                colIndex++;
+            }
+            final Iterator cells = rowUidl.getChildIterator();
+            while (cells.hasNext()) {
+                final Object cell = cells.next();
+                if (cell instanceof String) {
+                    tBody.setWidget(curRowIndex, colIndex, new BodyCell(row,
+                            (String) cell));
+                } else {
+                    final Paintable cellContent = client
+                            .getPaintable((UIDL) cell);
+                    final BodyCell bodyCell = new BodyCell(row);
+                    bodyCell.setWidget((Widget) cellContent);
+                    tBody.setWidget(curRowIndex, colIndex, bodyCell);
+                }
+                colIndex++;
+            }
+            curRowIndex++;
+        }
+    }
+
+    private void updatePager() {
+        if (pageLength == 0) {
+            pager.setVisible(false);
+            return;
+        }
+        if (isFirstPage()) {
+            firstPage.setEnabled(false);
+            prevPage.setEnabled(false);
+        } else {
+            firstPage.setEnabled(true);
+            prevPage.setEnabled(true);
+        }
+        if (hasNextPage()) {
+            nextPage.setEnabled(true);
+            lastPage.setEnabled(true);
+        } else {
+            nextPage.setEnabled(false);
+            lastPage.setEnabled(false);
+
+        }
+    }
+
+    private boolean hasNextPage() {
+        if (firstRow + rows + 1 > totalRows) {
+            return false;
+        }
+        return true;
+    }
+
+    private boolean isFirstPage() {
+        if (firstRow == 0) {
+            return true;
+        }
+        return false;
+    }
+
+    public void onClick(Widget sender) {
+        if (sender instanceof Button) {
+            if (sender == firstPage) {
+                client.updateVariable(id, "firstvisible", 0, true);
+            } else if (sender == nextPage) {
+                client.updateVariable(id, "firstvisible",
+                        firstRow + pageLength, true);
+            } else if (sender == prevPage) {
+                int newFirst = firstRow - pageLength;
+                if (newFirst < 0) {
+                    newFirst = 0;
+                }
+                client.updateVariable(id, "firstvisible", newFirst, true);
+            } else if (sender == lastPage) {
+                client.updateVariable(id, "firstvisible", totalRows
+                        - pageLength, true);
+            }
+        }
+        if (sender instanceof HeaderCell) {
+            final HeaderCell hCell = (HeaderCell) sender;
+            client.updateVariable(id, "sortcolumn", hCell.getCid(), false);
+            client.updateVariable(id, "sortascending", (sortAscending ? false
+                    : true), true);
+        }
+    }
+
+    private class HeaderCell extends HTML {
+
+        private String cid;
+
+        public String getCid() {
+            return cid;
+        }
+
+        public void setCid(String pid) {
+            cid = pid;
+        }
+
+        HeaderCell(String pid, String caption) {
+            super();
+            cid = pid;
+            addClickListener(VTablePaging.this);
+            setText(caption);
+            // TODO remove debug color
+            DOM.setStyleAttribute(getElement(), "color", "brown");
+            DOM.setStyleAttribute(getElement(), "font-weight", "bold");
+        }
+    }
+
+    /**
+     * Abstraction of table cell content. In needs to know on which row it is in
+     * case of context click.
+     * 
+     * @author mattitahvonen
+     */
+    public class BodyCell extends SimplePanel {
+        private final TableRow row;
+
+        public BodyCell(TableRow row) {
+            super();
+            sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT);
+            this.row = row;
+        }
+
+        public BodyCell(TableRow row2, String textContent) {
+            super();
+            sinkEvents(Event.BUTTON_LEFT | Event.BUTTON_RIGHT);
+            row = row2;
+            setWidget(new Label(textContent));
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            System.out.println("CEll event: " + event.toString());
+            switch (DOM.eventGetType(event)) {
+            case Event.BUTTON_RIGHT:
+                row.showContextMenu(event);
+                Window.alert("context menu un-implemented");
+                DOM.eventCancelBubble(event, true);
+                break;
+            case Event.BUTTON_LEFT:
+                if (selectMode > Table.SELECT_MODE_NONE) {
+                    row.toggleSelected();
+                }
+                break;
+            default:
+                break;
+            }
+            super.onBrowserEvent(event);
+        }
+    }
+
+    private class TableRow {
+
+        private final String key;
+        private final int rowIndex;
+        private boolean selected = false;
+
+        public TableRow(int rowIndex, String rowKey, boolean selected) {
+            rowKeysToTableRows.put(rowKey, this);
+            this.rowIndex = rowIndex;
+            key = rowKey;
+            setSelected(selected);
+        }
+
+        /**
+         * This method is used to set row status. Does not change value on
+         * server.
+         * 
+         * @param selected
+         */
+        public void setSelected(boolean sel) {
+            selected = sel;
+            if (selected) {
+                selectedRowKeys.add(key);
+                DOM.setStyleAttribute(tBody.getRowFormatter().getElement(
+                        rowIndex), "background", "yellow");
+
+            } else {
+                selectedRowKeys.remove(key);
+                DOM.setStyleAttribute(tBody.getRowFormatter().getElement(
+                        rowIndex), "background", "transparent");
+            }
+        }
+
+        public void setContextMenuOptions(HashMap options) {
+
+        }
+
+        /**
+         * Toggles rows select state. Also updates state to server according to
+         * tables immediate flag.
+         * 
+         */
+        public void toggleSelected() {
+            if (selected) {
+                setSelected(false);
+            } else {
+                if (selectMode == Table.SELECT_MODE_SINGLE) {
+                    deselectAll();
+                }
+                setSelected(true);
+            }
+            client.updateVariable(id, "selected", selectedRowKeys.toArray(),
+                    immediate);
+        }
+
+        /**
+         * Shows context menu for this row.
+         * 
+         * @param event
+         *            Event which triggered context menu. Correct place for
+         *            context menu can be determined with it.
+         */
+        public void showContextMenu(Event event) {
+            System.out.println("TODO: Show context menu");
+        }
+    }
+
+    public void deselectAll() {
+        final Object[] keys = selectedRowKeys.toArray();
+        for (int i = 0; i < keys.length; i++) {
+            final TableRow tableRow = (TableRow) rowKeysToTableRows
+                    .get(keys[i]);
+            if (tableRow != null) {
+                tableRow.setSelected(false);
+            }
+        }
+        // still ensure all selects are removed from
+        selectedRowKeys.clear();
+    }
+
+    public void add(Widget w) {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void clear() {
+        // TODO Auto-generated method stub
+
+    }
+
+    public Iterator iterator() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public boolean remove(Widget w) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java
new file mode 100644 (file)
index 0000000..4cc2887
--- /dev/null
@@ -0,0 +1,841 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.VCaption;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderInformation;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+public class VTabsheet extends VTabsheetBase {
+
+    private class TabSheetCaption extends VCaption {
+        TabSheetCaption() {
+            super(null, client);
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (event.getTypeInt() == Event.ONLOAD) {
+                // icon onloads may change total width of tabsheet
+                if (isDynamicWidth()) {
+                    updateDynamicWidth();
+                }
+                updateTabScroller();
+            }
+        }
+
+        @Override
+        public void setWidth(String width) {
+            super.setWidth(width);
+            if (BrowserInfo.get().isIE7()) {
+                /*
+                 * IE7 apparently has problems with calculating width for
+                 * floated elements inside a DIV with padding. Set the width
+                 * explicitly for the caption.
+                 */
+                fixTextWidth();
+            }
+        }
+
+        private void fixTextWidth() {
+            Element captionText = getTextElement();
+            int captionWidth = Util.getRequiredWidth(captionText);
+            int scrollWidth = captionText.getScrollWidth();
+            if (scrollWidth > captionWidth) {
+                captionWidth = scrollWidth;
+            }
+            captionText.getStyle().setPropertyPx("width", captionWidth);
+        }
+
+    }
+
+    class TabBar extends ComplexPanel implements ClickListener {
+
+        private Element tr = DOM.createTR();
+
+        private Element spacerTd = DOM.createTD();
+
+        TabBar() {
+            Element el = DOM.createTable();
+            Element tbody = DOM.createTBody();
+            DOM.appendChild(el, tbody);
+            DOM.appendChild(tbody, tr);
+            setStyleName(spacerTd, CLASSNAME + "-spacertd");
+            DOM.appendChild(tr, spacerTd);
+            DOM.appendChild(spacerTd, DOM.createDiv());
+            setElement(el);
+        }
+
+        protected Element getContainerElement() {
+            return tr;
+        }
+
+        private Widget oldSelected;
+
+        public int getTabCount() {
+            return getWidgetCount();
+        }
+
+        public void addTab(VCaption c) {
+            Element td = DOM.createTD();
+            setStyleName(td, CLASSNAME + "-tabitemcell");
+
+            if (getWidgetCount() == 0) {
+                setStyleName(td, CLASSNAME + "-tabitemcell-first", true);
+            }
+
+            Element div = DOM.createDiv();
+            setStyleName(div, CLASSNAME + "-tabitem");
+            DOM.appendChild(td, div);
+            DOM.insertBefore(tr, td, spacerTd);
+            c.addClickListener(this);
+            add(c, div);
+        }
+
+        public void onClick(Widget sender) {
+            int index = getWidgetIndex(sender);
+            onTabSelected(index);
+        }
+
+        public void selectTab(int index) {
+            Widget newSelected = getWidget(index);
+            Widget.setStyleName(DOM.getParent(newSelected.getElement()),
+                    CLASSNAME + "-tabitem-selected", true);
+            if (oldSelected != null && oldSelected != newSelected) {
+                Widget.setStyleName(DOM.getParent(oldSelected.getElement()),
+                        CLASSNAME + "-tabitem-selected", false);
+            }
+            oldSelected = newSelected;
+        }
+
+        public void removeTab(int i) {
+            Widget w = getWidget(i);
+            if (w == null) {
+                return;
+            }
+
+            Element caption = w.getElement();
+            Element div = DOM.getParent(caption);
+            Element td = DOM.getParent(div);
+            Element tr = DOM.getParent(td);
+            remove(w);
+
+            /*
+             * Widget is the Caption but we want to remove everything up to and
+             * including the parent TD
+             */
+
+            DOM.removeChild(tr, td);
+
+            /*
+             * If this widget was selected we need to unmark it as the last
+             * selected
+             */
+            if (w == oldSelected) {
+                oldSelected = null;
+            }
+        }
+
+        @Override
+        public boolean remove(Widget w) {
+            ((VCaption) w).removeClickListener(this);
+            return super.remove(w);
+        }
+
+        public TabSheetCaption getTab(int index) {
+            if (index >= getWidgetCount()) {
+                return null;
+            }
+            return (TabSheetCaption) getWidget(index);
+        }
+
+        public void setVisible(int index, boolean visible) {
+            Element e = DOM.getParent(getTab(index).getElement());
+            if (visible) {
+                DOM.setStyleAttribute(e, "display", "");
+            } else {
+                DOM.setStyleAttribute(e, "display", "none");
+            }
+        }
+
+        public void updateCaptionSize(int index) {
+            VCaption c = getTab(index);
+            c.setWidth(c.getRequiredWidth() + "px");
+
+        }
+
+    }
+
+    public static final String CLASSNAME = "i-tabsheet";
+
+    public static final String TABS_CLASSNAME = "i-tabsheet-tabcontainer";
+    public static final String SCROLLER_CLASSNAME = "i-tabsheet-scroller";
+    private final Element tabs; // tabbar and 'scroller' container
+    private final Element scroller; // tab-scroller element
+    private final Element scrollerNext; // tab-scroller next button element
+    private final Element scrollerPrev; // tab-scroller prev button element
+    private int scrollerIndex = 0;
+
+    private final TabBar tb = new TabBar();
+    private final VTabsheetPanel tp = new VTabsheetPanel();
+    private final Element contentNode, deco;
+
+    private final HashMap<String, VCaption> captions = new HashMap<String, VCaption>();
+
+    private String height;
+    private String width;
+
+    private boolean waitingForResponse;
+
+    private RenderInformation renderInformation = new RenderInformation();
+
+    /**
+     * Previous visible widget is set invisible with CSS (not display: none, but
+     * visibility: hidden), to avoid flickering during render process. Normal
+     * visibility must be returned later when new widget is rendered.
+     */
+    private Widget previousVisibleWidget;
+
+    private boolean rendering = false;
+
+    private void onTabSelected(final int tabIndex) {
+        if (disabled || waitingForResponse) {
+            return;
+        }
+        final Object tabKey = tabKeys.get(tabIndex);
+        if (disabledTabKeys.contains(tabKey)) {
+            return;
+        }
+        if (client != null && activeTabIndex != tabIndex) {
+            tb.selectTab(tabIndex);
+            addStyleDependentName("loading");
+            // run updating variables in deferred command to bypass some FF
+            // optimization issues
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    previousVisibleWidget = tp.getWidget(tp.getVisibleWidget());
+                    DOM.setStyleAttribute(DOM.getParent(previousVisibleWidget
+                            .getElement()), "visibility", "hidden");
+                    client.updateVariable(id, "selected", tabKeys.get(tabIndex)
+                            .toString(), true);
+                }
+            });
+            waitingForResponse = true;
+        }
+    }
+
+    private boolean isDynamicWidth() {
+        return width == null || width.equals("");
+    }
+
+    private boolean isDynamicHeight() {
+        return height == null || height.equals("");
+    }
+
+    public VTabsheet() {
+        super(CLASSNAME);
+
+        // Tab scrolling
+        DOM.setStyleAttribute(getElement(), "overflow", "hidden");
+        tabs = DOM.createDiv();
+        DOM.setElementProperty(tabs, "className", TABS_CLASSNAME);
+        scroller = DOM.createDiv();
+
+        DOM.setElementProperty(scroller, "className", SCROLLER_CLASSNAME);
+        scrollerPrev = DOM.createButton();
+        DOM.setElementProperty(scrollerPrev, "className", SCROLLER_CLASSNAME
+                + "Prev");
+        DOM.sinkEvents(scrollerPrev, Event.ONCLICK);
+        scrollerNext = DOM.createButton();
+        DOM.setElementProperty(scrollerNext, "className", SCROLLER_CLASSNAME
+                + "Next");
+        DOM.sinkEvents(scrollerNext, Event.ONCLICK);
+        DOM.appendChild(getElement(), tabs);
+
+        // Tabs
+        tp.setStyleName(CLASSNAME + "-tabsheetpanel");
+        contentNode = DOM.createDiv();
+
+        deco = DOM.createDiv();
+
+        addStyleDependentName("loading"); // Indicate initial progress
+        tb.setStyleName(CLASSNAME + "-tabs");
+        DOM
+                .setElementProperty(contentNode, "className", CLASSNAME
+                        + "-content");
+        DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
+
+        add(tb, tabs);
+        DOM.appendChild(scroller, scrollerPrev);
+        DOM.appendChild(scroller, scrollerNext);
+
+        DOM.appendChild(getElement(), contentNode);
+        add(tp, contentNode);
+        DOM.appendChild(getElement(), deco);
+
+        DOM.appendChild(tabs, scroller);
+
+        // TODO Use for Safari only. Fix annoying 1px first cell in TabBar.
+        // DOM.setStyleAttribute(DOM.getFirstChild(DOM.getFirstChild(DOM
+        // .getFirstChild(tb.getElement()))), "display", "none");
+
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+
+        // Tab scrolling
+        if (isScrolledTabs() && DOM.eventGetTarget(event) == scrollerPrev) {
+            if (scrollerIndex > 0) {
+                scrollerIndex--;
+                DOM.setStyleAttribute(DOM.getChild(DOM.getFirstChild(DOM
+                        .getFirstChild(tb.getElement())), scrollerIndex),
+                        "display", "");
+                tb.updateCaptionSize(scrollerIndex);
+                updateTabScroller();
+            }
+        } else if (isClippedTabs() && DOM.eventGetTarget(event) == scrollerNext) {
+            int tabs = tb.getTabCount();
+            if (scrollerIndex + 1 <= tabs) {
+                DOM.setStyleAttribute(DOM.getChild(DOM.getFirstChild(DOM
+                        .getFirstChild(tb.getElement())), scrollerIndex),
+                        "display", "none");
+                tb.updateCaptionSize(scrollerIndex);
+                scrollerIndex++;
+                updateTabScroller();
+            }
+        } else {
+            super.onBrowserEvent(event);
+        }
+    }
+
+    @Override
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+
+        super.updateFromUIDL(uidl, client);
+        if (cachedUpdate) {
+            return;
+        }
+
+        // Add proper stylenames for all elements (easier to prevent unwanted
+        // style inheritance)
+        if (uidl.hasAttribute("style")) {
+            final String[] styles = uidl.getStringAttribute("style").split(" ");
+            final String contentBaseClass = CLASSNAME + "-content";
+            String contentClass = contentBaseClass;
+            final String decoBaseClass = CLASSNAME + "-deco";
+            String decoClass = decoBaseClass;
+            for (int i = 0; i < styles.length; i++) {
+                tb.addStyleDependentName(styles[i]);
+                contentClass += " " + contentBaseClass + "-" + styles[i];
+                decoClass += " " + decoBaseClass + "-" + styles[i];
+            }
+            DOM.setElementProperty(contentNode, "className", contentClass);
+            DOM.setElementProperty(deco, "className", decoClass);
+        } else {
+            tb.setStyleName(CLASSNAME + "-tabs");
+            DOM.setElementProperty(contentNode, "className", CLASSNAME
+                    + "-content");
+            DOM.setElementProperty(deco, "className", CLASSNAME + "-deco");
+        }
+
+        if (uidl.hasAttribute("hidetabs")) {
+            tb.setVisible(false);
+            addStyleName(CLASSNAME + "-hidetabs");
+        } else {
+            tb.setVisible(true);
+            removeStyleName(CLASSNAME + "-hidetabs");
+        }
+
+        // tabs; push or not
+        if (!isDynamicWidth()) {
+            // FIXME: This makes tab sheet tabs go to 1px width on every update
+            // and then back to original width
+            // update width later, in updateTabScroller();
+            DOM.setStyleAttribute(tabs, "width", "1px");
+            DOM.setStyleAttribute(tabs, "overflow", "hidden");
+        } else {
+            showAllTabs();
+            DOM.setStyleAttribute(tabs, "width", "");
+            DOM.setStyleAttribute(tabs, "overflow", "visible");
+            updateDynamicWidth();
+        }
+
+        if (!isDynamicHeight()) {
+            // Must update height after the styles have been set
+            updateContentNodeHeight();
+            updateOpenTabSize();
+        }
+
+        iLayout();
+
+        // Re run relative size update to ensure optimal scrollbars
+        // TODO isolate to situation that visible tab has undefined height
+        try {
+            client.handleComponentRelativeSize(tp.getWidget(tp
+                    .getVisibleWidget()));
+        } catch (Exception e) {
+            // Ignore, most likely empty tabsheet
+        }
+
+        renderInformation.updateSize(getElement());
+
+        waitingForResponse = false;
+        rendering = false;
+    }
+
+    private void updateDynamicWidth() {
+        // Find tab width
+        int tabsWidth = 0;
+
+        int count = tb.getTabCount();
+        for (int i = 0; i < count; i++) {
+            Element tabTd = tb.getTab(i).getElement().getParentElement().cast();
+            tabsWidth += tabTd.getOffsetWidth();
+        }
+
+        // Find content width
+        Style style = tp.getElement().getStyle();
+        String overflow = style.getProperty("overflow");
+        style.setProperty("overflow", "hidden");
+        style.setPropertyPx("width", tabsWidth);
+        Style wrapperstyle = tp.getWidget(tp.getVisibleWidget()).getElement()
+                .getParentElement().getStyle();
+        wrapperstyle.setPropertyPx("width", tabsWidth);
+        // Get content width from actual widget
+
+        int contentWidth = 0;
+        if (tp.getWidgetCount() > 0) {
+            contentWidth = tp.getWidget(tp.getVisibleWidget()).getOffsetWidth();
+        }
+        style.setProperty("overflow", overflow);
+
+        // Set widths to max(tabs,content)
+        if (tabsWidth < contentWidth) {
+            tabsWidth = contentWidth;
+        }
+
+        int outerWidth = tabsWidth + getContentAreaBorderWidth();
+
+        tabs.getStyle().setPropertyPx("width", outerWidth);
+        style.setPropertyPx("width", tabsWidth);
+        wrapperstyle.setPropertyPx("width", tabsWidth);
+
+        contentNode.getStyle().setPropertyPx("width", tabsWidth);
+        super.setWidth(outerWidth + "px");
+        updateOpenTabSize();
+    }
+
+    @Override
+    protected void renderTab(final UIDL tabUidl, int index, boolean selected,
+            boolean hidden) {
+        TabSheetCaption c = tb.getTab(index);
+        if (c == null) {
+            c = new TabSheetCaption();
+            tb.addTab(c);
+        }
+        c.updateCaption(tabUidl);
+
+        tb.setVisible(index, !hidden);
+
+        /*
+         * Force the width of the caption container so the content will not wrap
+         * and tabs won't be too narrow in certain browsers
+         */
+        c.setWidth(c.getRequiredWidth() + "px");
+        captions.put("" + index, c);
+
+        UIDL tabContentUIDL = null;
+        Paintable tabContent = null;
+        if (tabUidl.getChildCount() > 0) {
+            tabContentUIDL = tabUidl.getChildUIDL(0);
+            tabContent = client.getPaintable(tabContentUIDL);
+        }
+
+        if (tabContent != null) {
+            /* This is a tab with content information */
+
+            int oldIndex = tp.getWidgetIndex((Widget) tabContent);
+            if (oldIndex != -1 && oldIndex != index) {
+                /*
+                 * The tab has previously been rendered in another position so
+                 * we must move the cached content to correct position
+                 */
+                tp.insert((Widget) tabContent, index);
+            }
+        } else {
+            /* A tab whose content has not yet been loaded */
+
+            /*
+             * Make sure there is a corresponding empty tab in tp. The same
+             * operation as the moving above but for not-loaded tabs.
+             */
+            if (index < tp.getWidgetCount()) {
+                Widget oldWidget = tp.getWidget(index);
+                if (!(oldWidget instanceof PlaceHolder)) {
+                    tp.insert(new PlaceHolder(), index);
+                }
+            }
+
+        }
+
+        if (selected) {
+            renderContent(tabContentUIDL);
+            tb.selectTab(index);
+        } else {
+            if (tabContentUIDL != null) {
+                // updating a drawn child on hidden tab
+                if (tp.getWidgetIndex((Widget) tabContent) < 0) {
+                    tp.insert((Widget) tabContent, index);
+                }
+                tabContent.updateFromUIDL(tabContentUIDL, client);
+            } else if (tp.getWidgetCount() <= index) {
+                tp.add(new PlaceHolder());
+            }
+        }
+    }
+
+    public class PlaceHolder extends VLabel {
+        public PlaceHolder() {
+            super("");
+        }
+    }
+
+    @Override
+    protected void selectTab(int index, final UIDL contentUidl) {
+        if (index != activeTabIndex) {
+            activeTabIndex = index;
+            tb.selectTab(activeTabIndex);
+        }
+        renderContent(contentUidl);
+    }
+
+    private void renderContent(final UIDL contentUIDL) {
+        final Paintable content = client.getPaintable(contentUIDL);
+        if (tp.getWidgetCount() > activeTabIndex) {
+            Widget old = tp.getWidget(activeTabIndex);
+            if (old != content) {
+                tp.remove(activeTabIndex);
+                if (old instanceof Paintable) {
+                    client.unregisterPaintable((Paintable) old);
+                }
+                tp.insert((Widget) content, activeTabIndex);
+            }
+        } else {
+            tp.add((Widget) content);
+        }
+
+        tp.showWidget(activeTabIndex);
+
+        VTabsheet.this.iLayout();
+        (content).updateFromUIDL(contentUIDL, client);
+        /*
+         * The size of a cached, relative sized component must be updated to
+         * report correct size to updateOpenTabSize().
+         */
+        if (contentUIDL.getBooleanAttribute("cached")) {
+            client.handleComponentRelativeSize((Widget) content);
+        }
+        updateOpenTabSize();
+        VTabsheet.this.removeStyleDependentName("loading");
+        if (previousVisibleWidget != null) {
+            DOM.setStyleAttribute(previousVisibleWidget.getElement(),
+                    "visibility", "");
+            previousVisibleWidget = null;
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        this.height = height;
+        updateContentNodeHeight();
+
+        if (!rendering) {
+            updateOpenTabSize();
+            iLayout();
+            // TODO Check if this is needed
+            client.runDescendentsLayout(this);
+        }
+    }
+
+    private void updateContentNodeHeight() {
+        if (height != null && !"".equals(height)) {
+            int contentHeight = getOffsetHeight();
+            contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight");
+            contentHeight -= tb.getOffsetHeight();
+            if (contentHeight < 0) {
+                contentHeight = 0;
+            }
+
+            // Set proper values for content element
+            DOM.setStyleAttribute(contentNode, "height", contentHeight + "px");
+            renderSpace.setHeight(contentHeight);
+        } else {
+            DOM.setStyleAttribute(contentNode, "height", "");
+            renderSpace.setHeight(0);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if ((this.width == null && width.equals(""))
+                || (this.width != null && this.width.equals(width))) {
+            return;
+        }
+
+        super.setWidth(width);
+        if (width.equals("")) {
+            width = null;
+        }
+        this.width = width;
+        if (width == null) {
+            renderSpace.setWidth(0);
+            contentNode.getStyle().setProperty("width", "");
+        } else {
+            int contentWidth = getOffsetWidth() - getContentAreaBorderWidth();
+            if (contentWidth < 0) {
+                contentWidth = 0;
+            }
+            contentNode.getStyle().setProperty("width", contentWidth + "px");
+            renderSpace.setWidth(contentWidth);
+        }
+
+        if (!rendering) {
+            if (isDynamicHeight()) {
+                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, tp,
+                        this);
+            }
+
+            updateOpenTabSize();
+            iLayout();
+            // TODO Check if this is needed
+            client.runDescendentsLayout(this);
+
+        }
+
+    }
+
+    public void iLayout() {
+        updateTabScroller();
+        tp.runWebkitOverflowAutoFix();
+    }
+
+    /**
+     * Sets the size of the visible tab (component). As the tab is set to
+     * position: absolute (to work around a firefox flickering bug) we must keep
+     * this up-to-date by hand.
+     */
+    private void updateOpenTabSize() {
+        /*
+         * The overflow=auto element must have a height specified, otherwise it
+         * will be just as high as the contents and no scrollbars will appear
+         */
+        int height = -1;
+        int width = -1;
+        int minWidth = 0;
+
+        if (!isDynamicHeight()) {
+            height = renderSpace.getHeight();
+        }
+        if (!isDynamicWidth()) {
+            width = renderSpace.getWidth();
+        } else {
+            /*
+             * If the tabbar is wider than the content we need to use the tabbar
+             * width as minimum width so scrollbars get placed correctly (at the
+             * right edge).
+             */
+            minWidth = tb.getOffsetWidth() - getContentAreaBorderWidth();
+        }
+        tp.fixVisibleTabSize(width, height, minWidth);
+
+    }
+
+    /**
+     * Layouts the tab-scroller elements, and applies styles.
+     */
+    private void updateTabScroller() {
+        if (width != null) {
+            DOM.setStyleAttribute(tabs, "width", width);
+        }
+        if (scrollerIndex > tb.getTabCount()) {
+            scrollerIndex = 0;
+        }
+        boolean scrolled = isScrolledTabs();
+        boolean clipped = isClippedTabs();
+        if (tb.isVisible() && (scrolled || clipped)) {
+            DOM.setStyleAttribute(scroller, "display", "");
+            DOM.setElementProperty(scrollerPrev, "className",
+                    SCROLLER_CLASSNAME + (scrolled ? "Prev" : "Prev-disabled"));
+            DOM.setElementProperty(scrollerNext, "className",
+                    SCROLLER_CLASSNAME + (clipped ? "Next" : "Next-disabled"));
+        } else {
+            DOM.setStyleAttribute(scroller, "display", "none");
+        }
+
+        if (BrowserInfo.get().isSafari()) {
+            // fix tab height for safari, bugs sometimes if tabs contain icons
+            String property = tabs.getStyle().getProperty("height");
+            if (property == null || property.equals("")) {
+                tabs.getStyle().setPropertyPx("height", tb.getOffsetHeight());
+            }
+            /*
+             * another hack for webkits. tabscroller sometimes drops without
+             * "shaking it" reproducable in
+             * com.vaadin.tests.components.tabsheet.TabSheetIcons
+             */
+            final Style style = scroller.getStyle();
+            style.setProperty("whiteSpace", "normal");
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    style.setProperty("whiteSpace", "");
+                }
+            });
+        }
+
+    }
+
+    private void showAllTabs() {
+        scrollerIndex = 0;
+        Element tr = DOM.getFirstChild(DOM.getFirstChild(tb.getElement()));
+        for (int i = 0; i < tb.getTabCount(); i++) {
+            DOM.setStyleAttribute(DOM.getChild(tr, i), "display", "");
+        }
+    }
+
+    private boolean isScrolledTabs() {
+        return scrollerIndex > 0;
+    }
+
+    private boolean isClippedTabs() {
+        return tb.getOffsetWidth() > getOffsetWidth();
+    }
+
+    @Override
+    protected void clearPaintables() {
+
+        int i = tb.getTabCount();
+        while (i > 0) {
+            tb.removeTab(--i);
+        }
+        tp.clear();
+
+    }
+
+    @Override
+    protected Iterator getPaintableIterator() {
+        return tp.iterator();
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (tp.getWidgetIndex(component) < 0) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        tp.replaceComponent(oldComponent, newComponent);
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        /* Tabsheet does not render its children's captions */
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        if (!isDynamicHeight() && !isDynamicWidth()) {
+            /*
+             * If the height and width has been specified for this container the
+             * child components cannot make the size of the layout change
+             */
+
+            return true;
+        }
+
+        updateOpenTabSize();
+
+        if (renderInformation.updateSize(getElement())) {
+            /*
+             * Size has changed so we let the child components know about the
+             * new size.
+             */
+            iLayout();
+            client.runDescendentsLayout(this);
+
+            return false;
+        } else {
+            /*
+             * Size has not changed so we do not need to propagate the event
+             * further
+             */
+            return true;
+        }
+
+    }
+
+    private int borderW = -1;
+
+    private int getContentAreaBorderWidth() {
+        if (borderW < 0) {
+            borderW = Util.measureHorizontalBorder(contentNode);
+        }
+        return borderW;
+    }
+
+    private RenderSpace renderSpace = new RenderSpace(0, 0, true);
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        // All tabs have equal amount of space allocated
+        return renderSpace;
+    }
+
+    @Override
+    protected int getTabCount() {
+        return tb.getWidgetCount();
+    }
+
+    @Override
+    protected Paintable getTab(int index) {
+        if (tp.getWidgetCount() > index) {
+            return (Paintable) tp.getWidget(index);
+        }
+        return null;
+    }
+
+    @Override
+    protected void removeTab(int index) {
+        tb.removeTab(index);
+        /*
+         * This must be checked because renderTab automatically removes the
+         * active tab content when it changes
+         */
+        if (tp.getWidgetCount() > index) {
+            tp.remove(index);
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetBase.java
new file mode 100644 (file)
index 0000000..6bf77bd
--- /dev/null
@@ -0,0 +1,144 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.ui.ComplexPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+abstract class VTabsheetBase extends ComplexPanel implements Container {
+
+    String id;
+    ApplicationConnection client;
+
+    protected final ArrayList tabKeys = new ArrayList();
+    protected int activeTabIndex = 0;
+    protected boolean disabled;
+    protected boolean readonly;
+    protected Set disabledTabKeys = new HashSet();
+    protected boolean cachedUpdate = false;
+
+    public VTabsheetBase(String classname) {
+        setElement(DOM.createDiv());
+        setStylePrimaryName(classname);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        this.client = client;
+
+        // Ensure correct implementation
+        cachedUpdate = client.updateComponent(this, uidl, true);
+        if (cachedUpdate) {
+            return;
+        }
+
+        // Update member references
+        id = uidl.getId();
+        disabled = uidl.hasAttribute("disabled");
+
+        // Render content
+        final UIDL tabs = uidl.getChildUIDL(0);
+
+        // Paintables in the TabSheet before update
+        ArrayList oldPaintables = new ArrayList();
+        for (Iterator iterator = getPaintableIterator(); iterator.hasNext();) {
+            oldPaintables.add(iterator.next());
+        }
+
+        // Clear previous values
+        tabKeys.clear();
+        disabledTabKeys.clear();
+
+        int index = 0;
+        for (final Iterator it = tabs.getChildIterator(); it.hasNext();) {
+            final UIDL tab = (UIDL) it.next();
+            final String key = tab.getStringAttribute("key");
+            final boolean selected = tab.getBooleanAttribute("selected");
+            final boolean hidden = tab.getBooleanAttribute("hidden");
+
+            if (tab.getBooleanAttribute("disabled")) {
+                disabledTabKeys.add(key);
+            }
+
+            tabKeys.add(key);
+
+            if (selected) {
+                activeTabIndex = index;
+            }
+            renderTab(tab, index, selected, hidden);
+            index++;
+        }
+
+        int tabCount = getTabCount();
+        while (tabCount-- > index) {
+            removeTab(index);
+        }
+
+        for (int i = 0; i < getTabCount(); i++) {
+            Paintable p = getTab(i);
+            oldPaintables.remove(p);
+        }
+
+        // Perform unregister for any paintables removed during update
+        for (Iterator iterator = oldPaintables.iterator(); iterator.hasNext();) {
+            Object oldPaintable = iterator.next();
+            if (oldPaintable instanceof Paintable) {
+                Widget w = (Widget) oldPaintable;
+                if (w.isAttached()) {
+                    w.removeFromParent();
+                }
+                client.unregisterPaintable((Paintable) oldPaintable);
+            }
+        }
+
+    }
+
+    /**
+     * @return a list of currently shown Paintables
+     */
+    abstract protected Iterator getPaintableIterator();
+
+    /**
+     * Clears current tabs and contents
+     */
+    abstract protected void clearPaintables();
+
+    /**
+     * Implement in extending classes. This method should render needed elements
+     * and set the visibility of the tab according to the 'selected' parameter.
+     */
+    protected abstract void renderTab(final UIDL tabUidl, int index,
+            boolean selected, boolean hidden);
+
+    /**
+     * Implement in extending classes. This method should render any previously
+     * non-cached content and set the activeTabIndex property to the specified
+     * index.
+     */
+    protected abstract void selectTab(int index, final UIDL contentUidl);
+
+    /**
+     * Implement in extending classes. This method should return the number of
+     * tabs currently rendered.
+     */
+    protected abstract int getTabCount();
+
+    /**
+     * Implement in extending classes. This method should return the Paintable
+     * corresponding to the given index.
+     */
+    protected abstract Paintable getTab(int index);
+
+    /**
+     * Implement in extending classes. This method should remove the rendered
+     * tab with the specified index.
+     */
+    protected abstract void removeTab(int index);
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheetPanel.java
new file mode 100644 (file)
index 0000000..cc81683
--- /dev/null
@@ -0,0 +1,183 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.Element;\r
+import com.google.gwt.user.client.ui.ComplexPanel;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.Util;\r
+\r
+/**\r
+ * A panel that displays all of its child widgets in a 'deck', where only one\r
+ * can be visible at a time. It is used by\r
+ * {@link com.vaadin.terminal.gwt.client.ui.VTabsheet}.\r
+ * \r
+ * This class has the same basic functionality as the GWT DeckPanel\r
+ * {@link com.google.gwt.user.client.ui.DeckPanel}, with the exception that it\r
+ * doesn't manipulate the child widgets' width and height attributes.\r
+ */\r
+public class VTabsheetPanel extends ComplexPanel {\r
+\r
+    private Widget visibleWidget;\r
+\r
+    /**\r
+     * Creates an empty tabsheet panel.\r
+     */\r
+    public VTabsheetPanel() {\r
+        setElement(DOM.createDiv());\r
+    }\r
+\r
+    /**\r
+     * Adds the specified widget to the deck.\r
+     * \r
+     * @param w\r
+     *            the widget to be added\r
+     */\r
+    @Override\r
+    public void add(Widget w) {\r
+        Element el = createContainerElement();\r
+        DOM.appendChild(getElement(), el);\r
+        super.add(w, el);\r
+    }\r
+\r
+    private Element createContainerElement() {\r
+        Element el = DOM.createDiv();\r
+        DOM.setStyleAttribute(el, "position", "absolute");\r
+        DOM.setStyleAttribute(el, "overflow", "auto");\r
+        hide(el);\r
+        return el;\r
+    }\r
+\r
+    /**\r
+     * Gets the index of the currently-visible widget.\r
+     * \r
+     * @return the visible widget's index\r
+     */\r
+    public int getVisibleWidget() {\r
+        return getWidgetIndex(visibleWidget);\r
+    }\r
+\r
+    /**\r
+     * Inserts a widget before the specified index.\r
+     * \r
+     * @param w\r
+     *            the widget to be inserted\r
+     * @param beforeIndex\r
+     *            the index before which it will be inserted\r
+     * @throws IndexOutOfBoundsException\r
+     *             if <code>beforeIndex</code> is out of range\r
+     */\r
+    public void insert(Widget w, int beforeIndex) {\r
+        Element el = createContainerElement();\r
+        DOM.insertChild(getElement(), el, beforeIndex);\r
+        super.insert(w, el, beforeIndex, false);\r
+    }\r
+\r
+    @Override\r
+    public boolean remove(Widget w) {\r
+        Element child = w.getElement();\r
+        Element parent = null;\r
+        if (child != null) {\r
+            parent = DOM.getParent(child);\r
+        }\r
+        final boolean removed = super.remove(w);\r
+        if (removed) {\r
+            if (visibleWidget == w) {\r
+                visibleWidget = null;\r
+            }\r
+            if (parent != null) {\r
+                DOM.removeChild(getElement(), parent);\r
+            }\r
+        }\r
+        return removed;\r
+    }\r
+\r
+    /**\r
+     * Shows the widget at the specified index. This causes the currently-\r
+     * visible widget to be hidden.\r
+     * \r
+     * @param index\r
+     *            the index of the widget to be shown\r
+     */\r
+    public void showWidget(int index) {\r
+        checkIndexBoundsForAccess(index);\r
+        Widget newVisible = getWidget(index);\r
+        if (visibleWidget != newVisible) {\r
+            if (visibleWidget != null) {\r
+                hide(DOM.getParent(visibleWidget.getElement()));\r
+            }\r
+            visibleWidget = newVisible;\r
+            unHide(DOM.getParent(visibleWidget.getElement()));\r
+        }\r
+    }\r
+\r
+    private void hide(Element e) {\r
+        DOM.setStyleAttribute(e, "visibility", "hidden");\r
+        DOM.setStyleAttribute(e, "top", "-100000px");\r
+        DOM.setStyleAttribute(e, "left", "-100000px");\r
+    }\r
+\r
+    private void unHide(Element e) {\r
+        DOM.setStyleAttribute(e, "top", "0px");\r
+        DOM.setStyleAttribute(e, "left", "0px");\r
+        DOM.setStyleAttribute(e, "visibility", "");\r
+    }\r
+\r
+    public void fixVisibleTabSize(int width, int height, int minWidth) {\r
+        if (visibleWidget == null) {\r
+            return;\r
+        }\r
+\r
+        boolean dynamicHeight = false;\r
+\r
+        if (height < 0) {\r
+            height = visibleWidget.getOffsetHeight();\r
+            dynamicHeight = true;\r
+        }\r
+        if (width < 0) {\r
+            width = visibleWidget.getOffsetWidth();\r
+        }\r
+        if (width < minWidth) {\r
+            width = minWidth;\r
+        }\r
+\r
+        Element wrapperDiv = (Element) visibleWidget.getElement()\r
+                .getParentElement();\r
+\r
+        // width first\r
+        getElement().getStyle().setPropertyPx("width", width);\r
+        wrapperDiv.getStyle().setPropertyPx("width", width);\r
+\r
+        if (dynamicHeight) {\r
+            // height of widget might have changed due wrapping\r
+            height = visibleWidget.getOffsetHeight();\r
+        }\r
+        // i-tabsheet-tabsheetpanel height\r
+        getElement().getStyle().setPropertyPx("height", height);\r
+\r
+        // widget wrapper height\r
+        wrapperDiv.getStyle().setPropertyPx("height", height);\r
+        runWebkitOverflowAutoFix();\r
+    }\r
+\r
+    public void runWebkitOverflowAutoFix() {\r
+        if (visibleWidget != null) {\r
+            Util.runWebkitOverflowAutoFix(DOM.getParent(visibleWidget\r
+                    .getElement()));\r
+        }\r
+\r
+    }\r
+\r
+    public void replaceComponent(Widget oldComponent, Widget newComponent) {\r
+        boolean isVisible = (visibleWidget == oldComponent);\r
+        int widgetIndex = getWidgetIndex(oldComponent);\r
+        remove(oldComponent);\r
+        insert(newComponent, widgetIndex);\r
+        if (isVisible) {\r
+            showWidget(widgetIndex);\r
+        }\r
+    }\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/VTextArea.java
new file mode 100644 (file)
index 0000000..29741af
--- /dev/null
@@ -0,0 +1,72 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.user.client.Command;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.DeferredCommand;\r
+import com.google.gwt.user.client.Element;\r
+import com.google.gwt.user.client.Event;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+/**\r
+ * This class represents a multiline textfield (textarea).\r
+ * \r
+ * TODO consider replacing this with a RichTextArea based implementation. IE\r
+ * does not support CSS height for textareas in Strict mode :-(\r
+ * \r
+ * @author IT Mill Ltd.\r
+ * \r
+ */\r
+public class VTextArea extends VTextField {\r
+    public static final String CLASSNAME = "i-textarea";\r
+\r
+    public VTextArea() {\r
+        super(DOM.createTextArea());\r
+        setStyleName(CLASSNAME);\r
+    }\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        // Call parent renderer explicitly\r
+        super.updateFromUIDL(uidl, client);\r
+\r
+        if (uidl.hasAttribute("rows")) {\r
+            setRows(new Integer(uidl.getStringAttribute("rows")).intValue());\r
+        }\r
+\r
+        if (getMaxLength() >= 0) {\r
+            sinkEvents(Event.ONKEYPRESS);\r
+        }\r
+    }\r
+\r
+    public void setRows(int rows) {\r
+        setRows(getElement(), rows);\r
+    }\r
+\r
+    private native void setRows(Element e, int r)\r
+    /*-{\r
+    try {\r
+        if(e.tagName.toLowerCase() == "textarea")\r
+                e.rows = r;\r
+    } catch (e) {}\r
+    }-*/;\r
+\r
+    @Override\r
+    public void onBrowserEvent(Event event) {\r
+        if (getMaxLength() >= 0 && event.getTypeInt() == Event.ONKEYPRESS) {\r
+            DeferredCommand.addCommand(new Command() {\r
+                public void execute() {\r
+                    if (getText().length() > getMaxLength()) {\r
+                        setText(getText().substring(0, getMaxLength()));\r
+                    }\r
+                }\r
+            });\r
+        }\r
+        super.onBrowserEvent(event);\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextField.java b/src/com/vaadin/terminal/gwt/client/ui/VTextField.java
new file mode 100644 (file)
index 0000000..7c14a4d
--- /dev/null
@@ -0,0 +1,270 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.ChangeListener;
+import com.google.gwt.user.client.ui.FocusListener;
+import com.google.gwt.user.client.ui.TextBoxBase;
+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.VTooltip;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+/**
+ * This class represents a basic text input field with one row.
+ * 
+ * @author IT Mill Ltd.
+ * 
+ */
+public class VTextField extends TextBoxBase implements Paintable, Field,
+        ChangeListener, FocusListener {
+
+    /**
+     * The input node CSS classname.
+     */
+    public static final String CLASSNAME = "i-textfield";
+    /**
+     * This CSS classname is added to the input node on hover.
+     */
+    public static final String CLASSNAME_FOCUS = "focus";
+
+    protected String id;
+
+    protected ApplicationConnection client;
+
+    private String valueBeforeEdit = null;
+
+    private boolean immediate = false;
+    private int extraHorizontalPixels = -1;
+    private int extraVerticalPixels = -1;
+    private int maxLength = -1;
+
+    private static final String CLASSNAME_PROMPT = "prompt";
+    private static final String ATTR_INPUTPROMPT = "prompt";
+    private String inputPrompt = null;
+    private boolean prompting = false;
+
+    public VTextField() {
+        this(DOM.createInputText());
+    }
+
+    protected VTextField(Element node) {
+        super(node);
+        if (BrowserInfo.get().isIE()) {
+            // Fixes IE margin problem (#2058)
+            DOM.setStyleAttribute(node, "marginTop", "-1px");
+            DOM.setStyleAttribute(node, "marginBottom", "-1px");
+        }
+        setStyleName(CLASSNAME);
+        addChangeListener(this);
+        addFocusListener(this);
+        sinkEvents(VTooltip.TOOLTIP_EVENTS);
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        if (client != null) {
+            client.handleTooltipEvent(event, this);
+        }
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        this.client = client;
+        id = uidl.getId();
+
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        if (uidl.getBooleanAttribute("readonly")) {
+            setReadOnly(true);
+        } else {
+            setReadOnly(false);
+        }
+
+        inputPrompt = uidl.getStringAttribute(ATTR_INPUTPROMPT);
+
+        setMaxLength(uidl.hasAttribute("maxLength") ? uidl
+                .getIntAttribute("maxLength") : -1);
+
+        immediate = uidl.getBooleanAttribute("immediate");
+
+        if (uidl.hasAttribute("cols")) {
+            setColumns(new Integer(uidl.getStringAttribute("cols")).intValue());
+        }
+
+        String text = uidl.getStringVariable("text");
+        prompting = inputPrompt != null && (text == null || text.equals(""));
+        if (prompting) {
+            setText(inputPrompt);
+            addStyleDependentName(CLASSNAME_PROMPT);
+        } else {
+            setText(text);
+            removeStyleDependentName(CLASSNAME_PROMPT);
+        }
+        valueBeforeEdit = uidl.getStringVariable("text");
+    }
+
+    private void setMaxLength(int newMaxLength) {
+        if (newMaxLength > 0) {
+            maxLength = newMaxLength;
+            if (getElement().getTagName().toLowerCase().equals("textarea")) {
+                // NOP no maxlength property for textarea
+            } else {
+                getElement().setPropertyInt("maxLength", maxLength);
+            }
+        } else if (maxLength != -1) {
+            if (getElement().getTagName().toLowerCase().equals("textarea")) {
+                // NOP no maxlength property for textarea
+            } else {
+                getElement().setAttribute("maxlength", "");
+            }
+            maxLength = -1;
+        }
+
+    }
+
+    protected int getMaxLength() {
+        return maxLength;
+    }
+
+    public void onChange(Widget sender) {
+        if (client != null && id != null) {
+            String newText = getText();
+            if (!prompting && newText != null
+                    && !newText.equals(valueBeforeEdit)) {
+                client.updateVariable(id, "text", getText(), immediate);
+                valueBeforeEdit = newText;
+            }
+        }
+    }
+
+    private static VTextField focusedTextField;
+
+    public static void flushChangesFromFocusedTextField() {
+        if (focusedTextField != null) {
+            focusedTextField.onChange(null);
+        }
+    }
+
+    public void onFocus(Widget sender) {
+        addStyleDependentName(CLASSNAME_FOCUS);
+        if (prompting) {
+            setText("");
+            removeStyleDependentName(CLASSNAME_PROMPT);
+        }
+        focusedTextField = this;
+    }
+
+    public void onLostFocus(Widget sender) {
+        removeStyleDependentName(CLASSNAME_FOCUS);
+        focusedTextField = null;
+        String text = getText();
+        prompting = inputPrompt != null && (text == null || "".equals(text));
+        if (prompting) {
+            setText(inputPrompt);
+            addStyleDependentName(CLASSNAME_PROMPT);
+        }
+        onChange(sender);
+    }
+
+    public void setColumns(int columns) {
+        setColumns(getElement(), columns);
+    }
+
+    private native void setColumns(Element e, int c)
+    /*-{
+    try {
+       switch(e.tagName.toLowerCase()) {
+               case "input":
+                       //e.size = c;
+                       e.style.width = c+"em";
+                       break;
+               case "textarea":
+                       //e.cols = c;
+                       e.style.width = c+"em";
+                       break;
+               default:;
+       }
+    } catch (e) {}
+    }-*/;
+
+    /**
+     * @return space used by components paddings and borders
+     */
+    private int getExtraHorizontalPixels() {
+        if (extraHorizontalPixels < 0) {
+            detectExtraSizes();
+        }
+        return extraHorizontalPixels;
+    }
+
+    /**
+     * @return space used by components paddings and borders
+     */
+    private int getExtraVerticalPixels() {
+        if (extraVerticalPixels < 0) {
+            detectExtraSizes();
+        }
+        return extraVerticalPixels;
+    }
+
+    /**
+     * Detects space used by components paddings and borders. Used when
+     * relational size are used.
+     */
+    private void detectExtraSizes() {
+        Element clone = Util.cloneNode(getElement(), false);
+        DOM.setElementAttribute(clone, "id", "");
+        DOM.setStyleAttribute(clone, "visibility", "hidden");
+        DOM.setStyleAttribute(clone, "position", "absolute");
+        // due FF3 bug set size to 10px and later subtract it from extra pixels
+        DOM.setStyleAttribute(clone, "width", "10px");
+        DOM.setStyleAttribute(clone, "height", "10px");
+        DOM.appendChild(DOM.getParent(getElement()), clone);
+        extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10;
+        extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10;
+
+        DOM.removeChild(DOM.getParent(getElement()), clone);
+    }
+
+    @Override
+    public void setHeight(String height) {
+        if (height.endsWith("px")) {
+            int h = Integer.parseInt(height.substring(0, height.length() - 2));
+            h -= getExtraVerticalPixels();
+            if (h < 0) {
+                h = 0;
+            }
+
+            super.setHeight(h + "px");
+        } else {
+            super.setHeight(height);
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (width.endsWith("px")) {
+            int w = Integer.parseInt(width.substring(0, width.length() - 2));
+            w -= getExtraHorizontalPixels();
+            if (w < 0) {
+                w = 0;
+            }
+
+            super.setWidth(w + "px");
+        } else {
+            super.setWidth(width);
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java b/src/com/vaadin/terminal/gwt/client/ui/VTextualDate.java
new file mode 100644 (file)
index 0000000..37a70ed
--- /dev/null
@@ -0,0 +1,301 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Date;\r
+\r
+import com.google.gwt.i18n.client.DateTimeFormat;\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.ui.ChangeListener;\r
+import com.google.gwt.user.client.ui.TextBox;\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.ClientExceptionHandler;\r
+import com.vaadin.terminal.gwt.client.ContainerResizedListener;\r
+import com.vaadin.terminal.gwt.client.Focusable;\r
+import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;\r
+import com.vaadin.terminal.gwt.client.LocaleService;\r
+import com.vaadin.terminal.gwt.client.Paintable;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VTextualDate extends VDateField implements Paintable, Field,\r
+        ChangeListener, ContainerResizedListener, Focusable {\r
+\r
+    private static final String PARSE_ERROR_CLASSNAME = CLASSNAME\r
+            + "-parseerror";\r
+\r
+    private final TextBox text;\r
+\r
+    private String formatStr;\r
+\r
+    private String width;\r
+\r
+    private boolean needLayout;\r
+\r
+    protected int fieldExtraWidth = -1;\r
+\r
+    public VTextualDate() {\r
+        super();\r
+        text = new TextBox();\r
+        // use normal textfield styles as a basis\r
+        text.setStyleName(VTextField.CLASSNAME);\r
+        // add datefield spesific style name also\r
+        text.addStyleName(CLASSNAME + "-textfield");\r
+        text.addChangeListener(this);\r
+        add(text);\r
+    }\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+\r
+        int origRes = currentResolution;\r
+        super.updateFromUIDL(uidl, client);\r
+        if (origRes != currentResolution) {\r
+            // force recreating format string\r
+            formatStr = null;\r
+        }\r
+        if (uidl.hasAttribute("format")) {\r
+            formatStr = uidl.getStringAttribute("format");\r
+        }\r
+\r
+        buildDate();\r
+        // not a FocusWidget -> needs own tabindex handling\r
+        if (uidl.hasAttribute("tabindex")) {\r
+            text.setTabIndex(uidl.getIntAttribute("tabindex"));\r
+        }\r
+    }\r
+\r
+    protected String getFormatString() {\r
+        if (formatStr == null) {\r
+            if (currentResolution == RESOLUTION_YEAR) {\r
+                formatStr = "yyyy"; // force full year\r
+            } else {\r
+\r
+                try {\r
+                    String frmString = LocaleService\r
+                            .getDateFormat(currentLocale);\r
+                    frmString = cleanFormat(frmString);\r
+                    String delim = LocaleService\r
+                            .getClockDelimiter(currentLocale);\r
+\r
+                    if (currentResolution >= RESOLUTION_HOUR) {\r
+                        if (dts.isTwelveHourClock()) {\r
+                            frmString += " hh";\r
+                        } else {\r
+                            frmString += " HH";\r
+                        }\r
+                        if (currentResolution >= RESOLUTION_MIN) {\r
+                            frmString += ":mm";\r
+                            if (currentResolution >= RESOLUTION_SEC) {\r
+                                frmString += ":ss";\r
+                                if (currentResolution >= RESOLUTION_MSEC) {\r
+                                    frmString += ".SSS";\r
+                                }\r
+                            }\r
+                        }\r
+                        if (dts.isTwelveHourClock()) {\r
+                            frmString += " aaa";\r
+                        }\r
+\r
+                    }\r
+\r
+                    formatStr = frmString;\r
+                } catch (LocaleNotLoadedException e) {\r
+                    ClientExceptionHandler.displayError(e);\r
+                }\r
+            }\r
+        }\r
+        return formatStr;\r
+    }\r
+\r
+    /**\r
+     * \r
+     */\r
+    protected void buildDate() {\r
+        removeStyleName(PARSE_ERROR_CLASSNAME);\r
+        // Create the initial text for the textfield\r
+        String dateText;\r
+        if (date != null) {\r
+            dateText = DateTimeFormat.getFormat(getFormatString()).format(date);\r
+        } else {\r
+            dateText = "";\r
+        }\r
+\r
+        text.setText(dateText);\r
+        text.setEnabled(enabled && !readonly);\r
+\r
+        if (readonly) {\r
+            text.addStyleName("i-readonly");\r
+        } else {\r
+            text.removeStyleName("i-readonly");\r
+        }\r
+\r
+    }\r
+\r
+    public void onChange(Widget sender) {\r
+        if (sender == text) {\r
+            if (!text.getText().equals("")) {\r
+                try {\r
+                    DateTimeFormat format = DateTimeFormat\r
+                            .getFormat(getFormatString());\r
+                    date = format.parse(text.getText());\r
+                    long stamp = date.getTime();\r
+                    if (stamp == 0) {\r
+                        // If date parsing fails in firefox the stamp will be 0\r
+                        date = null;\r
+                        addStyleName(PARSE_ERROR_CLASSNAME);\r
+                    } else {\r
+                        // remove possibly added invalid value indication\r
+                        removeStyleName(PARSE_ERROR_CLASSNAME);\r
+                    }\r
+                } catch (final Exception e) {\r
+                    ClientExceptionHandler.displayError(e.getMessage());\r
+\r
+                    addStyleName(PARSE_ERROR_CLASSNAME);\r
+                    // this is a hack that may eventually be removed\r
+                    client.updateVariable(id, "lastInvalidDateString", text\r
+                            .getText(), false);\r
+                    date = null;\r
+                }\r
+            } else {\r
+                date = null;\r
+                // remove possibly added invalid value indication\r
+                removeStyleName(PARSE_ERROR_CLASSNAME);\r
+            }\r
+            // always send the date string\r
+            client.updateVariable(id, "dateString", text.getText(), false);\r
+\r
+            if (date != null) {\r
+                showingDate = new Date(date.getTime());\r
+            }\r
+\r
+            // Update variables\r
+            // (only the smallest defining resolution needs to be\r
+            // immediate)\r
+            client.updateVariable(id, "year",\r
+                    date != null ? date.getYear() + 1900 : -1,\r
+                    currentResolution == VDateField.RESOLUTION_YEAR\r
+                            && immediate);\r
+            if (currentResolution >= VDateField.RESOLUTION_MONTH) {\r
+                client.updateVariable(id, "month", date != null ? date\r
+                        .getMonth() + 1 : -1,\r
+                        currentResolution == VDateField.RESOLUTION_MONTH\r
+                                && immediate);\r
+            }\r
+            if (currentResolution >= VDateField.RESOLUTION_DAY) {\r
+                client.updateVariable(id, "day", date != null ? date.getDate()\r
+                        : -1, currentResolution == VDateField.RESOLUTION_DAY\r
+                        && immediate);\r
+            }\r
+            if (currentResolution >= VDateField.RESOLUTION_HOUR) {\r
+                client.updateVariable(id, "hour", date != null ? date\r
+                        .getHours() : -1,\r
+                        currentResolution == VDateField.RESOLUTION_HOUR\r
+                                && immediate);\r
+            }\r
+            if (currentResolution >= VDateField.RESOLUTION_MIN) {\r
+                client.updateVariable(id, "min", date != null ? date\r
+                        .getMinutes() : -1,\r
+                        currentResolution == VDateField.RESOLUTION_MIN\r
+                                && immediate);\r
+            }\r
+            if (currentResolution >= VDateField.RESOLUTION_SEC) {\r
+                client.updateVariable(id, "sec", date != null ? date\r
+                        .getSeconds() : -1,\r
+                        currentResolution == VDateField.RESOLUTION_SEC\r
+                                && immediate);\r
+            }\r
+            if (currentResolution == VDateField.RESOLUTION_MSEC) {\r
+                client.updateVariable(id, "msec",\r
+                        date != null ? getMilliseconds() : -1, immediate);\r
+            }\r
+\r
+        }\r
+    }\r
+\r
+    private String cleanFormat(String format) {\r
+        // Remove unnecessary d & M if resolution is too low\r
+        if (currentResolution < VDateField.RESOLUTION_DAY) {\r
+            format = format.replaceAll("d", "");\r
+        }\r
+        if (currentResolution < VDateField.RESOLUTION_MONTH) {\r
+            format = format.replaceAll("M", "");\r
+        }\r
+\r
+        // Remove unsupported patterns\r
+        // TODO support for 'G', era designator (used at least in Japan)\r
+        format = format.replaceAll("[GzZwWkK]", "");\r
+\r
+        // Remove extra delimiters ('/' and '.')\r
+        while (format.startsWith("/") || format.startsWith(".")\r
+                || format.startsWith("-")) {\r
+            format = format.substring(1);\r
+        }\r
+        while (format.endsWith("/") || format.endsWith(".")\r
+                || format.endsWith("-")) {\r
+            format = format.substring(0, format.length() - 1);\r
+        }\r
+\r
+        // Remove duplicate delimiters\r
+        format = format.replaceAll("//", "/");\r
+        format = format.replaceAll("\\.\\.", ".");\r
+        format = format.replaceAll("--", "-");\r
+\r
+        return format.trim();\r
+    }\r
+\r
+    @Override\r
+    public void setWidth(String newWidth) {\r
+        if (!"".equals(newWidth) && (width == null || !newWidth.equals(width))) {\r
+            if (BrowserInfo.get().isIE6()) {\r
+                // in IE6 cols ~ min-width\r
+                DOM.setElementProperty(text.getElement(), "size", "1");\r
+            }\r
+            needLayout = true;\r
+            width = newWidth;\r
+            super.setWidth(width);\r
+            iLayout();\r
+            if (newWidth.indexOf("%") < 0) {\r
+                needLayout = false;\r
+            }\r
+        } else {\r
+            if ("".equals(newWidth) && width != null && !"".equals(width)) {\r
+                if (BrowserInfo.get().isIE6()) {\r
+                    // revert IE6 hack\r
+                    DOM.setElementProperty(text.getElement(), "size", "");\r
+                }\r
+                super.setWidth("");\r
+                needLayout = true;\r
+                iLayout();\r
+                needLayout = false;\r
+                width = null;\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns pixels in x-axis reserved for other than textfield content.\r
+     * \r
+     * @return extra width in pixels\r
+     */\r
+    protected int getFieldExtraWidth() {\r
+        if (fieldExtraWidth < 0) {\r
+            text.setWidth("0px");\r
+            fieldExtraWidth = text.getOffsetWidth();\r
+        }\r
+        return fieldExtraWidth;\r
+    }\r
+\r
+    public void iLayout() {\r
+        if (needLayout) {\r
+            text.setWidth((getOffsetWidth() - getFieldExtraWidth()) + "px");\r
+        }\r
+    }\r
+\r
+    public void focus() {\r
+        text.setFocus(true);\r
+    }\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTime.java b/src/com/vaadin/terminal/gwt/client/ui/VTime.java
new file mode 100644 (file)
index 0000000..8b9c1e0
--- /dev/null
@@ -0,0 +1,317 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Date;\r
+\r
+import com.google.gwt.user.client.ui.ChangeListener;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.google.gwt.user.client.ui.ListBox;\r
+import com.google.gwt.user.client.ui.Widget;\r
+\r
+public class VTime extends FlowPanel implements ChangeListener {\r
+\r
+    private final VDateField datefield;\r
+\r
+    private ListBox hours;\r
+\r
+    private ListBox mins;\r
+\r
+    private ListBox sec;\r
+\r
+    private ListBox msec;\r
+\r
+    private ListBox ampm;\r
+\r
+    private int resolution = VDateField.RESOLUTION_HOUR;\r
+\r
+    private boolean readonly;\r
+\r
+    public VTime(VDateField parent) {\r
+        super();\r
+        datefield = parent;\r
+        setStyleName(VDateField.CLASSNAME + "-time");\r
+    }\r
+\r
+    private void buildTime(boolean redraw) {\r
+        final boolean thc = datefield.getDateTimeService().isTwelveHourClock();\r
+        if (redraw) {\r
+            clear();\r
+            final int numHours = thc ? 12 : 24;\r
+            hours = new ListBox();\r
+            hours.setStyleName(VNativeSelect.CLASSNAME);\r
+            for (int i = 0; i < numHours; i++) {\r
+                hours.addItem((i < 10) ? "0" + i : "" + i);\r
+            }\r
+            hours.addChangeListener(this);\r
+            if (thc) {\r
+                ampm = new ListBox();\r
+                ampm.setStyleName(VNativeSelect.CLASSNAME);\r
+                final String[] ampmText = datefield.getDateTimeService()\r
+                        .getAmPmStrings();\r
+                ampm.addItem(ampmText[0]);\r
+                ampm.addItem(ampmText[1]);\r
+                ampm.addChangeListener(this);\r
+            }\r
+\r
+            if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_MIN) {\r
+                mins = new ListBox();\r
+                mins.setStyleName(VNativeSelect.CLASSNAME);\r
+                for (int i = 0; i < 60; i++) {\r
+                    mins.addItem((i < 10) ? "0" + i : "" + i);\r
+                }\r
+                mins.addChangeListener(this);\r
+            }\r
+            if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_SEC) {\r
+                sec = new ListBox();\r
+                sec.setStyleName(VNativeSelect.CLASSNAME);\r
+                for (int i = 0; i < 60; i++) {\r
+                    sec.addItem((i < 10) ? "0" + i : "" + i);\r
+                }\r
+                sec.addChangeListener(this);\r
+            }\r
+            if (datefield.getCurrentResolution() == VDateField.RESOLUTION_MSEC) {\r
+                msec = new ListBox();\r
+                msec.setStyleName(VNativeSelect.CLASSNAME);\r
+                for (int i = 0; i < 1000; i++) {\r
+                    if (i < 10) {\r
+                        msec.addItem("00" + i);\r
+                    } else if (i < 100) {\r
+                        msec.addItem("0" + i);\r
+                    } else {\r
+                        msec.addItem("" + i);\r
+                    }\r
+                }\r
+                msec.addChangeListener(this);\r
+            }\r
+\r
+            final String delimiter = datefield.getDateTimeService()\r
+                    .getClockDelimeter();\r
+            final boolean ro = datefield.isReadonly();\r
+\r
+            if (ro) {\r
+                int h = 0;\r
+                if (datefield.getCurrentDate() != null) {\r
+                    h = datefield.getCurrentDate().getHours();\r
+                }\r
+                if (thc) {\r
+                    h -= h < 12 ? 0 : 12;\r
+                }\r
+                add(new VLabel(h < 10 ? "0" + h : "" + h));\r
+            } else {\r
+                add(hours);\r
+            }\r
+\r
+            if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_MIN) {\r
+                add(new VLabel(delimiter));\r
+                if (ro) {\r
+                    final int m = mins.getSelectedIndex();\r
+                    add(new VLabel(m < 10 ? "0" + m : "" + m));\r
+                } else {\r
+                    add(mins);\r
+                }\r
+            }\r
+            if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_SEC) {\r
+                add(new VLabel(delimiter));\r
+                if (ro) {\r
+                    final int s = sec.getSelectedIndex();\r
+                    add(new VLabel(s < 10 ? "0" + s : "" + s));\r
+                } else {\r
+                    add(sec);\r
+                }\r
+            }\r
+            if (datefield.getCurrentResolution() == VDateField.RESOLUTION_MSEC) {\r
+                add(new VLabel("."));\r
+                if (ro) {\r
+                    final int m = datefield.getMilliseconds();\r
+                    final String ms = m < 100 ? "0" + m : "" + m;\r
+                    add(new VLabel(m < 10 ? "0" + ms : ms));\r
+                } else {\r
+                    add(msec);\r
+                }\r
+            }\r
+            if (datefield.getCurrentResolution() == VDateField.RESOLUTION_HOUR) {\r
+                add(new VLabel(delimiter + "00")); // o'clock\r
+            }\r
+            if (thc) {\r
+                add(new VLabel("&nbsp;"));\r
+                if (ro) {\r
+                    add(new VLabel(ampm.getItemText(datefield.getCurrentDate()\r
+                            .getHours() < 12 ? 0 : 1)));\r
+                } else {\r
+                    add(ampm);\r
+                }\r
+            }\r
+\r
+            if (ro) {\r
+                return;\r
+            }\r
+        }\r
+\r
+        // Update times\r
+        Date cdate = datefield.getCurrentDate();\r
+        boolean selected = true;\r
+        if (cdate == null) {\r
+            cdate = new Date();\r
+            selected = false;\r
+        }\r
+        if (thc) {\r
+            int h = cdate.getHours();\r
+            ampm.setSelectedIndex(h < 12 ? 0 : 1);\r
+            h -= ampm.getSelectedIndex() * 12;\r
+            hours.setSelectedIndex(h);\r
+        } else {\r
+            hours.setSelectedIndex(cdate.getHours());\r
+        }\r
+        if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_MIN) {\r
+            mins.setSelectedIndex(cdate.getMinutes());\r
+        }\r
+        if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_SEC) {\r
+            sec.setSelectedIndex(cdate.getSeconds());\r
+        }\r
+        if (datefield.getCurrentResolution() == VDateField.RESOLUTION_MSEC) {\r
+            if (selected) {\r
+                msec.setSelectedIndex(datefield.getMilliseconds());\r
+            } else {\r
+                msec.setSelectedIndex(0);\r
+            }\r
+        }\r
+        if (thc) {\r
+            ampm.setSelectedIndex(cdate.getHours() < 12 ? 0 : 1);\r
+        }\r
+\r
+        if (datefield.isReadonly() && !redraw) {\r
+            // Do complete redraw when in read-only status\r
+            clear();\r
+            final String delimiter = datefield.getDateTimeService()\r
+                    .getClockDelimeter();\r
+\r
+            int h = cdate.getHours();\r
+            if (thc) {\r
+                h -= h < 12 ? 0 : 12;\r
+            }\r
+            add(new VLabel(h < 10 ? "0" + h : "" + h));\r
+\r
+            if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_MIN) {\r
+                add(new VLabel(delimiter));\r
+                final int m = mins.getSelectedIndex();\r
+                add(new VLabel(m < 10 ? "0" + m : "" + m));\r
+            }\r
+            if (datefield.getCurrentResolution() >= VDateField.RESOLUTION_SEC) {\r
+                add(new VLabel(delimiter));\r
+                final int s = sec.getSelectedIndex();\r
+                add(new VLabel(s < 10 ? "0" + s : "" + s));\r
+            }\r
+            if (datefield.getCurrentResolution() == VDateField.RESOLUTION_MSEC) {\r
+                add(new VLabel("."));\r
+                final int m = datefield.getMilliseconds();\r
+                final String ms = m < 100 ? "0" + m : "" + m;\r
+                add(new VLabel(m < 10 ? "0" + ms : ms));\r
+            }\r
+            if (datefield.getCurrentResolution() == VDateField.RESOLUTION_HOUR) {\r
+                add(new VLabel(delimiter + "00")); // o'clock\r
+            }\r
+            if (thc) {\r
+                add(new VLabel("&nbsp;"));\r
+                add(new VLabel(ampm.getItemText(cdate.getHours() < 12 ? 0 : 1)));\r
+            }\r
+        }\r
+\r
+        final boolean enabled = datefield.isEnabled();\r
+        hours.setEnabled(enabled);\r
+        if (mins != null) {\r
+            mins.setEnabled(enabled);\r
+        }\r
+        if (sec != null) {\r
+            sec.setEnabled(enabled);\r
+        }\r
+        if (msec != null) {\r
+            msec.setEnabled(enabled);\r
+        }\r
+        if (ampm != null) {\r
+            ampm.setEnabled(enabled);\r
+        }\r
+\r
+    }\r
+\r
+    public void updateTime(boolean redraw) {\r
+        buildTime(redraw || resolution != datefield.getCurrentResolution()\r
+                || readonly != datefield.isReadonly());\r
+        if (datefield instanceof VTextualDate) {\r
+            ((VTextualDate) datefield).buildDate();\r
+        }\r
+        resolution = datefield.getCurrentResolution();\r
+        readonly = datefield.isReadonly();\r
+    }\r
+\r
+    public void onChange(Widget sender) {\r
+        if (datefield.getCurrentDate() == null) {\r
+            // was null on server, need to set\r
+            Date now = datefield.getShowingDate();\r
+            if (now == null) {\r
+                now = new Date();\r
+                datefield.setShowingDate(now);\r
+            }\r
+            datefield.setCurrentDate(new Date(now.getTime()));\r
+\r
+            // Init variables with current time\r
+            datefield.getClient().updateVariable(datefield.getId(), "year",\r
+                    now.getYear() + 1900, false);\r
+            datefield.getClient().updateVariable(datefield.getId(), "month",\r
+                    now.getMonth() + 1, false);\r
+            datefield.getClient().updateVariable(datefield.getId(), "day",\r
+                    now.getDate(), false);\r
+            datefield.getClient().updateVariable(datefield.getId(), "hour",\r
+                    now.getHours(), false);\r
+            datefield.getClient().updateVariable(datefield.getId(), "min",\r
+                    now.getMinutes(), false);\r
+            datefield.getClient().updateVariable(datefield.getId(), "sec",\r
+                    now.getSeconds(), false);\r
+            datefield.getClient().updateVariable(datefield.getId(), "msec",\r
+                    datefield.getMilliseconds(), false);\r
+        }\r
+        if (sender == hours) {\r
+            int h = hours.getSelectedIndex();\r
+            if (datefield.getDateTimeService().isTwelveHourClock()) {\r
+                h = h + ampm.getSelectedIndex() * 12;\r
+            }\r
+            datefield.getCurrentDate().setHours(h);\r
+            datefield.getShowingDate().setHours(h);\r
+            datefield.getClient().updateVariable(datefield.getId(), "hour", h,\r
+                    datefield.isImmediate());\r
+            updateTime(false);\r
+        } else if (sender == mins) {\r
+            final int m = mins.getSelectedIndex();\r
+            datefield.getCurrentDate().setMinutes(m);\r
+            datefield.getShowingDate().setMinutes(m);\r
+            datefield.getClient().updateVariable(datefield.getId(), "min", m,\r
+                    datefield.isImmediate());\r
+            updateTime(false);\r
+        } else if (sender == sec) {\r
+            final int s = sec.getSelectedIndex();\r
+            datefield.getCurrentDate().setSeconds(s);\r
+            datefield.getShowingDate().setSeconds(s);\r
+            datefield.getClient().updateVariable(datefield.getId(), "sec", s,\r
+                    datefield.isImmediate());\r
+            updateTime(false);\r
+        } else if (sender == msec) {\r
+            final int ms = msec.getSelectedIndex();\r
+            datefield.setMilliseconds(ms);\r
+            datefield.setShowingMilliseconds(ms);\r
+            datefield.getClient().updateVariable(datefield.getId(), "msec", ms,\r
+                    datefield.isImmediate());\r
+            updateTime(false);\r
+        } else if (sender == ampm) {\r
+            final int h = hours.getSelectedIndex() + ampm.getSelectedIndex()\r
+                    * 12;\r
+            datefield.getCurrentDate().setHours(h);\r
+            datefield.getShowingDate().setHours(h);\r
+            datefield.getClient().updateVariable(datefield.getId(), "hour", h,\r
+                    datefield.isImmediate());\r
+            updateTime(false);\r
+        }\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VToolkitOverlay.java b/src/com/vaadin/terminal/gwt/client/ui/VToolkitOverlay.java
new file mode 100644 (file)
index 0000000..9ea284b
--- /dev/null
@@ -0,0 +1,313 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.animation.client.Animation;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.PopupListener;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+
+/**
+ * In Toolkit UI this Overlay should always be used for all elements that
+ * temporary float over other components like context menus etc. This is to deal
+ * stacking order correctly with VWindow objects.
+ */
+public class VToolkitOverlay extends PopupPanel {
+
+    /*
+     * The z-index value from where all overlays live. This can be overridden in
+     * any extending class.
+     */
+    protected static int Z_INDEX = 20000;
+
+    /*
+     * Shadow element style. If an extending class wishes to use a different
+     * style of shadow, it can use setShadowStyle(String) to give the shadow
+     * element a new style name.
+     */
+    public static final String CLASSNAME_SHADOW = "i-shadow";
+
+    /*
+     * The shadow element for this overlay.
+     */
+    private Element shadow;
+
+    /**
+     * The HTML snippet that is used to render the actual shadow. In consists of
+     * nine different DIV-elements with the following class names:
+     * 
+     * <pre>
+     *   .i-shadow[-stylename]
+     *   ----------------------------------------------
+     *   | .top-left     |   .top    |     .top-right |
+     *   |---------------|-----------|----------------|
+     *   |               |           |                |
+     *   | .left         |  .center  |         .right |
+     *   |               |           |                |
+     *   |---------------|-----------|----------------|
+     *   | .bottom-left  |  .bottom  |  .bottom-right |
+     *   ----------------------------------------------
+     * </pre>
+     * 
+     * See default theme 'shadow.css' for implementation example.
+     */
+    private static final String SHADOW_HTML = "<div class=\"top-left\"></div><div class=\"top\"></div><div class=\"top-right\"></div><div class=\"left\"></div><div class=\"center\"></div><div class=\"right\"></div><div class=\"bottom-left\"></div><div class=\"bottom\"></div><div class=\"bottom-right\"></div>";
+
+    public VToolkitOverlay() {
+        super();
+        adjustZIndex();
+    }
+
+    public VToolkitOverlay(boolean autoHide) {
+        super(autoHide);
+        adjustZIndex();
+    }
+
+    public VToolkitOverlay(boolean autoHide, boolean modal) {
+        super(autoHide, modal);
+        adjustZIndex();
+    }
+
+    public VToolkitOverlay(boolean autoHide, boolean modal, boolean showShadow) {
+        super(autoHide, modal);
+        if (showShadow) {
+            shadow = DOM.createDiv();
+            shadow.setClassName(CLASSNAME_SHADOW);
+            shadow.setInnerHTML(SHADOW_HTML);
+            DOM.setStyleAttribute(shadow, "position", "absolute");
+
+            addPopupListener(new PopupListener() {
+                public void onPopupClosed(PopupPanel sender, boolean autoClosed) {
+                    if (shadow.getParentElement() != null) {
+                        shadow.getParentElement().removeChild(shadow);
+                    }
+                }
+            });
+        }
+        adjustZIndex();
+    }
+
+    private void adjustZIndex() {
+        setZIndex(Z_INDEX);
+    }
+
+    /**
+     * Set the z-index (visual stack position) for this overlay.
+     * 
+     * @param zIndex
+     *            The new z-index
+     */
+    protected void setZIndex(int zIndex) {
+        DOM.setStyleAttribute(getElement(), "zIndex", "" + zIndex);
+        if (shadow != null) {
+            DOM.setStyleAttribute(shadow, "zIndex", "" + zIndex);
+        }
+        if (BrowserInfo.get().isIE6()) {
+            adjustIE6Frame(getElement(), zIndex - 1);
+        }
+    }
+
+    /**
+     * Get the z-index (visual stack position) of this overlay.
+     * 
+     * @return The z-index for this overlay.
+     */
+    private int getZIndex() {
+        return Integer.parseInt(DOM.getStyleAttribute(getElement(), "zIndex"));
+    }
+
+    @Override
+    public void setPopupPosition(int left, int top) {
+        super.setPopupPosition(left, top);
+        if (shadow != null) {
+            updateShadowSizeAndPosition(isAnimationEnabled() ? 0 : 1);
+        }
+    }
+
+    @Override
+    public void show() {
+        super.show();
+        if (shadow != null) {
+            if (isAnimationEnabled()) {
+                ShadowAnimation sa = new ShadowAnimation();
+                sa.run(200);
+            } else {
+                updateShadowSizeAndPosition(1.0);
+            }
+        }
+        if (BrowserInfo.get().isIE6()) {
+            adjustIE6Frame(getElement(), getZIndex());
+        }
+    }
+
+    @Override
+    public void setVisible(boolean visible) {
+        super.setVisible(visible);
+        if (shadow != null) {
+            shadow.getStyle().setProperty("visibility",
+                    visible ? "visible" : "hidden");
+        }
+    }
+
+    /*
+     * Needed to position overlays on top of native SELECT elements in IE6. See
+     * bug #2004
+     */
+    private native void adjustIE6Frame(Element popup, int zindex)
+    /*-{
+        // relies on PopupImplIE6
+        if(popup.__frame) 
+            popup.__frame.style.zIndex = zindex;
+    }-*/;
+
+    @Override
+    public void setWidth(String width) {
+        super.setWidth(width);
+        if (shadow != null) {
+            updateShadowSizeAndPosition(1.0);
+        }
+    }
+
+    @Override
+    public void setHeight(String height) {
+        super.setHeight(height);
+        if (shadow != null) {
+            updateShadowSizeAndPosition(1.0);
+        }
+    }
+
+    /**
+     * Sets the shadow style for this overlay. Will override any previous style
+     * for the shadow. The default style name is defined by CLASSNAME_SHADOW.
+     * The given style will be prefixed with CLASSNAME_SHADOW.
+     * 
+     * @param style
+     *            The new style name for the shadow element. Will be prefixed by
+     *            CLASSNAME_SHADOW, e.g. style=='foobar' -> actual style
+     *            name=='i-shadow-foobar'.
+     */
+    protected void setShadowStyle(String style) {
+        if (shadow != null) {
+            shadow.setClassName(CLASSNAME_SHADOW + "-" + style);
+        }
+    }
+
+    /*
+     * Extending classes should always call this method after they change the
+     * size of overlay without using normal 'setWidth(String)' and
+     * 'setHeight(String)' methods (if not calling super.setWidth/Height).
+     */
+    protected void updateShadowSizeAndPosition() {
+        updateShadowSizeAndPosition(1.0);
+    }
+
+    /**
+     * Recalculates proper position and dimensions for the shadow element. Can
+     * be used to animate the shadow, using the 'progress' parameter (used to
+     * animate the shadow in sync with GWT PopupPanel's default animation
+     * 'PopupPanel.AnimationType.CENTER').
+     * 
+     * @param progress
+     *            A value between 0.0 and 1.0, indicating the progress of the
+     *            animation (0=start, 1=end).
+     */
+    private void updateShadowSizeAndPosition(final double progress) {
+        // Don't do anything if overlay element is not attached
+        if (!isAttached()) {
+            return;
+        }
+        // Calculate proper z-index
+        String zIndex = null;
+        try {
+            // Odd behaviour with Windows Hosted Mode forces us to use
+            // this redundant try/catch block (See dev.itmill.com #2011)
+            zIndex = DOM.getStyleAttribute(getElement(), "zIndex");
+        } catch (Exception ignore) {
+            // Ignored, will cause no harm
+        }
+        if (zIndex == null) {
+            zIndex = "" + Z_INDEX;
+        }
+        // Calculate position and size
+        if (BrowserInfo.get().isIE()) {
+            // Shake IE
+            getOffsetHeight();
+            getOffsetWidth();
+        }
+
+        int x = getAbsoluteLeft();
+        int y = getAbsoluteTop();
+
+        /* This is needed for IE7 at least */
+        // Account for the difference between absolute position and the
+        // body's positioning context.
+        x -= Document.get().getBodyOffsetLeft();
+        y -= Document.get().getBodyOffsetTop();
+
+        int width = getOffsetWidth();
+        int height = getOffsetHeight();
+
+        if (width < 0) {
+            width = 0;
+        }
+        if (height < 0) {
+            height = 0;
+        }
+
+        // Animate the shadow size
+        x += (int) (width * (1.0 - progress) / 2.0);
+        y += (int) (height * (1.0 - progress) / 2.0);
+        width = (int) (width * progress);
+        height = (int) (height * progress);
+
+        // Opera needs some shaking to get parts of the shadow showing
+        // properly
+        // (ticket #2704)
+        if (BrowserInfo.get().isOpera()) {
+            // Clear the height of all middle elements
+            DOM.getChild(shadow, 3).getStyle().setProperty("height", "auto");
+            DOM.getChild(shadow, 4).getStyle().setProperty("height", "auto");
+            DOM.getChild(shadow, 5).getStyle().setProperty("height", "auto");
+        }
+
+        // Update correct values
+        DOM.setStyleAttribute(shadow, "zIndex", zIndex);
+        DOM.setStyleAttribute(shadow, "width", width + "px");
+        DOM.setStyleAttribute(shadow, "height", height + "px");
+        DOM.setStyleAttribute(shadow, "top", y + "px");
+        DOM.setStyleAttribute(shadow, "left", x + "px");
+        DOM.setStyleAttribute(shadow, "display", progress < 0.9 ? "none" : "");
+
+        // Opera fix, part 2 (ticket #2704)
+        if (BrowserInfo.get().isOpera()) {
+            // We'll fix the height of all the middle elements
+            DOM.getChild(shadow, 3).getStyle().setPropertyPx("height",
+                    DOM.getChild(shadow, 3).getOffsetHeight());
+            DOM.getChild(shadow, 4).getStyle().setPropertyPx("height",
+                    DOM.getChild(shadow, 4).getOffsetHeight());
+            DOM.getChild(shadow, 5).getStyle().setPropertyPx("height",
+                    DOM.getChild(shadow, 5).getOffsetHeight());
+        }
+
+        // Attach to dom if not there already
+        if (shadow.getParentElement() == null) {
+            RootPanel.get().getElement().insertBefore(shadow, getElement());
+        }
+
+    }
+
+    protected class ShadowAnimation extends Animation {
+        @Override
+        protected void onUpdate(double progress) {
+            if (shadow != null) {
+                updateShadowSizeAndPosition(progress);
+            }
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java
new file mode 100644 (file)
index 0000000..57887bb
--- /dev/null
@@ -0,0 +1,469 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+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.FlowPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.MouseEventDetails;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+/**
+ * 
+ */
+public class VTree extends FlowPanel implements Paintable {
+
+    public static final String CLASSNAME = "i-tree";
+
+    private Set<String> selectedIds = new HashSet<String>();
+    private ApplicationConnection client;
+    private String paintableId;
+    private boolean selectable;
+    private boolean isMultiselect;
+
+    private final HashMap<String, TreeNode> keyToNode = new HashMap<String, TreeNode>();
+
+    /**
+     * This map contains captions and icon urls for actions like: * "33_c" ->
+     * "Edit" * "33_i" -> "http://dom.com/edit.png"
+     */
+    private final HashMap<String, String> actionMap = new HashMap<String, String>();
+
+    private boolean immediate;
+
+    private boolean isNullSelectionAllowed = true;
+
+    private boolean disabled = false;
+
+    private boolean readonly;
+
+    private boolean emitClickEvents;
+
+    private boolean rendering;
+
+    public VTree() {
+        super();
+        setStyleName(CLASSNAME);
+    }
+
+    private void updateActionMap(UIDL c) {
+        final Iterator it = c.getChildIterator();
+        while (it.hasNext()) {
+            final UIDL action = (UIDL) it.next();
+            final String key = action.getStringAttribute("key");
+            final String caption = action.getStringAttribute("caption");
+            actionMap.put(key + "_c", caption);
+            if (action.hasAttribute("icon")) {
+                // TODO need some uri handling ??
+                actionMap.put(key + "_i", client.translateToolkitUri(action
+                        .getStringAttribute("icon")));
+            }
+        }
+
+    }
+
+    public String getActionCaption(String actionKey) {
+        return actionMap.get(actionKey + "_c");
+    }
+
+    public String getActionIcon(String actionKey) {
+        return actionMap.get(actionKey + "_i");
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        // Ensure correct implementation and let container manage caption
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        rendering = true;
+
+        this.client = client;
+
+        if (uidl.hasAttribute("partialUpdate")) {
+            handleUpdate(uidl);
+            rendering = false;
+            return;
+        }
+
+        paintableId = uidl.getId();
+
+        immediate = uidl.hasAttribute("immediate");
+
+        disabled = uidl.getBooleanAttribute("disabled");
+        readonly = uidl.getBooleanAttribute("readonly");
+        emitClickEvents = uidl.getBooleanAttribute("listenClicks");
+
+        isNullSelectionAllowed = uidl.getBooleanAttribute("nullselect");
+
+        clear();
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
+            final UIDL childUidl = (UIDL) i.next();
+            if ("actions".equals(childUidl.getTag())) {
+                updateActionMap(childUidl);
+                continue;
+            }
+            final TreeNode childTree = new TreeNode();
+            this.add(childTree);
+            childTree.updateFromUIDL(childUidl, client);
+        }
+        final String selectMode = uidl.getStringAttribute("selectmode");
+        selectable = !"none".equals(selectMode);
+        isMultiselect = "multi".equals(selectMode);
+
+        selectedIds = uidl.getStringArrayVariableAsSet("selected");
+
+        rendering = false;
+
+    }
+
+    private void handleUpdate(UIDL uidl) {
+        final TreeNode rootNode = keyToNode.get(uidl
+                .getStringAttribute("rootKey"));
+        if (rootNode != null) {
+            if (!rootNode.getState()) {
+                // expanding node happened server side
+                rootNode.setState(true, false);
+            }
+            rootNode.renderChildNodes(uidl.getChildIterator());
+        }
+
+        if (uidl.hasVariable("selected")) {
+            // update selection in case selected nodes were not visible
+            selectedIds = uidl.getStringArrayVariableAsSet("selected");
+        }
+
+    }
+
+    public void setSelected(TreeNode treeNode, boolean selected) {
+        if (selected) {
+            if (!isMultiselect) {
+                while (selectedIds.size() > 0) {
+                    final String id = selectedIds.iterator().next();
+                    final TreeNode oldSelection = keyToNode.get(id);
+                    if (oldSelection != null) {
+                        // can be null if the node is not visible (parent
+                        // collapsed)
+                        oldSelection.setSelected(false);
+                    }
+                    selectedIds.remove(id);
+                }
+            }
+            treeNode.setSelected(true);
+            selectedIds.add(treeNode.key);
+        } else {
+            if (!isNullSelectionAllowed) {
+                if (!isMultiselect || selectedIds.size() == 1) {
+                    return;
+                }
+            }
+            selectedIds.remove(treeNode.key);
+            treeNode.setSelected(false);
+        }
+        client.updateVariable(paintableId, "selected", selectedIds.toArray(),
+                immediate);
+    }
+
+    public boolean isSelected(TreeNode treeNode) {
+        return selectedIds.contains(treeNode.key);
+    }
+
+    protected class TreeNode extends SimplePanel implements ActionOwner {
+
+        public static final String CLASSNAME = "i-tree-node";
+
+        String key;
+
+        private String[] actionKeys = null;
+
+        private boolean childrenLoaded;
+
+        private Element nodeCaptionDiv;
+
+        protected Element nodeCaptionSpan;
+
+        private FlowPanel childNodeContainer;
+
+        private boolean open;
+
+        private Icon icon;
+
+        private Element ie6compatnode;
+
+        public TreeNode() {
+            constructDom();
+            sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.ONMOUSEUP
+                    | Event.ONCONTEXTMENU);
+        }
+
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (disabled) {
+                return;
+            }
+            final int type = DOM.eventGetType(event);
+            final Element target = DOM.eventGetTarget(event);
+            if (emitClickEvents && target == nodeCaptionSpan
+                    && (type == Event.ONDBLCLICK || type == Event.ONMOUSEUP)) {
+                fireClick(event);
+            }
+            if (type == Event.ONCLICK) {
+                if (getElement() == target || ie6compatnode == target) {
+                    // state change
+                    toggleState();
+                } else if (!readonly && target == nodeCaptionSpan) {
+                    // caption click = selection change && possible click event
+                    toggleSelection();
+                }
+                DOM.eventCancelBubble(event, true);
+            } else if (type == Event.ONCONTEXTMENU) {
+                showContextMenu(event);
+            }
+        }
+
+        private void fireClick(Event evt) {
+            // non-immediate iff an immediate select event is going to happen
+            boolean imm = !immediate
+                    || !selectable
+                    || (!isNullSelectionAllowed && isSelected() && selectedIds
+                            .size() == 1);
+            MouseEventDetails details = new MouseEventDetails(evt);
+            client.updateVariable(paintableId, "clickedKey", key, false);
+            client.updateVariable(paintableId, "clickEvent",
+                    details.toString(), imm);
+        }
+
+        private void toggleSelection() {
+            if (selectable) {
+                VTree.this.setSelected(this, !isSelected());
+            }
+        }
+
+        private void toggleState() {
+            setState(!getState(), true);
+        }
+
+        protected void constructDom() {
+            // workaround for a very weird IE6 issue #1245
+            ie6compatnode = DOM.createDiv();
+            setStyleName(ie6compatnode, CLASSNAME + "-ie6compatnode");
+            DOM.setInnerText(ie6compatnode, " ");
+            DOM.appendChild(getElement(), ie6compatnode);
+
+            DOM.sinkEvents(ie6compatnode, Event.ONCLICK);
+
+            nodeCaptionDiv = DOM.createDiv();
+            DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME
+                    + "-caption");
+            Element wrapper = DOM.createDiv();
+            nodeCaptionSpan = DOM.createSpan();
+            DOM.appendChild(getElement(), nodeCaptionDiv);
+            DOM.appendChild(nodeCaptionDiv, wrapper);
+            DOM.appendChild(wrapper, nodeCaptionSpan);
+
+            childNodeContainer = new FlowPanel();
+            childNodeContainer.setStylePrimaryName(CLASSNAME + "-children");
+            setWidget(childNodeContainer);
+        }
+
+        public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+            setText(uidl.getStringAttribute("caption"));
+            key = uidl.getStringAttribute("key");
+
+            keyToNode.put(key, this);
+
+            if (uidl.hasAttribute("al")) {
+                actionKeys = uidl.getStringArrayAttribute("al");
+            }
+
+            if (uidl.getTag().equals("node")) {
+                if (uidl.getChildCount() == 0) {
+                    childNodeContainer.setVisible(false);
+                } else {
+                    renderChildNodes(uidl.getChildIterator());
+                    childrenLoaded = true;
+                }
+            } else {
+                addStyleName(CLASSNAME + "-leaf");
+            }
+            addStyleName(CLASSNAME);
+
+            if (uidl.getBooleanAttribute("expanded") && !getState()) {
+                setState(true, false);
+            }
+
+            if (uidl.getBooleanAttribute("selected")) {
+                setSelected(true);
+            }
+
+            if (uidl.hasAttribute("icon")) {
+                if (icon == null) {
+                    icon = new Icon(client);
+                    DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv), icon
+                            .getElement(), nodeCaptionSpan);
+                }
+                icon.setUri(uidl.getStringAttribute("icon"));
+            } else {
+                if (icon != null) {
+                    DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv), icon
+                            .getElement());
+                    icon = null;
+                }
+            }
+
+            if (BrowserInfo.get().isIE6() && isAttached()) {
+                fixWidth();
+            }
+        }
+
+        private void setState(boolean state, boolean notifyServer) {
+            if (open == state) {
+                return;
+            }
+            if (state) {
+                if (!childrenLoaded && notifyServer) {
+                    client.updateVariable(paintableId, "requestChildTree",
+                            true, false);
+                }
+                if (notifyServer) {
+                    client.updateVariable(paintableId, "expand",
+                            new String[] { key }, true);
+                }
+                addStyleName(CLASSNAME + "-expanded");
+                childNodeContainer.setVisible(true);
+
+            } else {
+                removeStyleName(CLASSNAME + "-expanded");
+                childNodeContainer.setVisible(false);
+                if (notifyServer) {
+                    client.updateVariable(paintableId, "collapse",
+                            new String[] { key }, true);
+                }
+            }
+            open = state;
+
+            if (!rendering) {
+                Util.notifyParentOfSizeChange(VTree.this, false);
+            }
+        }
+
+        private boolean getState() {
+            return open;
+        }
+
+        private void setText(String text) {
+            DOM.setInnerText(nodeCaptionSpan, text);
+        }
+
+        private void renderChildNodes(Iterator i) {
+            childNodeContainer.clear();
+            childNodeContainer.setVisible(true);
+            while (i.hasNext()) {
+                final UIDL childUidl = (UIDL) i.next();
+                // actions are in bit weird place, don't mix them with children,
+                // but current node's actions
+                if ("actions".equals(childUidl.getTag())) {
+                    updateActionMap(childUidl);
+                    continue;
+                }
+                final TreeNode childTree = new TreeNode();
+                childNodeContainer.add(childTree);
+                childTree.updateFromUIDL(childUidl, client);
+            }
+            childrenLoaded = true;
+        }
+
+        public boolean isChildrenLoaded() {
+            return childrenLoaded;
+        }
+
+        public Action[] getActions() {
+            if (actionKeys == null) {
+                return new Action[] {};
+            }
+            final Action[] actions = new Action[actionKeys.length];
+            for (int i = 0; i < actions.length; i++) {
+                final String actionKey = actionKeys[i];
+                final TreeAction a = new TreeAction(this, String.valueOf(key),
+                        actionKey);
+                a.setCaption(getActionCaption(actionKey));
+                a.setIconUrl(getActionIcon(actionKey));
+                actions[i] = a;
+            }
+            return actions;
+        }
+
+        public ApplicationConnection getClient() {
+            return client;
+        }
+
+        public String getPaintableId() {
+            return paintableId;
+        }
+
+        /**
+         * Adds/removes IT Mill Toolkit specific style name. This method ought
+         * to be called only from VTree.
+         * 
+         * @param selected
+         */
+        protected void setSelected(boolean selected) {
+            // add style name to caption dom structure only, not to subtree
+            setStyleName(nodeCaptionDiv, "i-tree-node-selected", selected);
+        }
+
+        protected boolean isSelected() {
+            return VTree.this.isSelected(this);
+        }
+
+        public void showContextMenu(Event event) {
+            if (!readonly && !disabled) {
+                if (actionKeys != null) {
+                    int left = event.getClientX();
+                    int top = event.getClientY();
+                    top += Window.getScrollTop();
+                    left += Window.getScrollLeft();
+                    client.getContextMenu().showAt(this, left, top);
+                }
+                event.cancelBubble(true);
+                event.preventDefault();
+            }
+        }
+
+        /*
+         * We need to fix the width of TreeNodes so that the float in
+         * ie6compatNode does not wrap (see ticket #1245)
+         */
+        private void fixWidth() {
+            nodeCaptionDiv.getStyle().setProperty("styleFloat", "left");
+            nodeCaptionDiv.getStyle().setProperty("display", "inline");
+            nodeCaptionDiv.getStyle().setProperty("marginLeft", "0");
+            final int captionWidth = ie6compatnode.getOffsetWidth()
+                    + nodeCaptionDiv.getOffsetWidth();
+            setWidth(captionWidth + "px");
+        }
+
+        @Override
+        public void onAttach() {
+            super.onAttach();
+            if (BrowserInfo.get().isIE6()) {
+                fixWidth();
+            }
+        }
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VTwinColSelect.java
new file mode 100644 (file)
index 0000000..a439b38
--- /dev/null
@@ -0,0 +1,244 @@
+/* \r
+@ITMillApache2LicenseForJavaFiles@\r
+ */\r
+\r
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Iterator;\r
+import java.util.Vector;\r
+\r
+import com.google.gwt.user.client.DOM;\r
+import com.google.gwt.user.client.ui.FlowPanel;\r
+import com.google.gwt.user.client.ui.HTML;\r
+import com.google.gwt.user.client.ui.ListBox;\r
+import com.google.gwt.user.client.ui.Panel;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+\r
+public class VTwinColSelect extends VOptionGroupBase {\r
+\r
+    private static final String CLASSNAME = "i-select-twincol";\r
+\r
+    private static final int VISIBLE_COUNT = 10;\r
+\r
+    private static final int DEFAULT_COLUMN_COUNT = 10;\r
+\r
+    private final ListBox options;\r
+\r
+    private final ListBox selections;\r
+\r
+    private final VButton add;\r
+\r
+    private final VButton remove;\r
+\r
+    private FlowPanel buttons;\r
+\r
+    private Panel panel;\r
+\r
+    private boolean widthSet = false;\r
+\r
+    public VTwinColSelect() {\r
+        super(CLASSNAME);\r
+        options = new ListBox();\r
+        options.addClickListener(this);\r
+        selections = new ListBox();\r
+        selections.addClickListener(this);\r
+        options.setVisibleItemCount(VISIBLE_COUNT);\r
+        selections.setVisibleItemCount(VISIBLE_COUNT);\r
+        options.setStyleName(CLASSNAME + "-options");\r
+        selections.setStyleName(CLASSNAME + "-selections");\r
+        buttons = new FlowPanel();\r
+        buttons.setStyleName(CLASSNAME + "-buttons");\r
+        add = new VButton();\r
+        add.setText(">>");\r
+        add.addClickListener(this);\r
+        remove = new VButton();\r
+        remove.setText("<<");\r
+        remove.addClickListener(this);\r
+        panel = ((Panel) optionsContainer);\r
+        panel.add(options);\r
+        buttons.add(add);\r
+        final HTML br = new HTML("<span/>");\r
+        br.setStyleName(CLASSNAME + "-deco");\r
+        buttons.add(br);\r
+        buttons.add(remove);\r
+        panel.add(buttons);\r
+        panel.add(selections);\r
+    }\r
+\r
+    @Override\r
+    protected void buildOptions(UIDL uidl) {\r
+        final boolean enabled = !isDisabled() && !isReadonly();\r
+        options.setMultipleSelect(isMultiselect());\r
+        selections.setMultipleSelect(isMultiselect());\r
+        options.setEnabled(enabled);\r
+        selections.setEnabled(enabled);\r
+        add.setEnabled(enabled);\r
+        remove.setEnabled(enabled);\r
+        options.clear();\r
+        selections.clear();\r
+        for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {\r
+            final UIDL optionUidl = (UIDL) i.next();\r
+            if (optionUidl.hasAttribute("selected")) {\r
+                selections.addItem(optionUidl.getStringAttribute("caption"),\r
+                        optionUidl.getStringAttribute("key"));\r
+            } else {\r
+                options.addItem(optionUidl.getStringAttribute("caption"),\r
+                        optionUidl.getStringAttribute("key"));\r
+            }\r
+        }\r
+\r
+        int cols = -1;\r
+        if (getColumns() > 0) {\r
+            cols = getColumns();\r
+        } else if (!widthSet) {\r
+            cols = DEFAULT_COLUMN_COUNT;\r
+        }\r
+\r
+        if (cols >= 0) {\r
+            options.setWidth(cols + "em");\r
+            selections.setWidth(cols + "em");\r
+            buttons.setWidth("3.5em");\r
+            optionsContainer.setWidth((2 * cols + 4) + "em");\r
+        }\r
+        if (getRows() > 0) {\r
+            options.setVisibleItemCount(getRows());\r
+            selections.setVisibleItemCount(getRows());\r
+\r
+        }\r
+\r
+    }\r
+\r
+    @Override\r
+    protected Object[] getSelectedItems() {\r
+        final Vector selectedItemKeys = new Vector();\r
+        for (int i = 0; i < selections.getItemCount(); i++) {\r
+            selectedItemKeys.add(selections.getValue(i));\r
+        }\r
+        return selectedItemKeys.toArray();\r
+    }\r
+\r
+    private boolean[] getItemsToAdd() {\r
+        final boolean[] selectedIndexes = new boolean[options.getItemCount()];\r
+        for (int i = 0; i < options.getItemCount(); i++) {\r
+            if (options.isItemSelected(i)) {\r
+                selectedIndexes[i] = true;\r
+            } else {\r
+                selectedIndexes[i] = false;\r
+            }\r
+        }\r
+        return selectedIndexes;\r
+    }\r
+\r
+    private boolean[] getItemsToRemove() {\r
+        final boolean[] selectedIndexes = new boolean[selections.getItemCount()];\r
+        for (int i = 0; i < selections.getItemCount(); i++) {\r
+            if (selections.isItemSelected(i)) {\r
+                selectedIndexes[i] = true;\r
+            } else {\r
+                selectedIndexes[i] = false;\r
+            }\r
+        }\r
+        return selectedIndexes;\r
+    }\r
+\r
+    @Override\r
+    public void onClick(Widget sender) {\r
+        super.onClick(sender);\r
+        if (sender == add) {\r
+            final boolean[] sel = getItemsToAdd();\r
+            for (int i = 0; i < sel.length; i++) {\r
+                if (sel[i]) {\r
+                    final int optionIndex = i\r
+                            - (sel.length - options.getItemCount());\r
+                    selectedKeys.add(options.getValue(optionIndex));\r
+\r
+                    // Move selection to another column\r
+                    final String text = options.getItemText(optionIndex);\r
+                    final String value = options.getValue(optionIndex);\r
+                    selections.addItem(text, value);\r
+                    selections.setItemSelected(selections.getItemCount() - 1,\r
+                            true);\r
+                    options.removeItem(optionIndex);\r
+                }\r
+            }\r
+            client.updateVariable(id, "selected", selectedKeys.toArray(),\r
+                    isImmediate());\r
+\r
+        } else if (sender == remove) {\r
+            final boolean[] sel = getItemsToRemove();\r
+            for (int i = 0; i < sel.length; i++) {\r
+                if (sel[i]) {\r
+                    final int selectionIndex = i\r
+                            - (sel.length - selections.getItemCount());\r
+                    selectedKeys.remove(selections.getValue(selectionIndex));\r
+\r
+                    // Move selection to another column\r
+                    final String text = selections.getItemText(selectionIndex);\r
+                    final String value = selections.getValue(selectionIndex);\r
+                    options.addItem(text, value);\r
+                    options.setItemSelected(options.getItemCount() - 1, true);\r
+                    selections.removeItem(selectionIndex);\r
+                }\r
+            }\r
+            client.updateVariable(id, "selected", selectedKeys.toArray(),\r
+                    isImmediate());\r
+        } else if (sender == options) {\r
+            // unselect all in other list, to avoid mistakes (i.e wrong button)\r
+            final int c = selections.getItemCount();\r
+            for (int i = 0; i < c; i++) {\r
+                selections.setItemSelected(i, false);\r
+            }\r
+        } else if (sender == selections) {\r
+            // unselect all in other list, to avoid mistakes (i.e wrong button)\r
+            final int c = options.getItemCount();\r
+            for (int i = 0; i < c; i++) {\r
+                options.setItemSelected(i, false);\r
+            }\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void setHeight(String height) {\r
+        super.setHeight(height);\r
+        if ("".equals(height)) {\r
+            options.setHeight("");\r
+            selections.setHeight("");\r
+        } else {\r
+            setFullHeightInternals();\r
+        }\r
+    }\r
+\r
+    private void setFullHeightInternals() {\r
+        options.setHeight("100%");\r
+        selections.setHeight("100%");\r
+    }\r
+\r
+    @Override\r
+    public void setWidth(String width) {\r
+        super.setWidth(width);\r
+        if (!"".equals(width) && width != null) {\r
+            setRelativeInternalWidths();\r
+        }\r
+    }\r
+\r
+    private void setRelativeInternalWidths() {\r
+        DOM.setStyleAttribute(getElement(), "position", "relative");\r
+        buttons.setWidth("15%");\r
+        options.setWidth("42%");\r
+        selections.setWidth("42%");\r
+        widthSet = true;\r
+    }\r
+\r
+    @Override\r
+    protected void setTabIndex(int tabIndex) {\r
+        options.setTabIndex(tabIndex);\r
+        selections.setTabIndex(tabIndex);\r
+        add.setTabIndex(tabIndex);\r
+        remove.setTabIndex(tabIndex);\r
+    }\r
+\r
+    public void focus() {\r
+        options.setFocus(true);\r
+    }\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java b/src/com/vaadin/terminal/gwt/client/ui/VUnknownComponent.java
new file mode 100644 (file)
index 0000000..12faa71
--- /dev/null
@@ -0,0 +1,40 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.Tree;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VUnknownComponent extends Composite implements Paintable {
+
+    com.google.gwt.user.client.ui.Label caption = new com.google.gwt.user.client.ui.Label();;
+    Tree uidlTree = new Tree();
+
+    public VUnknownComponent() {
+        final VerticalPanel panel = new VerticalPanel();
+        panel.add(caption);
+        panel.add(uidlTree);
+        initWidget(panel);
+        setStyleName("itmill-unknown");
+        caption.setStyleName("itmill-unknown-caption");
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+        setCaption("Client faced an unknown component type. Unrendered UIDL:");
+        uidlTree.clear();
+        uidlTree.addItem(uidl.dir());
+    }
+
+    public void setCaption(String c) {
+        caption.setText(c);
+    }
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUpload.java b/src/com/vaadin/terminal/gwt/client/ui/VUpload.java
new file mode 100644 (file)
index 0000000..0010bda
--- /dev/null
@@ -0,0 +1,152 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.Button;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.FileUpload;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FormHandler;
+import com.google.gwt.user.client.ui.FormPanel;
+import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
+import com.google.gwt.user.client.ui.FormSubmitEvent;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+public class VUpload extends FormPanel implements Paintable, ClickListener,
+        FormHandler {
+
+    public static final String CLASSNAME = "i-upload";
+
+    /**
+     * FileUpload component that opens native OS dialog to select file.
+     */
+    FileUpload fu = new FileUpload();
+
+    Panel panel = new FlowPanel();
+
+    ApplicationConnection client;
+
+    private String paintableId;
+
+    /**
+     * Button that initiates uploading
+     */
+    private final Button submitButton;
+
+    /**
+     * When expecting big files, programmer may initiate some UI changes when
+     * uploading the file starts. Bit after submitting file we'll visit the
+     * server to check possible changes.
+     */
+    private Timer t;
+
+    /**
+     * some browsers tries to send form twice if submit is called in button
+     * click handler, some don't submit at all without it, so we need to track
+     * if form is already being submitted
+     */
+    private boolean submitted = false;
+
+    private boolean enabled = true;
+
+    public VUpload() {
+        super();
+        setEncoding(FormPanel.ENCODING_MULTIPART);
+        setMethod(FormPanel.METHOD_POST);
+
+        setWidget(panel);
+        panel.add(fu);
+        submitButton = new Button();
+        submitButton.addClickListener(this);
+        panel.add(submitButton);
+
+        addFormHandler(this);
+
+        setStyleName(CLASSNAME);
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+        this.client = client;
+        paintableId = uidl.getId();
+        setAction(client.getAppUri());
+        submitButton.setText(uidl.getStringAttribute("buttoncaption"));
+        fu.setName(paintableId + "_file");
+
+        if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) {
+            disableUpload();
+        } else if (uidl.getBooleanAttribute("state")) {
+            enableUploaod();
+        }
+
+    }
+
+    public void onClick(Widget sender) {
+        submit();
+    }
+
+    public void onSubmit(FormSubmitEvent event) {
+        if (fu.getFilename().length() == 0 || submitted || !enabled) {
+            event.setCancelled(true);
+            ApplicationConnection
+                    .getConsole()
+                    .log(
+                            "Submit cancelled (disabled, no file or already submitted)");
+            return;
+        }
+        // flush possibly pending variable changes, so they will be handled
+        // before upload
+        client.sendPendingVariableChanges();
+
+        submitted = true;
+        ApplicationConnection.getConsole().log("Submitted form");
+
+        disableUpload();
+
+        /*
+         * Visit server a moment after upload has started to see possible
+         * changes from UploadStarted event. Will be cleared on complete.
+         */
+        t = new Timer() {
+            @Override
+            public void run() {
+                client.sendPendingVariableChanges();
+            }
+        };
+        t.schedule(800);
+    }
+
+    protected void disableUpload() {
+        submitButton.setEnabled(false);
+        fu.setVisible(false);
+        enabled = false;
+    }
+
+    protected void enableUploaod() {
+        submitButton.setEnabled(true);
+        fu.setVisible(true);
+        enabled = true;
+    }
+
+    public void onSubmitComplete(FormSubmitCompleteEvent event) {
+        if (client != null) {
+            if (t != null) {
+                t.cancel();
+            }
+            ApplicationConnection.getConsole().log("Submit complete");
+            client.sendPendingVariableChanges();
+        }
+        submitted = false;
+        enableUploaod();
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java b/src/com/vaadin/terminal/gwt/client/ui/VUriFragmentUtility.java
new file mode 100644 (file)
index 0000000..2b53711
--- /dev/null
@@ -0,0 +1,67 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.History;
+import com.google.gwt.user.client.HistoryListener;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+
+/**
+ * Client side implementation for UriFragmentUtility. Uses GWT's History object
+ * as an implementation.
+ * 
+ */
+public class VUriFragmentUtility extends Widget implements Paintable,
+        HistoryListener {
+
+    private String fragment;
+    private ApplicationConnection client;
+    private String paintableId;
+    private boolean immediate;
+
+    public VUriFragmentUtility() {
+        setElement(Document.get().createDivElement());
+        if (BrowserInfo.get().isIE6()) {
+            getElement().getStyle().setProperty("overflow", "hidden");
+            getElement().getStyle().setProperty("height", "0");
+        }
+        History.addHistoryListener(this);
+        History.fireCurrentHistoryState();
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+        String uidlFragment = uidl.getStringVariable("fragment");
+        immediate = uidl.getBooleanAttribute("immediate");
+        if (this.client == null) {
+            // initial paint has some special logic
+            this.client = client;
+            paintableId = uidl.getId();
+            if (!fragment.equals(uidlFragment)) {
+                // initial server side fragment (from link/bookmark/typed) does
+                // not equal the one on
+                // server, send initial fragment to server
+                History.fireCurrentHistoryState();
+            }
+        } else {
+            if (uidlFragment != null && !uidlFragment.equals(fragment)) {
+                fragment = uidlFragment;
+                // normal fragment change from server, add new history item
+                History.newItem(uidlFragment, false);
+            }
+        }
+    }
+
+    public void onHistoryChanged(String historyToken) {
+        fragment = historyToken;
+        if (client != null) {
+            client.updateVariable(paintableId, "fragment", fragment, immediate);
+        }
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayout.java b/src/com/vaadin/terminal/gwt/client/ui/VVerticalLayout.java
new file mode 100644 (file)
index 0000000..c6b944f
--- /dev/null
@@ -0,0 +1,11 @@
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+public class VVerticalLayout extends VOrderedLayout {\r
+\r
+    public static final String CLASSNAME = "i-verticallayout";\r
+\r
+    public VVerticalLayout() {\r
+        super(CLASSNAME, ORIENTATION_VERTICAL);\r
+    }\r
+\r
+}\r
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VView.java b/src/com/vaadin/terminal/gwt/client/ui/VView.java
new file mode 100644 (file)
index 0000000..a9aaf40
--- /dev/null
@@ -0,0 +1,575 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import com.google.gwt.dom.client.DivElement;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+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.WindowCloseListener;
+import com.google.gwt.user.client.WindowResizeListener;
+import com.google.gwt.user.client.ui.HasFocus;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.SimplePanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Focusable;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+/**
+ * 
+ */
+public class VView extends SimplePanel implements Container,
+        WindowResizeListener, WindowCloseListener {
+
+    private static final String CLASSNAME = "i-view";
+
+    private String theme;
+
+    private Paintable layout;
+
+    private final LinkedHashSet<VWindow> subWindows = new LinkedHashSet<VWindow>();
+
+    private String id;
+
+    private ShortcutActionHandler actionHandler;
+
+    /** stored width for IE resize optimization */
+    private int width;
+
+    /** stored height for IE resize optimization */
+    private int height;
+
+    private ApplicationConnection connection;
+
+    /**
+     * We are postponing resize process with IE. IE bugs with scrollbars in some
+     * situations, that causes false onWindowResized calls. With Timer we will
+     * give IE some time to decide if it really wants to keep current size
+     * (scrollbars).
+     */
+    private Timer resizeTimer;
+
+    private int scrollTop;
+
+    private int scrollLeft;
+
+    private boolean rendering;
+
+    private boolean scrollable;
+
+    private boolean immediate;
+
+    public VView(String elementId) {
+        super();
+        setStyleName(CLASSNAME);
+
+        DOM.sinkEvents(getElement(), Event.ONKEYDOWN | Event.ONSCROLL);
+
+        // iview is focused when created so element needs tabIndex
+        // 1 due 0 is at the end of natural tabbing order
+        DOM.setElementProperty(getElement(), "tabIndex", "1");
+
+        RootPanel root = RootPanel.get(elementId);
+        root.add(this);
+        root.removeStyleName("i-app-loading");
+
+        BrowserInfo browser = BrowserInfo.get();
+
+        // set focus to iview element by default to listen possible keyboard
+        // shortcuts
+        if (browser.isOpera() || browser.isSafari()
+                && browser.getWebkitVersion() < 526) {
+            // old webkits don't support focusing div elements
+            Element fElem = DOM.createInputCheck();
+            DOM.setStyleAttribute(fElem, "margin", "0");
+            DOM.setStyleAttribute(fElem, "padding", "0");
+            DOM.setStyleAttribute(fElem, "border", "0");
+            DOM.setStyleAttribute(fElem, "outline", "0");
+            DOM.setStyleAttribute(fElem, "width", "1px");
+            DOM.setStyleAttribute(fElem, "height", "1px");
+            DOM.setStyleAttribute(fElem, "position", "absolute");
+            DOM.setStyleAttribute(fElem, "opacity", "0.1");
+            DOM.appendChild(getElement(), fElem);
+            focus(fElem);
+        } else {
+            focus(getElement());
+        }
+
+    }
+
+    private static native void focus(Element el)
+    /*-{
+        try {
+            el.focus();
+        } catch (e) {
+        
+        }
+    }-*/;
+
+    public String getTheme() {
+        return theme;
+    }
+
+    /**
+     * Used to reload host page on theme changes.
+     */
+    private static native void reloadHostPage()
+    /*-{
+         $wnd.location.reload(); 
+     }-*/;
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        rendering = true;
+
+        id = uidl.getId();
+        boolean firstPaint = connection == null;
+        connection = client;
+
+        immediate = uidl.hasAttribute("immediate");
+
+        String newTheme = uidl.getStringAttribute("theme");
+        if (theme != null && !newTheme.equals(theme)) {
+            // Complete page refresh is needed due css can affect layout
+            // calculations etc
+            reloadHostPage();
+        } else {
+            theme = newTheme;
+        }
+        if (uidl.hasAttribute("style")) {
+            addStyleName(uidl.getStringAttribute("style"));
+        }
+
+        if (uidl.hasAttribute("name")) {
+            client.setWindowName(uidl.getStringAttribute("name"));
+        }
+
+        com.google.gwt.user.client.Window.setTitle(uidl
+                .getStringAttribute("caption"));
+
+        // Process children
+        int childIndex = 0;
+
+        // Open URL:s
+        boolean isClosed = false; // was this window closed?
+        while (childIndex < uidl.getChildCount()
+                && "open".equals(uidl.getChildUIDL(childIndex).getTag())) {
+            final UIDL open = uidl.getChildUIDL(childIndex);
+            final String url = open.getStringAttribute("src");
+            final String target = open.getStringAttribute("name");
+            if (target == null) {
+                // This window is closing. Send close event before
+                // going to the new url
+                isClosed = true;
+                onWindowClosed();
+                goTo(url);
+            } else {
+                String options;
+                if (open.hasAttribute("border")) {
+                    if (open.getStringAttribute("border").equals("minimal")) {
+                        options = "menubar=yes,location=no,status=no";
+                    } else {
+                        options = "menubar=no,location=no,status=no";
+                    }
+
+                } else {
+                    options = "resizable=yes,menubar=yes,toolbar=yes,directories=yes,location=yes,scrollbars=yes,status=yes";
+                }
+
+                if (open.hasAttribute("width")) {
+                    int w = open.getIntAttribute("width");
+                    options += ",width=" + w;
+                }
+                if (open.hasAttribute("height")) {
+                    int h = open.getIntAttribute("height");
+                    options += ",height=" + h;
+                }
+
+                Window.open(url, target, options);
+            }
+            childIndex++;
+        }
+        if (isClosed) {
+            // don't render the content
+            rendering = false;
+            return;
+        }
+
+        // Draw this application level window
+        UIDL childUidl = uidl.getChildUIDL(childIndex);
+        final Paintable lo = client.getPaintable(childUidl);
+
+        if (layout != null) {
+            if (layout != lo) {
+                // remove old
+                client.unregisterPaintable(layout);
+                // add new
+                setWidget((Widget) lo);
+                layout = lo;
+            }
+        } else {
+            setWidget((Widget) lo);
+            layout = lo;
+        }
+
+        layout.updateFromUIDL(childUidl, client);
+
+        // Update subwindows
+        final HashSet<VWindow> removedSubWindows = new HashSet<VWindow>(
+                subWindows);
+
+        // Open new windows
+        while ((childUidl = uidl.getChildUIDL(childIndex++)) != null) {
+            if ("window".equals(childUidl.getTag())) {
+                final Paintable w = client.getPaintable(childUidl);
+                if (subWindows.contains(w)) {
+                    removedSubWindows.remove(w);
+                } else {
+                    subWindows.add((VWindow) w);
+                }
+                w.updateFromUIDL(childUidl, client);
+            } else if ("actions".equals(childUidl.getTag())) {
+                if (actionHandler == null) {
+                    actionHandler = new ShortcutActionHandler(id, client);
+                }
+                actionHandler.updateActionMap(childUidl);
+            } else if (childUidl.getTag().equals("notifications")) {
+                for (final Iterator it = childUidl.getChildIterator(); it
+                        .hasNext();) {
+                    final UIDL notification = (UIDL) it.next();
+                    String html = "";
+                    if (notification.hasAttribute("icon")) {
+                        final String parsedUri = client
+                                .translateToolkitUri(notification
+                                        .getStringAttribute("icon"));
+                        html += "<IMG src=\"" + parsedUri + "\" />";
+                    }
+                    if (notification.hasAttribute("caption")) {
+                        html += "<H1>"
+                                + notification.getStringAttribute("caption")
+                                + "</H1>";
+                    }
+                    if (notification.hasAttribute("message")) {
+                        html += "<p>"
+                                + notification.getStringAttribute("message")
+                                + "</p>";
+                    }
+
+                    final String style = notification.hasAttribute("style") ? notification
+                            .getStringAttribute("style")
+                            : null;
+                    final int position = notification
+                            .getIntAttribute("position");
+                    final int delay = notification.getIntAttribute("delay");
+                    new VNotification(delay).show(html, position, style);
+                }
+            }
+        }
+
+        // Close old windows
+        for (final Iterator<VWindow> rem = removedSubWindows.iterator(); rem
+                .hasNext();) {
+            final VWindow w = rem.next();
+            client.unregisterPaintable(w);
+            subWindows.remove(w);
+            w.hide();
+        }
+
+        if (uidl.hasAttribute("focused")) {
+            final String focusPid = uidl.getStringAttribute("focused");
+            // set focused component when render phase is finished
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    final Paintable toBeFocused = connection
+                            .getPaintable(focusPid);
+
+                    /*
+                     * Two types of Widgets can be focused, either implementing
+                     * GWT HasFocus of a thinner Toolkit specific Focusable
+                     * interface.
+                     */
+                    if (toBeFocused instanceof HasFocus) {
+                        final HasFocus toBeFocusedWidget = (HasFocus) toBeFocused;
+                        toBeFocusedWidget.setFocus(true);
+                    } else if (toBeFocused instanceof Focusable) {
+                        ((Focusable) toBeFocused).focus();
+                    } else {
+                        ApplicationConnection.getConsole().log(
+                                "Could not focus component");
+                    }
+                }
+            });
+        }
+
+        // Add window listeners on first paint, to prevent premature
+        // variablechanges
+        if (firstPaint) {
+            Window.addWindowCloseListener(this);
+            Window.addWindowResizeListener(this);
+        }
+
+        onWindowResized(Window.getClientWidth(), Window.getClientHeight());
+
+        if (BrowserInfo.get().isSafari()) {
+            Util.runWebkitOverflowAutoFix(getElement());
+        }
+
+        // finally set scroll position from UIDL
+        if (uidl.hasVariable("scrollTop")) {
+            scrollable = true;
+            scrollTop = uidl.getIntVariable("scrollTop");
+            DOM.setElementPropertyInt(getElement(), "scrollTop", scrollTop);
+            scrollLeft = uidl.getIntVariable("scrollLeft");
+            DOM.setElementPropertyInt(getElement(), "scrollLeft", scrollLeft);
+        } else {
+            scrollable = false;
+        }
+
+        rendering = false;
+    }
+
+    @Override
+    public void onBrowserEvent(Event event) {
+        super.onBrowserEvent(event);
+        int type = DOM.eventGetType(event);
+        if (type == Event.ONKEYDOWN && actionHandler != null) {
+            actionHandler.handleKeyboardEvent(event);
+            return;
+        } else if (scrollable && type == Event.ONSCROLL) {
+            updateScrollPosition();
+        }
+    }
+
+    /**
+     * Updates scroll position from DOM and saves variables to server.
+     */
+    private void updateScrollPosition() {
+        int oldTop = scrollTop;
+        int oldLeft = scrollLeft;
+        scrollTop = DOM.getElementPropertyInt(getElement(), "scrollTop");
+        scrollLeft = DOM.getElementPropertyInt(getElement(), "scrollLeft");
+        if (connection != null && !rendering) {
+            if (oldTop != scrollTop) {
+                connection.updateVariable(id, "scrollTop", scrollTop, false);
+            }
+            if (oldLeft != scrollLeft) {
+                connection.updateVariable(id, "scrollLeft", scrollLeft, false);
+            }
+        }
+    }
+
+    public void onWindowResized(int width, int height) {
+        if (BrowserInfo.get().isIE()) {
+            /*
+             * IE will give us some false resized events due bugs with
+             * scrollbars. Postponing layout phase to see if size was really
+             * changed.
+             */
+            if (resizeTimer == null) {
+                resizeTimer = new Timer() {
+                    @Override
+                    public void run() {
+                        boolean changed = false;
+                        if (VView.this.width != getOffsetWidth()) {
+                            VView.this.width = getOffsetWidth();
+                            changed = true;
+                            ApplicationConnection.getConsole().log(
+                                    "window w" + VView.this.width);
+                        }
+                        if (VView.this.height != getOffsetHeight()) {
+                            VView.this.height = getOffsetHeight();
+                            changed = true;
+                            ApplicationConnection.getConsole().log(
+                                    "window h" + VView.this.height);
+                        }
+                        if (changed) {
+                            ApplicationConnection
+                                    .getConsole()
+                                    .log(
+                                            "Running layout functions due window resize");
+                            connection.runDescendentsLayout(VView.this);
+
+                            sendClientResized();
+                        }
+                    }
+                };
+            } else {
+                resizeTimer.cancel();
+            }
+            resizeTimer.schedule(200);
+        } else {
+            if (width == VView.this.width && height == VView.this.height) {
+                // No point in doing resize operations if window size has not
+                // changed
+                return;
+            }
+
+            VView.this.width = Window.getClientWidth();
+            VView.this.height = Window.getClientHeight();
+
+            ApplicationConnection.getConsole().log(
+                    "Running layout functions due window resize");
+
+            connection.runDescendentsLayout(this);
+            Util.runWebkitOverflowAutoFix(getElement());
+
+            sendClientResized();
+        }
+
+    }
+
+    /**
+     * Send new dimensions to the server.
+     */
+    private void sendClientResized() {
+        connection.updateVariable(id, "height", height, false);
+        connection.updateVariable(id, "width", width, immediate);
+    }
+
+    public native static void goTo(String url)
+    /*-{
+       $wnd.location = url;
+     }-*/;
+
+    public void onWindowClosed() {
+        // Change focus on this window in order to ensure that all state is
+        // collected from textfields
+        VTextField.flushChangesFromFocusedTextField();
+
+        // Send the closing state to server
+        connection.updateVariable(id, "close", true, false);
+        connection.sendPendingVariableChangesSync();
+    }
+
+    public String onWindowClosing() {
+        return null;
+    }
+
+    private final RenderSpace myRenderSpace = new RenderSpace() {
+        private int excessHeight = -1;
+        private int excessWidth = -1;
+
+        @Override
+        public int getHeight() {
+            return getElement().getOffsetHeight() - getExcessHeight();
+        }
+
+        private int getExcessHeight() {
+            if (excessHeight < 0) {
+                detectExcessSize();
+            }
+            return excessHeight;
+        }
+
+        private void detectExcessSize() {
+            // TODO define that iview cannot be themed and decorations should
+            // get to parent element, then get rid of this expensive and error
+            // prone function
+            final String overflow = getElement().getStyle().getProperty(
+                    "overflow");
+            getElement().getStyle().setProperty("overflow", "hidden");
+            if (BrowserInfo.get().isIE()
+                    && getElement().getPropertyInt("clientWidth") == 0) {
+                // can't detect possibly themed border/padding width in some
+                // situations (with some layout configurations), use empty div
+                // to measure width properly
+                DivElement div = Document.get().createDivElement();
+                div.setInnerHTML("&nbsp;");
+                div.getStyle().setProperty("overflow", "hidden");
+                div.getStyle().setProperty("height", "1px");
+                getElement().appendChild(div);
+                excessWidth = getElement().getOffsetWidth()
+                        - div.getOffsetWidth();
+                getElement().removeChild(div);
+            } else {
+                excessWidth = getElement().getOffsetWidth()
+                        - getElement().getPropertyInt("clientWidth");
+            }
+            excessHeight = getElement().getOffsetHeight()
+                    - getElement().getPropertyInt("clientHeight");
+
+            getElement().getStyle().setProperty("overflow", overflow);
+        }
+
+        @Override
+        public int getWidth() {
+            return getElement().getOffsetWidth() - getExcessWidth();
+        }
+
+        private int getExcessWidth() {
+            if (excessWidth < 0) {
+                detectExcessSize();
+            }
+            return excessWidth;
+        }
+
+        @Override
+        public int getScrollbarSize() {
+            return Util.getNativeScrollbarSize();
+        }
+    };
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        return myRenderSpace;
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        return (component != null && component == layout);
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        // TODO This is untested as no layouts require this
+        if (oldComponent != layout) {
+            return;
+        }
+
+        setWidget(newComponent);
+        layout = (Paintable) newComponent;
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        /*
+         * Can never propagate further and we do not want need to re-layout the
+         * layout which has caused this request.
+         */
+        return true;
+
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        // NOP Subwindows never draw caption for their first child (layout)
+    }
+
+    /**
+     * Return an iterator for current subwindows. This method is meant for
+     * testing purposes only.
+     * 
+     * @return
+     */
+    public ArrayList<VWindow> getSubWindowList() {
+        ArrayList<VWindow> windows = new ArrayList<VWindow>(subWindows.size());
+        for (VWindow widget : subWindows) {
+            windows.add(widget);
+        }
+        return windows;
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java
new file mode 100644 (file)
index 0000000..18a7b6a
--- /dev/null
@@ -0,0 +1,1001 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Vector;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Frame;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.google.gwt.user.client.ui.ScrollListener;
+import com.google.gwt.user.client.ui.ScrollPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Container;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.RenderSpace;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+
+/**
+ * "Sub window" component.
+ * 
+ * TODO update position / scroll position / size to client
+ * 
+ * @author IT Mill Ltd
+ */
+public class VWindow extends VToolkitOverlay implements Container,
+        ScrollListener {
+
+    private static final int MIN_HEIGHT = 100;
+
+    private static final int MIN_WIDTH = 150;
+
+    private static Vector<VWindow> windowOrder = new Vector<VWindow>();
+
+    public static final String CLASSNAME = "i-window";
+
+    /**
+     * Pixels used by inner borders and paddings horizontally (calculated only
+     * once)
+     */
+    private int borderWidth = -1;
+
+    /**
+     * Pixels used by inner borders and paddings vertically (calculated only
+     * once)
+     */
+    private int borderHeight = -1;
+
+    private static final int STACKING_OFFSET_PIXELS = 15;
+
+    public static final int Z_INDEX = 10000;
+
+    private Paintable layout;
+
+    private Element contents;
+
+    private Element header;
+
+    private Element footer;
+
+    private Element resizeBox;
+
+    private final ScrollPanel contentPanel = new ScrollPanel();
+
+    private boolean dragging;
+
+    private int startX;
+
+    private int startY;
+
+    private int origX;
+
+    private int origY;
+
+    private boolean resizing;
+
+    private int origW;
+
+    private int origH;
+
+    private Element closeBox;
+
+    protected ApplicationConnection client;
+
+    private String id;
+
+    ShortcutActionHandler shortcutHandler;
+
+    /** Last known positionx read from UIDL or updated to application connection */
+    private int uidlPositionX = -1;
+
+    /** Last known positiony read from UIDL or updated to application connection */
+    private int uidlPositionY = -1;
+
+    private boolean vaadinModality = false;
+
+    private boolean resizable = true;
+
+    private Element modalityCurtain;
+    private Element draggingCurtain;
+
+    private Element headerText;
+
+    private boolean readonly;
+
+    boolean dynamicWidth = false;
+    boolean dynamicHeight = false;
+    boolean layoutRelativeWidth = false;
+    boolean layoutRelativeHeight = false;
+
+    // If centered (via UIDL), the window should stay in the centered -mode
+    // until a position is received from the server, or the user moves or
+    // resizes the window.
+    boolean centered = false;
+
+    private RenderSpace renderSpace = new RenderSpace(MIN_WIDTH, MIN_HEIGHT,
+            true);
+
+    private String width;
+
+    private String height;
+
+    private boolean immediate;
+
+    public VWindow() {
+        super(false, false, true); // no autohide, not modal, shadow
+        // Different style of shadow for windows
+        setShadowStyle("window");
+
+        final int order = windowOrder.size();
+        setWindowOrder(order);
+        windowOrder.add(this);
+        constructDOM();
+        setPopupPosition(order * STACKING_OFFSET_PIXELS, order
+                * STACKING_OFFSET_PIXELS);
+        contentPanel.addScrollListener(this);
+    }
+
+    private void bringToFront() {
+        int curIndex = windowOrder.indexOf(this);
+        if (curIndex + 1 < windowOrder.size()) {
+            windowOrder.remove(this);
+            windowOrder.add(this);
+            for (; curIndex < windowOrder.size(); curIndex++) {
+                windowOrder.get(curIndex).setWindowOrder(curIndex);
+            }
+        }
+    }
+
+    /**
+     * Returns true if window is the topmost window
+     * 
+     * @return
+     */
+    private boolean isActive() {
+        return windowOrder.lastElement().equals(this);
+    }
+
+    public void setWindowOrder(int order) {
+        setZIndex(order + Z_INDEX);
+    }
+
+    @Override
+    protected void setZIndex(int zIndex) {
+        super.setZIndex(zIndex);
+        if (vaadinModality) {
+            DOM.setStyleAttribute(modalityCurtain, "zIndex", "" + zIndex);
+        }
+    }
+
+    protected void constructDOM() {
+        setStyleName(CLASSNAME);
+
+        header = DOM.createDiv();
+        DOM.setElementProperty(header, "className", CLASSNAME + "-outerheader");
+        headerText = DOM.createDiv();
+        DOM.setElementProperty(headerText, "className", CLASSNAME + "-header");
+        contents = DOM.createDiv();
+        DOM.setElementProperty(contents, "className", CLASSNAME + "-contents");
+        footer = DOM.createDiv();
+        DOM.setElementProperty(footer, "className", CLASSNAME + "-footer");
+        resizeBox = DOM.createDiv();
+        DOM
+                .setElementProperty(resizeBox, "className", CLASSNAME
+                        + "-resizebox");
+        closeBox = DOM.createDiv();
+        DOM.setElementProperty(closeBox, "className", CLASSNAME + "-closebox");
+        DOM.appendChild(footer, resizeBox);
+
+        DOM.sinkEvents(getElement(), Event.ONLOSECAPTURE);
+        DOM.sinkEvents(closeBox, Event.ONCLICK);
+        DOM.sinkEvents(contents, Event.ONCLICK);
+
+        final Element wrapper = DOM.createDiv();
+        DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap");
+
+        final Element wrapper2 = DOM.createDiv();
+        DOM.setElementProperty(wrapper2, "className", CLASSNAME + "-wrap2");
+
+        DOM.sinkEvents(wrapper, Event.ONKEYDOWN);
+
+        DOM.appendChild(wrapper2, closeBox);
+        DOM.appendChild(wrapper2, header);
+        DOM.appendChild(header, headerText);
+        DOM.appendChild(wrapper2, contents);
+        DOM.appendChild(wrapper2, footer);
+        DOM.appendChild(wrapper, wrapper2);
+        DOM.appendChild(super.getContainerElement(), wrapper);
+
+        sinkEvents(Event.MOUSEEVENTS);
+
+        setWidget(contentPanel);
+
+    }
+
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+        id = uidl.getId();
+        this.client = client;
+
+        // Workaround needed for Testing Tools (GWT generates window DOM
+        // slightly different in different browsers).
+        DOM.setElementProperty(closeBox, "id", id + "_window_close");
+
+        if (uidl.hasAttribute("invisible")) {
+            hide();
+            return;
+        }
+
+        if (!uidl.hasAttribute("cached")) {
+            if (uidl.getBooleanAttribute("modal") != vaadinModality) {
+                setVaadinModality(!vaadinModality);
+            }
+            if (!isAttached()) {
+                show();
+            }
+        }
+
+        if (client.updateComponent(this, uidl, false)) {
+            return;
+        }
+
+        immediate = uidl.hasAttribute("immediate");
+
+        if (uidl.getBooleanAttribute("resizable") != resizable) {
+            setResizable(!resizable);
+        }
+
+        if (isReadOnly() != uidl.getBooleanAttribute("readonly")) {
+            setReadOnly(!isReadOnly());
+        }
+
+        // Initialize the position form UIDL
+        try {
+            final int positionx = uidl.getIntVariable("positionx");
+            final int positiony = uidl.getIntVariable("positiony");
+            if (positionx >= 0 && positiony >= 0) {
+                setPopupPosition(positionx, positiony);
+            }
+        } catch (final IllegalArgumentException e) {
+            // Silently ignored as positionx and positiony are not required
+            // parameters
+        }
+
+        if (uidl.hasAttribute("caption")) {
+            setCaption(uidl.getStringAttribute("caption"), uidl
+                    .getStringAttribute("icon"));
+        }
+
+        boolean showingUrl = false;
+        int childIndex = 0;
+        UIDL childUidl = uidl.getChildUIDL(childIndex++);
+        while ("open".equals(childUidl.getTag())) {
+            // TODO multiple opens with the same target will in practice just
+            // open the last one - should we fix that somehow?
+            final String parsedUri = client.translateToolkitUri(childUidl
+                    .getStringAttribute("src"));
+            if (!childUidl.hasAttribute("name")) {
+                final Frame frame = new Frame();
+                DOM.setStyleAttribute(frame.getElement(), "width", "100%");
+                DOM.setStyleAttribute(frame.getElement(), "height", "100%");
+                DOM.setStyleAttribute(frame.getElement(), "border", "0px");
+                frame.setUrl(parsedUri);
+                contentPanel.setWidget(frame);
+                showingUrl = true;
+            } else {
+                final String target = childUidl.getStringAttribute("name");
+                Window.open(parsedUri, target, "");
+            }
+            childUidl = uidl.getChildUIDL(childIndex++);
+        }
+
+        final Paintable lo = client.getPaintable(childUidl);
+        if (layout != null) {
+            if (layout != lo) {
+                // remove old
+                client.unregisterPaintable(layout);
+                contentPanel.remove((Widget) layout);
+                // add new
+                if (!showingUrl) {
+                    contentPanel.setWidget((Widget) lo);
+                }
+                layout = lo;
+            }
+        } else if (!showingUrl) {
+            contentPanel.setWidget((Widget) lo);
+            layout = lo;
+        }
+
+        dynamicWidth = !uidl.hasAttribute("width");
+        dynamicHeight = !uidl.hasAttribute("height");
+
+        layoutRelativeWidth = uidl.hasAttribute("layoutRelativeWidth");
+        layoutRelativeHeight = uidl.hasAttribute("layoutRelativeHeight");
+
+        if (dynamicWidth && layoutRelativeWidth) {
+            /*
+             * Relative layout width, fix window width before rendering (width
+             * according to caption)
+             */
+            setNaturalWidth();
+        }
+
+        layout.updateFromUIDL(childUidl, client);
+        if (!dynamicHeight && layoutRelativeWidth) {
+            /*
+             * Relative layout width, and fixed height. Must update the size to
+             * be able to take scrollbars into account (layout gets narrower
+             * space if it is higher than the window) -> only vertical scrollbar
+             */
+            client.runDescendentsLayout(this);
+        }
+
+        /*
+         * No explicit width is set and the layout does not have relative width
+         * so fix the size according to the layout.
+         */
+        if (dynamicWidth && !layoutRelativeWidth) {
+            setNaturalWidth();
+        }
+
+        if (dynamicHeight && layoutRelativeHeight) {
+            // Prevent resizing until height has been fixed
+            resizable = false;
+        }
+
+        // we may have actions and notifications
+        if (uidl.getChildCount() > 1) {
+            final int cnt = uidl.getChildCount();
+            for (int i = 1; i < cnt; i++) {
+                childUidl = uidl.getChildUIDL(i);
+                if (childUidl.getTag().equals("actions")) {
+                    if (shortcutHandler == null) {
+                        shortcutHandler = new ShortcutActionHandler(id, client);
+                    }
+                    shortcutHandler.updateActionMap(childUidl);
+                } else if (childUidl.getTag().equals("notifications")) {
+                    // TODO needed? move ->
+                    for (final Iterator it = childUidl.getChildIterator(); it
+                            .hasNext();) {
+                        final UIDL notification = (UIDL) it.next();
+                        String html = "";
+                        if (notification.hasAttribute("icon")) {
+                            final String parsedUri = client
+                                    .translateToolkitUri(notification
+                                            .getStringAttribute("icon"));
+                            html += "<img src=\"" + parsedUri + "\" />";
+                        }
+                        if (notification.hasAttribute("caption")) {
+                            html += "<h1>"
+                                    + notification
+                                            .getStringAttribute("caption")
+                                    + "</h1>";
+                        }
+                        if (notification.hasAttribute("message")) {
+                            html += "<p>"
+                                    + notification
+                                            .getStringAttribute("message")
+                                    + "</p>";
+                        }
+
+                        final String style = notification.hasAttribute("style") ? notification
+                                .getStringAttribute("style")
+                                : null;
+                        final int position = notification
+                                .getIntAttribute("position");
+                        final int delay = notification.getIntAttribute("delay");
+                        new VNotification(delay).show(html, position, style);
+                    }
+                }
+            }
+
+        }
+
+        // setting scrollposition must happen after children is rendered
+        contentPanel.setScrollPosition(uidl.getIntVariable("scrollTop"));
+        contentPanel.setHorizontalScrollPosition(uidl
+                .getIntVariable("scrollLeft"));
+
+        // Center this window on screen if requested
+        // This has to be here because we might not know the content size before
+        // everything is painted into the window
+        if (uidl.getBooleanAttribute("center")) {
+            // mark as centered - this is unset on move/resize
+            centered = true;
+            center();
+        } else {
+            // don't try to center the window anymore
+            centered = false;
+        }
+
+        updateShadowSizeAndPosition();
+
+        // ensure window is not larger than browser window
+        if (getOffsetWidth() > Window.getClientWidth()) {
+            setWidth(Window.getClientWidth() + "px");
+        }
+        if (getOffsetHeight() > Window.getClientHeight()) {
+            setHeight(Window.getClientHeight() + "px");
+        }
+
+        if (dynamicHeight && layoutRelativeHeight) {
+            /*
+             * Window height is undefined, layout is 100% high so the layout
+             * should define the initial window height but on resize the layout
+             * should be as high as the window. We fix the height to deal with
+             * this.
+             */
+
+            int h = contents.getOffsetHeight() + getExtraHeight();
+            int w = contents.getOffsetWidth();
+
+            client.updateVariable(id, "height", h, false);
+            client.updateVariable(id, "width", w, true);
+        }
+
+    }
+
+    private void setNaturalWidth() {
+        /*
+         * For some reason IE6 has title DIV set to width 100% which messes this
+         * up. Also IE6 has a 0 wide element so we use the container element.
+         */
+        int naturalWidth;
+        if (BrowserInfo.get().isIE6()) {
+            String headerW = headerText.getStyle().getProperty("width");
+            headerText.getStyle().setProperty("width", "auto");
+            naturalWidth = getElement().getOffsetWidth();
+            headerText.getStyle().setProperty("width", headerW);
+        } else {
+            // use max(layout width, window width)
+            // i.e layout content width or caption width
+            int lowidth = contentPanel.getElement().getScrollWidth()
+                    + borderWidth; // layout does not know about border
+            int elwidth = getElement().getOffsetWidth();
+            naturalWidth = (lowidth > elwidth ? lowidth : elwidth);
+        }
+
+        setWidth(naturalWidth + "px");
+    }
+
+    private void setReadOnly(boolean readonly) {
+        this.readonly = readonly;
+        if (readonly) {
+            DOM.setStyleAttribute(closeBox, "display", "none");
+        } else {
+            DOM.setStyleAttribute(closeBox, "display", "");
+        }
+    }
+
+    private boolean isReadOnly() {
+        return readonly;
+    }
+
+    @Override
+    public void show() {
+        if (vaadinModality) {
+            showModalityCurtain();
+        }
+        super.show();
+
+        setFF2CaretFixEnabled(true);
+        fixFF3OverflowBug();
+    }
+
+    /** Disable overflow auto with FF3 to fix #1837. */
+    private void fixFF3OverflowBug() {
+        if (BrowserInfo.get().isFF3()) {
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    DOM.setStyleAttribute(getElement(), "overflow", "");
+                }
+            });
+        }
+    }
+
+    /**
+     * Fix "missing cursor" browser bug workaround for FF2 in Windows and Linux.
+     * 
+     * Calling this method has no effect on other browsers than the ones based
+     * on Gecko 1.8
+     * 
+     * @param enable
+     */
+    private void setFF2CaretFixEnabled(boolean enable) {
+        if (BrowserInfo.get().isFF2()) {
+            if (enable) {
+                DeferredCommand.addCommand(new Command() {
+                    public void execute() {
+                        DOM.setStyleAttribute(getElement(), "overflow", "auto");
+                    }
+                });
+            } else {
+                DOM.setStyleAttribute(getElement(), "overflow", "");
+            }
+        }
+    }
+
+    @Override
+    public void hide() {
+        if (vaadinModality) {
+            hideModalityCurtain();
+        }
+        super.hide();
+    }
+
+    private void setVaadinModality(boolean modality) {
+        vaadinModality = modality;
+        if (vaadinModality) {
+            modalityCurtain = DOM.createDiv();
+            DOM.setElementProperty(modalityCurtain, "className", CLASSNAME
+                    + "-modalitycurtain");
+            if (isAttached()) {
+                showModalityCurtain();
+                bringToFront();
+            } else {
+                DeferredCommand.addCommand(new Command() {
+                    public void execute() {
+                        // vaadinModality window must on top of others
+                        bringToFront();
+                    }
+                });
+            }
+        } else {
+            if (modalityCurtain != null) {
+                if (isAttached()) {
+                    hideModalityCurtain();
+                }
+                modalityCurtain = null;
+            }
+        }
+    }
+
+    private void showModalityCurtain() {
+        if (BrowserInfo.get().isFF2()) {
+            DOM.setStyleAttribute(modalityCurtain, "height", DOM
+                    .getElementPropertyInt(RootPanel.getBodyElement(),
+                            "offsetHeight")
+                    + "px");
+            DOM.setStyleAttribute(modalityCurtain, "position", "absolute");
+        }
+        DOM.setStyleAttribute(modalityCurtain, "zIndex", ""
+                + (windowOrder.indexOf(this) + Z_INDEX));
+        DOM.appendChild(RootPanel.getBodyElement(), modalityCurtain);
+    }
+
+    private void hideModalityCurtain() {
+        DOM.removeChild(RootPanel.getBodyElement(), modalityCurtain);
+    }
+
+    /*
+     * 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.
+     */
+    private void showDraggingCurtain(boolean show) {
+        if (show && draggingCurtain == null) {
+
+            setFF2CaretFixEnabled(false); // makes FF2 slow
+
+            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", ""
+                    + VToolkitOverlay.Z_INDEX);
+
+            DOM.appendChild(RootPanel.getBodyElement(), draggingCurtain);
+        } else if (!show && draggingCurtain != null) {
+
+            setFF2CaretFixEnabled(true); // makes FF2 slow
+
+            DOM.removeChild(RootPanel.getBodyElement(), draggingCurtain);
+            draggingCurtain = null;
+        }
+
+    }
+
+    private void setResizable(boolean resizability) {
+        resizable = resizability;
+        if (resizability) {
+            DOM.setElementProperty(resizeBox, "className", CLASSNAME
+                    + "-resizebox");
+        } else {
+            DOM.setElementProperty(resizeBox, "className", CLASSNAME
+                    + "-resizebox " + CLASSNAME + "-resizebox-disabled");
+        }
+    }
+
+    @Override
+    public void setPopupPosition(int left, int top) {
+        super.setPopupPosition(left, top);
+        if (left != uidlPositionX && client != null) {
+            client.updateVariable(id, "positionx", left, false);
+            uidlPositionX = left;
+        }
+        if (top != uidlPositionY && client != null) {
+            client.updateVariable(id, "positiony", top, false);
+            uidlPositionY = top;
+        }
+    }
+
+    public void setCaption(String c) {
+        setCaption(c, null);
+    }
+
+    public void setCaption(String c, String icon) {
+        String html = Util.escapeHTML(c);
+        if (icon != null) {
+            icon = client.translateToolkitUri(icon);
+            html = "<img src=\"" + icon + "\" class=\"i-icon\" />" + html;
+        }
+        DOM.setInnerHTML(headerText, html);
+    }
+
+    @Override
+    protected Element getContainerElement() {
+        // in GWT 1.5 this method is used in PopupPanel constructor
+        if (contents == null) {
+            return super.getContainerElement();
+        }
+        return contents;
+    }
+
+    @Override
+    public void onBrowserEvent(final Event event) {
+        if (event != null) {
+            final int type = event.getTypeInt();
+
+            if (type == Event.ONKEYDOWN && shortcutHandler != null) {
+                shortcutHandler.handleKeyboardEvent(event);
+                return;
+            }
+
+            final Element target = DOM.eventGetTarget(event);
+
+            // Handle window caption tooltips
+            if (client != null && DOM.isOrHasChild(header, target)) {
+                client.handleTooltipEvent(event, this);
+            }
+
+            if (resizing || resizeBox == target) {
+                onResizeEvent(event);
+                event.cancelBubble(true);
+            } else if (target == closeBox) {
+                if (type == Event.ONCLICK) {
+                    onCloseClick();
+                    event.cancelBubble(true);
+                }
+            } else if (dragging || !DOM.isOrHasChild(contents, target)) {
+                onDragEvent(event);
+                event.cancelBubble(true);
+            } else if (type == Event.ONCLICK) {
+                // clicked inside window, ensure to be on top
+                if (!isActive()) {
+                    bringToFront();
+                }
+            }
+        }
+    }
+
+    private void onCloseClick() {
+        client.updateVariable(id, "close", true, true);
+    }
+
+    private void onResizeEvent(Event event) {
+        if (resizable) {
+            switch (event.getTypeInt()) {
+            case Event.ONMOUSEDOWN:
+                if (!isActive()) {
+                    bringToFront();
+                }
+                showDraggingCurtain(true);
+                if (BrowserInfo.get().isIE()) {
+                    DOM.setStyleAttribute(resizeBox, "visibility", "hidden");
+                }
+                resizing = true;
+                startX = event.getScreenX();
+                startY = event.getScreenY();
+                origW = getElement().getOffsetWidth();
+                origH = getElement().getOffsetHeight();
+                DOM.setCapture(getElement());
+                event.preventDefault();
+                break;
+            case Event.ONMOUSEUP:
+                showDraggingCurtain(false);
+                if (BrowserInfo.get().isIE()) {
+                    DOM.setStyleAttribute(resizeBox, "visibility", "");
+                }
+                resizing = false;
+                DOM.releaseCapture(getElement());
+                setSize(event, true);
+                break;
+            case Event.ONLOSECAPTURE:
+                showDraggingCurtain(false);
+                if (BrowserInfo.get().isIE()) {
+                    DOM.setStyleAttribute(resizeBox, "visibility", "");
+                }
+                resizing = false;
+            case Event.ONMOUSEMOVE:
+                if (resizing) {
+                    centered = false;
+                    setSize(event, false);
+                    event.preventDefault();
+                }
+                break;
+            default:
+                event.preventDefault();
+                break;
+            }
+        }
+    }
+
+    private void setSize(Event event, boolean updateVariables) {
+        int w = event.getScreenX() - startX + origW;
+        if (w < MIN_WIDTH + borderWidth) {
+            w = MIN_WIDTH + borderWidth;
+        }
+
+        int h = event.getScreenY() - startY + origH;
+        if (h < MIN_HEIGHT + getExtraHeight()) {
+            h = MIN_HEIGHT + getExtraHeight();
+        }
+
+        setWidth(w + "px");
+        setHeight(h + "px");
+
+        if (updateVariables) {
+            // sending width back always as pixels, no need for unit
+            client.updateVariable(id, "width", w, false);
+            client.updateVariable(id, "height", h, immediate);
+        }
+
+        // Update child widget dimensions
+        if (client != null) {
+            client.handleComponentRelativeSize((Widget) layout);
+            client.runDescendentsLayout((HasWidgets) layout);
+        }
+
+        Util.runWebkitOverflowAutoFix(contentPanel.getElement());
+    }
+
+    @Override
+    /*
+     * Width is set to the out-most element (i-window).
+     * 
+     * This function should never be called with percentage values (it will
+     * throw an exception)
+     */
+    public void setWidth(String width) {
+        this.width = width;
+        if (!isAttached()) {
+            return;
+        }
+        if (width != null && !"".equals(width)) {
+            int pixelWidth;
+            // Convert non-pixel values to pixels
+            if (width.indexOf("px") < 0) {
+                DOM.setStyleAttribute(getElement(), "width", width);
+                pixelWidth = getElement().getOffsetWidth();
+                width = pixelWidth + "px";
+            }
+            if (BrowserInfo.get().isIE6()) {
+                getElement().getStyle().setProperty("overflow", "hidden");
+            }
+            getElement().getStyle().setProperty("width", width);
+
+            pixelWidth = getElement().getOffsetWidth() - borderWidth;
+            if (pixelWidth < MIN_WIDTH) {
+                pixelWidth = MIN_WIDTH;
+                int rootWidth = pixelWidth + borderWidth;
+                DOM.setStyleAttribute(getElement(), "width", rootWidth + "px");
+            }
+
+            renderSpace.setWidth(pixelWidth);
+
+            // IE6 needs the actual inner content width on the content element,
+            // otherwise it won't wrap the content properly (no scrollbars
+            // appear, content flows out of window)
+            if (BrowserInfo.get().isIE6()) {
+                DOM.setStyleAttribute(contentPanel.getElement(), "width",
+                        pixelWidth + "px");
+            }
+            updateShadowSizeAndPosition();
+        }
+    }
+
+    @Override
+    /*
+     * Height is set to the out-most element (i-window).
+     * 
+     * This function should never be called with percentage values (it will
+     * throw an exception)
+     */
+    public void setHeight(String height) {
+        this.height = height;
+        if (!isAttached()) {
+            return;
+        }
+        if (height != null && !"".equals(height)) {
+            DOM.setStyleAttribute(getElement(), "height", height);
+            int pixels = getElement().getOffsetHeight() - getExtraHeight();
+            if (pixels < MIN_HEIGHT) {
+                pixels = MIN_HEIGHT;
+                int rootHeight = pixels + getExtraHeight();
+                DOM.setStyleAttribute(getElement(), "height", (rootHeight)
+                        + "px");
+
+            }
+            renderSpace.setHeight(pixels);
+            height = pixels + "px";
+            contentPanel.getElement().getStyle().setProperty("height", height);
+            updateShadowSizeAndPosition();
+
+        }
+    }
+
+    private int extraH = 0;
+
+    private int getExtraHeight() {
+        extraH = header.getOffsetHeight() + footer.getOffsetHeight();
+        return extraH;
+    }
+
+    private void onDragEvent(Event event) {
+        switch (DOM.eventGetType(event)) {
+        case Event.ONMOUSEDOWN:
+            if (!isActive()) {
+                bringToFront();
+            }
+            showDraggingCurtain(true);
+            dragging = true;
+            startX = DOM.eventGetScreenX(event);
+            startY = DOM.eventGetScreenY(event);
+            origX = DOM.getAbsoluteLeft(getElement());
+            origY = DOM.getAbsoluteTop(getElement());
+            DOM.setCapture(getElement());
+            DOM.eventPreventDefault(event);
+            break;
+        case Event.ONMOUSEUP:
+            dragging = false;
+            showDraggingCurtain(false);
+            DOM.releaseCapture(getElement());
+            break;
+        case Event.ONLOSECAPTURE:
+            showDraggingCurtain(false);
+            dragging = false;
+            break;
+        case Event.ONMOUSEMOVE:
+            if (dragging) {
+                centered = false;
+                final int x = DOM.eventGetScreenX(event) - startX + origX;
+                final int y = DOM.eventGetScreenY(event) - startY + origY;
+                setPopupPosition(x, y);
+                DOM.eventPreventDefault(event);
+            }
+            break;
+        default:
+            break;
+        }
+    }
+
+    @Override
+    public boolean onEventPreview(Event event) {
+        if (dragging) {
+            onDragEvent(event);
+            return false;
+        } else if (resizing) {
+            onResizeEvent(event);
+            return false;
+        } else if (vaadinModality) {
+            // return false when modal and outside window
+            final Element target = event.getTarget().cast();
+            if (!DOM.isOrHasChild(getElement(), target)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public void onScroll(Widget widget, int scrollLeft, int scrollTop) {
+        client.updateVariable(id, "scrollTop", scrollTop, false);
+        client.updateVariable(id, "scrollLeft", scrollLeft, false);
+    }
+
+    @Override
+    public void addStyleDependentName(String styleSuffix) {
+        // VWindow's getStyleElement() does not return the same element as
+        // getElement(), so we need to override this.
+        setStyleName(getElement(), getStylePrimaryName() + "-" + styleSuffix,
+                true);
+    }
+
+    @Override
+    protected void onAttach() {
+        super.onAttach();
+
+        // Calculate space required by window borders, so we can accurately
+        // calculate space for content
+
+        // IE (IE6 especially) requires some magic tricks to pull the border
+        // size correctly (remember that we want to accomodate for paddings as
+        // well)
+        if (BrowserInfo.get().isIE()) {
+            DOM.setStyleAttribute(contents, "width", "7000px");
+            DOM.setStyleAttribute(contentPanel.getElement(), "width", "7000px");
+            int contentWidth = DOM.getElementPropertyInt(contentPanel
+                    .getElement(), "offsetWidth");
+            contentWidth = DOM.getElementPropertyInt(contentPanel.getElement(),
+                    "offsetWidth");
+            final int windowWidth = DOM.getElementPropertyInt(getElement(),
+                    "offsetWidth");
+            DOM.setStyleAttribute(contentPanel.getElement(), "width", "");
+            DOM.setStyleAttribute(contents, "width", "");
+
+            borderWidth = windowWidth - contentWidth;
+        }
+
+        // Standards based browsers get away with it a little easier :)
+        else {
+            final int contentWidth = DOM.getElementPropertyInt(contentPanel
+                    .getElement(), "offsetWidth");
+            final int windowWidth = DOM.getElementPropertyInt(getElement(),
+                    "offsetWidth");
+            borderWidth = windowWidth - contentWidth;
+        }
+
+        setWidth(width);
+        setHeight(height);
+
+    }
+
+    public RenderSpace getAllocatedSpace(Widget child) {
+        if (child == layout) {
+            return renderSpace;
+        } else {
+            // Exception ??
+            return null;
+        }
+    }
+
+    public boolean hasChildComponent(Widget component) {
+        if (component == layout) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
+        contentPanel.setWidget(newComponent);
+    }
+
+    public boolean requestLayout(Set<Paintable> child) {
+        if (dynamicWidth && !layoutRelativeWidth) {
+            setNaturalWidth();
+        }
+        if (centered) {
+            center();
+        }
+        updateShadowSizeAndPosition();
+        return true;
+    }
+
+    public void updateCaption(Paintable component, UIDL uidl) {
+        // NOP, window has own caption, layout captio not rendered
+    }
+
+}
index 5c2c2f020493795218ff876caa43d2b36062f9e8..2da551dcdd00568b4205e77c223fdd5b46989996 100644 (file)
@@ -13,7 +13,7 @@ import com.vaadin.terminal.gwt.client.BrowserInfo;
 import com.vaadin.terminal.gwt.client.Container;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.ui.IMarginInfo;
+import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
 
 public abstract class CellBasedLayout extends ComplexPanel implements Container {
 
@@ -27,7 +27,7 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
     public static final int ORIENTATION_HORIZONTAL = 1;
 
     protected Margins activeMargins = new Margins(0, 0, 0, 0);
-    protected IMarginInfo activeMarginsInfo = new IMarginInfo(-1);
+    protected VMarginInfo activeMarginsInfo = new VMarginInfo(-1);
 
     protected boolean spacingEnabled = false;
     protected final Spacing spacingFromCSS = new Spacing(12, 12);
@@ -214,7 +214,7 @@ public abstract class CellBasedLayout extends ComplexPanel implements Container
     private void updateMarginAndSpacingInfo(UIDL uidl) {
         int bitMask = uidl.getIntAttribute("margins");
         if (activeMarginsInfo.getBitMask() != bitMask) {
-            activeMarginsInfo = new IMarginInfo(bitMask);
+            activeMarginsInfo = new VMarginInfo(bitMask);
             marginsNeedsRecalculation = true;
         }
         boolean spacing = uidl.getBooleanAttribute("spacing");
index 158138359d104c344834e5f7e04d54e022898506..299bbd6918d37fbc559ba0d806c8fcc28c4e451a 100644 (file)
@@ -12,7 +12,7 @@ import com.google.gwt.user.client.ui.Panel;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
 import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.ICaption;
+import com.vaadin.terminal.gwt.client.VCaption;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
 import com.vaadin.terminal.gwt.client.Util;
@@ -62,7 +62,7 @@ public class ChildComponentContainer extends Panel {
     private int alignmentTopOffset = 0;
 
     // private Margins alignmentOffset = new Margins(0, 0, 0, 0);
-    private ICaption caption = null;
+    private VCaption caption = null;
     private DivElement containerDIV;
     private DivElement widgetDIV;
     private Widget widget;
@@ -413,13 +413,13 @@ public class ChildComponentContainer extends Panel {
     }
 
     public void updateCaption(UIDL uidl, ApplicationConnection client) {
-        if (ICaption.isNeeded(uidl)) {
+        if (VCaption.isNeeded(uidl)) {
             // We need a caption
 
-            ICaption newCaption = caption;
+            VCaption newCaption = caption;
 
             if (newCaption == null) {
-                newCaption = new ICaption((Paintable) widget, client);
+                newCaption = new VCaption((Paintable) widget, client);
                 // Set initial height to avoid Safari flicker
                 newCaption.setHeight("18px");
                 // newCaption.setHeight(newCaption.getHeight()); // This might
@@ -462,7 +462,7 @@ public class ChildComponentContainer extends Panel {
 
     }
 
-    private void setCaption(ICaption newCaption) {
+    private void setCaption(VCaption newCaption) {
         // Validate
         // if (newCaption == caption) {
         // return;
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextArea.java
deleted file mode 100644 (file)
index b6a3c85..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/* 
-@ITMillApache2LicenseForJavaFiles@
- */
-
-package com.vaadin.terminal.gwt.client.ui.richtextarea;
-
-import com.google.gwt.user.client.Command;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.DeferredCommand;
-import com.google.gwt.user.client.Element;
-import com.google.gwt.user.client.ui.ChangeListener;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.FocusListener;
-import com.google.gwt.user.client.ui.HTML;
-import com.google.gwt.user.client.ui.KeyboardListener;
-import com.google.gwt.user.client.ui.RichTextArea;
-import com.google.gwt.user.client.ui.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Paintable;
-import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.ui.Field;
-
-/**
- * This class implements a basic client side rich text editor component.
- * 
- * @author IT Mill Ltd.
- * 
- */
-public class IRichTextArea extends Composite implements Paintable, Field,
-        ChangeListener, FocusListener, KeyboardListener {
-
-    /**
-     * The input node CSS classname.
-     */
-    public static final String CLASSNAME = "i-richtextarea";
-
-    protected String id;
-
-    protected ApplicationConnection client;
-
-    private boolean immediate = false;
-
-    private RichTextArea rta = new RichTextArea();
-
-    private IRichTextToolbar formatter = new IRichTextToolbar(rta);
-
-    private HTML html = new HTML();
-
-    private final FlowPanel fp = new FlowPanel();
-
-    private boolean enabled = true;
-
-    private int extraHorizontalPixels = -1;
-    private int extraVerticalPixels = -1;
-
-    private int maxLength = -1;
-
-    private int toolbarNaturalWidth = 500;
-
-    public IRichTextArea() {
-        fp.add(formatter);
-
-        rta.setWidth("100%");
-        rta.addFocusListener(this);
-
-        fp.add(rta);
-
-        initWidget(fp);
-        setStyleName(CLASSNAME);
-
-    }
-
-    public void setEnabled(boolean enabled) {
-        if (this.enabled != enabled) {
-            rta.setEnabled(enabled);
-            if (enabled) {
-                fp.remove(html);
-                fp.add(rta);
-            } else {
-                html.setHTML(rta.getHTML());
-                fp.remove(rta);
-                fp.add(html);
-            }
-
-            this.enabled = enabled;
-        }
-    }
-
-    public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
-        this.client = client;
-        id = uidl.getId();
-
-        if (uidl.hasVariable("text")) {
-            if (BrowserInfo.get().isIE()) {
-                // rta is rather buggy in IE (as pretty much everything is)
-                // it needs some "shaking" not to fall into uneditable state
-                // see #2374
-                rta.getBasicFormatter().toggleBold();
-                rta.getBasicFormatter().toggleBold();
-            }
-            rta.setHTML(uidl.getStringVariable("text"));
-
-        }
-        setEnabled(!uidl.getBooleanAttribute("disabled"));
-
-        if (client.updateComponent(this, uidl, true)) {
-            return;
-        }
-
-        immediate = uidl.getBooleanAttribute("immediate");
-        int newMaxLength = uidl.hasAttribute("maxLength") ? uidl
-                .getIntAttribute("maxLength") : -1;
-        if (newMaxLength >= 0) {
-            if (maxLength == -1) {
-                rta.addKeyboardListener(this);
-            }
-            maxLength = newMaxLength;
-        } else if (maxLength != -1) {
-            getElement().setAttribute("maxlength", "");
-            maxLength = -1;
-            rta.removeKeyboardListener(this);
-        }
-    }
-
-    public void onChange(Widget sender) {
-        if (client != null && id != null) {
-            client.updateVariable(id, "text", rta.getText(), immediate);
-        }
-    }
-
-    public void onFocus(Widget sender) {
-
-    }
-
-    public void onLostFocus(Widget sender) {
-        final String html = rta.getHTML();
-        client.updateVariable(id, "text", html, immediate);
-
-    }
-
-    /**
-     * @return space used by components paddings and borders
-     */
-    private int getExtraHorizontalPixels() {
-        if (extraHorizontalPixels < 0) {
-            detectExtraSizes();
-        }
-        return extraHorizontalPixels;
-    }
-
-    /**
-     * @return space used by components paddings and borders
-     */
-    private int getExtraVerticalPixels() {
-        if (extraVerticalPixels < 0) {
-            detectExtraSizes();
-        }
-        return extraVerticalPixels;
-    }
-
-    /**
-     * Detects space used by components paddings and borders.
-     */
-    private void detectExtraSizes() {
-        Element clone = Util.cloneNode(getElement(), false);
-        DOM.setElementAttribute(clone, "id", "");
-        DOM.setStyleAttribute(clone, "visibility", "hidden");
-        DOM.setStyleAttribute(clone, "position", "absolute");
-        // due FF3 bug set size to 10px and later subtract it from extra pixels
-        DOM.setStyleAttribute(clone, "width", "10px");
-        DOM.setStyleAttribute(clone, "height", "10px");
-        DOM.appendChild(DOM.getParent(getElement()), clone);
-        extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10;
-        extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10;
-
-        DOM.removeChild(DOM.getParent(getElement()), clone);
-    }
-
-    @Override
-    public void setHeight(String height) {
-        if (height.endsWith("px")) {
-            int h = Integer.parseInt(height.substring(0, height.length() - 2));
-            h -= getExtraVerticalPixels();
-            if (h < 0) {
-                h = 0;
-            }
-
-            super.setHeight(h + "px");
-        } else {
-            super.setHeight(height);
-        }
-
-        if (height == null || height.equals("")) {
-            rta.setHeight("");
-        } else {
-            int editorHeight = getOffsetHeight() - getExtraVerticalPixels()
-                    - formatter.getOffsetHeight();
-            rta.setHeight(editorHeight + "px");
-        }
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (width.endsWith("px")) {
-            int w = Integer.parseInt(width.substring(0, width.length() - 2));
-            w -= getExtraHorizontalPixels();
-            if (w < 0) {
-                w = 0;
-            }
-
-            super.setWidth(w + "px");
-        } else if (width.equals("")) {
-            /*
-             * IE cannot calculate the width of the 100% iframe correctly if
-             * there is no width specified for the parent. In this case we would
-             * use the toolbar but IE cannot calculate the width of that one
-             * correctly either in all cases. So we end up using a default width
-             * for a RichTextArea with no width definition in all browsers (for
-             * compatibility).
-             */
-
-            super.setWidth(toolbarNaturalWidth + "px");
-        } else {
-            super.setWidth(width);
-        }
-    }
-
-    public void onKeyDown(Widget sender, char keyCode, int modifiers) {
-        // NOP
-    }
-
-    public void onKeyPress(Widget sender, char keyCode, int modifiers) {
-        if (maxLength >= 0) {
-            DeferredCommand.addCommand(new Command() {
-                public void execute() {
-                    if (rta.getHTML().length() > maxLength) {
-                        rta.setHTML(rta.getHTML().substring(0, maxLength));
-                    }
-                }
-            });
-        }
-    }
-
-    public void onKeyUp(Widget sender, char keyCode, int modifiers) {
-        // NOP
-    }
-
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextToolbar$Strings.properties b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextToolbar$Strings.properties
deleted file mode 100644 (file)
index 363b704..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-bold = Toggle Bold
-createLink = Create Link
-hr = Insert Horizontal Rule
-indent = Indent Right
-insertImage = Insert Image
-italic = Toggle Italic
-justifyCenter = Center
-justifyLeft = Left Justify
-justifyRight = Right Justify
-ol = Insert Ordered List
-outdent = Indent Left
-removeFormat = Remove Formatting
-removeLink = Remove Link
-strikeThrough = Toggle Strikethrough
-subscript = Toggle Subscript
-superscript = Toggle Superscript
-ul = Insert Unordered List
-underline = Toggle Underline
-color = Color
-black = Black
-white = White
-red = Red
-green = Green
-yellow = Yellow
-blue = Blue
-font = Font
-normal = Normal
-size = Size
-xxsmall = XX-Small
-xsmall = X-Small
-small = Small
-medium = Medium
-large = Large
-xlarge = X-Large
-xxlarge = XX-Large
\ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextToolbar.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/IRichTextToolbar.java
deleted file mode 100644 (file)
index 433be77..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright 2007 Google Inc.
- * 
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.vaadin.terminal.gwt.client.ui.richtextarea;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.i18n.client.Constants;
-import com.google.gwt.user.client.Window;
-import com.google.gwt.user.client.ui.AbstractImagePrototype;
-import com.google.gwt.user.client.ui.ChangeListener;
-import com.google.gwt.user.client.ui.ClickListener;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.FlowPanel;
-import com.google.gwt.user.client.ui.ImageBundle;
-import com.google.gwt.user.client.ui.KeyboardListener;
-import com.google.gwt.user.client.ui.ListBox;
-import com.google.gwt.user.client.ui.PushButton;
-import com.google.gwt.user.client.ui.RichTextArea;
-import com.google.gwt.user.client.ui.ToggleButton;
-import com.google.gwt.user.client.ui.Widget;
-
-/**
- * A modified version of sample toolbar for use with {@link RichTextArea}. It
- * provides a simple UI for all rich text formatting, dynamically displayed only
- * for the available functionality.
- */
-public class IRichTextToolbar extends Composite {
-
-    /**
-     * This {@link ImageBundle} is used for all the button icons. Using an image
-     * bundle allows all of these images to be packed into a single image, which
-     * saves a lot of HTTP requests, drastically improving startup time.
-     */
-    public interface Images extends ImageBundle {
-
-        @ImageBundle.Resource("bold.gif")
-        AbstractImagePrototype bold();
-
-        @ImageBundle.Resource("createLink.gif")
-        AbstractImagePrototype createLink();
-
-        @ImageBundle.Resource("hr.gif")
-        AbstractImagePrototype hr();
-
-        @ImageBundle.Resource("indent.gif")
-        AbstractImagePrototype indent();
-
-        @ImageBundle.Resource("insertImage.gif")
-        AbstractImagePrototype insertImage();
-
-        @ImageBundle.Resource("italic.gif")
-        AbstractImagePrototype italic();
-
-        @ImageBundle.Resource("justifyCenter.gif")
-        AbstractImagePrototype justifyCenter();
-
-        @ImageBundle.Resource("justifyLeft.gif")
-        AbstractImagePrototype justifyLeft();
-
-        @ImageBundle.Resource("justifyRight.gif")
-        AbstractImagePrototype justifyRight();
-
-        @ImageBundle.Resource("ol.gif")
-        AbstractImagePrototype ol();
-
-        @ImageBundle.Resource("outdent.gif")
-        AbstractImagePrototype outdent();
-
-        @ImageBundle.Resource("removeFormat.gif")
-        AbstractImagePrototype removeFormat();
-
-        @ImageBundle.Resource("removeLink.gif")
-        AbstractImagePrototype removeLink();
-
-        @ImageBundle.Resource("strikeThrough.gif")
-        AbstractImagePrototype strikeThrough();
-
-        @ImageBundle.Resource("subscript.gif")
-        AbstractImagePrototype subscript();
-
-        @ImageBundle.Resource("superscript.gif")
-        AbstractImagePrototype superscript();
-
-        @ImageBundle.Resource("ul.gif")
-        AbstractImagePrototype ul();
-
-        @ImageBundle.Resource("underline.gif")
-        AbstractImagePrototype underline();
-    }
-
-    /**
-     * This {@link Constants} interface is used to make the toolbar's strings
-     * internationalizable.
-     */
-    public interface Strings extends Constants {
-
-        String black();
-
-        String blue();
-
-        String bold();
-
-        String color();
-
-        String createLink();
-
-        String font();
-
-        String green();
-
-        String hr();
-
-        String indent();
-
-        String insertImage();
-
-        String italic();
-
-        String justifyCenter();
-
-        String justifyLeft();
-
-        String justifyRight();
-
-        String large();
-
-        String medium();
-
-        String normal();
-
-        String ol();
-
-        String outdent();
-
-        String red();
-
-        String removeFormat();
-
-        String removeLink();
-
-        String size();
-
-        String small();
-
-        String strikeThrough();
-
-        String subscript();
-
-        String superscript();
-
-        String ul();
-
-        String underline();
-
-        String white();
-
-        String xlarge();
-
-        String xsmall();
-
-        String xxlarge();
-
-        String xxsmall();
-
-        String yellow();
-    }
-
-    /**
-     * We use an inner EventListener class to avoid exposing event methods on
-     * the RichTextToolbar itself.
-     */
-    private class EventListener implements ClickListener, ChangeListener,
-            KeyboardListener {
-
-        public void onChange(Widget sender) {
-            if (sender == backColors) {
-                basic.setBackColor(backColors.getValue(backColors
-                        .getSelectedIndex()));
-                backColors.setSelectedIndex(0);
-            } else if (sender == foreColors) {
-                basic.setForeColor(foreColors.getValue(foreColors
-                        .getSelectedIndex()));
-                foreColors.setSelectedIndex(0);
-            } else if (sender == fonts) {
-                basic.setFontName(fonts.getValue(fonts.getSelectedIndex()));
-                fonts.setSelectedIndex(0);
-            } else if (sender == fontSizes) {
-                basic.setFontSize(fontSizesConstants[fontSizes
-                        .getSelectedIndex() - 1]);
-                fontSizes.setSelectedIndex(0);
-            }
-        }
-
-        public void onClick(Widget sender) {
-            if (sender == bold) {
-                basic.toggleBold();
-            } else if (sender == italic) {
-                basic.toggleItalic();
-            } else if (sender == underline) {
-                basic.toggleUnderline();
-            } else if (sender == subscript) {
-                basic.toggleSubscript();
-            } else if (sender == superscript) {
-                basic.toggleSuperscript();
-            } else if (sender == strikethrough) {
-                extended.toggleStrikethrough();
-            } else if (sender == indent) {
-                extended.rightIndent();
-            } else if (sender == outdent) {
-                extended.leftIndent();
-            } else if (sender == justifyLeft) {
-                basic.setJustification(RichTextArea.Justification.LEFT);
-            } else if (sender == justifyCenter) {
-                basic.setJustification(RichTextArea.Justification.CENTER);
-            } else if (sender == justifyRight) {
-                basic.setJustification(RichTextArea.Justification.RIGHT);
-            } else if (sender == insertImage) {
-                final String url = Window.prompt("Enter an image URL:",
-                        "http://");
-                if (url != null) {
-                    extended.insertImage(url);
-                }
-            } else if (sender == createLink) {
-                final String url = Window
-                        .prompt("Enter a link URL:", "http://");
-                if (url != null) {
-                    extended.createLink(url);
-                }
-            } else if (sender == removeLink) {
-                extended.removeLink();
-            } else if (sender == hr) {
-                extended.insertHorizontalRule();
-            } else if (sender == ol) {
-                extended.insertOrderedList();
-            } else if (sender == ul) {
-                extended.insertUnorderedList();
-            } else if (sender == removeFormat) {
-                extended.removeFormat();
-            } else if (sender == richText) {
-                // We use the RichTextArea's onKeyUp event to update the toolbar
-                // status.
-                // This will catch any cases where the user moves the cursur
-                // using the
-                // keyboard, or uses one of the browser's built-in keyboard
-                // shortcuts.
-                updateStatus();
-            }
-        }
-
-        public void onKeyDown(Widget sender, char keyCode, int modifiers) {
-        }
-
-        public void onKeyPress(Widget sender, char keyCode, int modifiers) {
-        }
-
-        public void onKeyUp(Widget sender, char keyCode, int modifiers) {
-            if (sender == richText) {
-                // We use the RichTextArea's onKeyUp event to update the toolbar
-                // status.
-                // This will catch any cases where the user moves the cursur
-                // using the
-                // keyboard, or uses one of the browser's built-in keyboard
-                // shortcuts.
-                updateStatus();
-            }
-        }
-    }
-
-    private static final RichTextArea.FontSize[] fontSizesConstants = new RichTextArea.FontSize[] {
-            RichTextArea.FontSize.XX_SMALL, RichTextArea.FontSize.X_SMALL,
-            RichTextArea.FontSize.SMALL, RichTextArea.FontSize.MEDIUM,
-            RichTextArea.FontSize.LARGE, RichTextArea.FontSize.X_LARGE,
-            RichTextArea.FontSize.XX_LARGE };
-
-    private final Images images = (Images) GWT.create(Images.class);
-    private final Strings strings = (Strings) GWT.create(Strings.class);
-    private final EventListener listener = new EventListener();
-
-    private final RichTextArea richText;
-    private final RichTextArea.BasicFormatter basic;
-    private final RichTextArea.ExtendedFormatter extended;
-
-    private final FlowPanel outer = new FlowPanel();
-    private final FlowPanel topPanel = new FlowPanel();
-    private final FlowPanel bottomPanel = new FlowPanel();
-    private ToggleButton bold;
-    private ToggleButton italic;
-    private ToggleButton underline;
-    private ToggleButton subscript;
-    private ToggleButton superscript;
-    private ToggleButton strikethrough;
-    private PushButton indent;
-    private PushButton outdent;
-    private PushButton justifyLeft;
-    private PushButton justifyCenter;
-    private PushButton justifyRight;
-    private PushButton hr;
-    private PushButton ol;
-    private PushButton ul;
-    private PushButton insertImage;
-    private PushButton createLink;
-    private PushButton removeLink;
-    private PushButton removeFormat;
-
-    private ListBox backColors;
-    private ListBox foreColors;
-    private ListBox fonts;
-    private ListBox fontSizes;
-
-    /**
-     * Creates a new toolbar that drives the given rich text area.
-     * 
-     * @param richText
-     *            the rich text area to be controlled
-     */
-    public IRichTextToolbar(RichTextArea richText) {
-        this.richText = richText;
-        basic = richText.getBasicFormatter();
-        extended = richText.getExtendedFormatter();
-
-        outer.add(topPanel);
-        outer.add(bottomPanel);
-        topPanel.setWidth("100%");
-        topPanel.setHeight("20px");
-        topPanel.getElement().getStyle().setProperty("overflow", "hidden");
-        bottomPanel.setWidth("100%");
-
-        initWidget(outer);
-        setStyleName("gwt-RichTextToolbar");
-
-        if (basic != null) {
-            topPanel.add(bold = createToggleButton(images.bold(), strings
-                    .bold()));
-            topPanel.add(italic = createToggleButton(images.italic(), strings
-                    .italic()));
-            topPanel.add(underline = createToggleButton(images.underline(),
-                    strings.underline()));
-            topPanel.add(subscript = createToggleButton(images.subscript(),
-                    strings.subscript()));
-            topPanel.add(superscript = createToggleButton(images.superscript(),
-                    strings.superscript()));
-            topPanel.add(justifyLeft = createPushButton(images.justifyLeft(),
-                    strings.justifyLeft()));
-            topPanel.add(justifyCenter = createPushButton(images
-                    .justifyCenter(), strings.justifyCenter()));
-            topPanel.add(justifyRight = createPushButton(images.justifyRight(),
-                    strings.justifyRight()));
-        }
-
-        if (extended != null) {
-            topPanel.add(strikethrough = createToggleButton(images
-                    .strikeThrough(), strings.strikeThrough()));
-            topPanel.add(indent = createPushButton(images.indent(), strings
-                    .indent()));
-            topPanel.add(outdent = createPushButton(images.outdent(), strings
-                    .outdent()));
-            topPanel.add(hr = createPushButton(images.hr(), strings.hr()));
-            topPanel.add(ol = createPushButton(images.ol(), strings.ol()));
-            topPanel.add(ul = createPushButton(images.ul(), strings.ul()));
-            topPanel.add(insertImage = createPushButton(images.insertImage(),
-                    strings.insertImage()));
-            topPanel.add(createLink = createPushButton(images.createLink(),
-                    strings.createLink()));
-            topPanel.add(removeLink = createPushButton(images.removeLink(),
-                    strings.removeLink()));
-            topPanel.add(removeFormat = createPushButton(images.removeFormat(),
-                    strings.removeFormat()));
-        }
-
-        if (basic != null) {
-            bottomPanel.add(backColors = createColorList("Background"));
-            bottomPanel.add(foreColors = createColorList("Foreground"));
-            bottomPanel.add(fonts = createFontList());
-            bottomPanel.add(fontSizes = createFontSizes());
-
-            // We only use these listeners for updating status, so don't hook
-            // them up
-            // unless at least basic editing is supported.
-            richText.addKeyboardListener(listener);
-            richText.addClickListener(listener);
-        }
-    }
-
-    private ListBox createColorList(String caption) {
-        final ListBox lb = new ListBox();
-        lb.addChangeListener(listener);
-        lb.setVisibleItemCount(1);
-
-        lb.addItem(caption);
-        lb.addItem(strings.white(), "white");
-        lb.addItem(strings.black(), "black");
-        lb.addItem(strings.red(), "red");
-        lb.addItem(strings.green(), "green");
-        lb.addItem(strings.yellow(), "yellow");
-        lb.addItem(strings.blue(), "blue");
-        return lb;
-    }
-
-    private ListBox createFontList() {
-        final ListBox lb = new ListBox();
-        lb.addChangeListener(listener);
-        lb.setVisibleItemCount(1);
-
-        lb.addItem(strings.font(), "");
-        lb.addItem(strings.normal(), "");
-        lb.addItem("Times New Roman", "Times New Roman");
-        lb.addItem("Arial", "Arial");
-        lb.addItem("Courier New", "Courier New");
-        lb.addItem("Georgia", "Georgia");
-        lb.addItem("Trebuchet", "Trebuchet");
-        lb.addItem("Verdana", "Verdana");
-        return lb;
-    }
-
-    private ListBox createFontSizes() {
-        final ListBox lb = new ListBox();
-        lb.addChangeListener(listener);
-        lb.setVisibleItemCount(1);
-
-        lb.addItem(strings.size());
-        lb.addItem(strings.xxsmall());
-        lb.addItem(strings.xsmall());
-        lb.addItem(strings.small());
-        lb.addItem(strings.medium());
-        lb.addItem(strings.large());
-        lb.addItem(strings.xlarge());
-        lb.addItem(strings.xxlarge());
-        return lb;
-    }
-
-    private PushButton createPushButton(AbstractImagePrototype img, String tip) {
-        final PushButton pb = new PushButton(img.createImage());
-        pb.addClickListener(listener);
-        pb.setTitle(tip);
-        return pb;
-    }
-
-    private ToggleButton createToggleButton(AbstractImagePrototype img,
-            String tip) {
-        final ToggleButton tb = new ToggleButton(img.createImage());
-        tb.addClickListener(listener);
-        tb.setTitle(tip);
-        return tb;
-    }
-
-    /**
-     * Updates the status of all the stateful buttons.
-     */
-    private void updateStatus() {
-        if (basic != null) {
-            bold.setDown(basic.isBold());
-            italic.setDown(basic.isItalic());
-            underline.setDown(basic.isUnderlined());
-            subscript.setDown(basic.isSubscript());
-            superscript.setDown(basic.isSuperscript());
-        }
-
-        if (extended != null) {
-            strikethrough.setDown(extended.isStrikethrough());
-        }
-    }
-}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextArea.java
new file mode 100644 (file)
index 0000000..fea431e
--- /dev/null
@@ -0,0 +1,251 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.terminal.gwt.client.ui.richtextarea;
+
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.DeferredCommand;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.ChangeListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.FocusListener;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.KeyboardListener;
+import com.google.gwt.user.client.ui.RichTextArea;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.BrowserInfo;
+import com.vaadin.terminal.gwt.client.Paintable;
+import com.vaadin.terminal.gwt.client.UIDL;
+import com.vaadin.terminal.gwt.client.Util;
+import com.vaadin.terminal.gwt.client.ui.Field;
+
+/**
+ * This class implements a basic client side rich text editor component.
+ * 
+ * @author IT Mill Ltd.
+ * 
+ */
+public class VRichTextArea extends Composite implements Paintable, Field,
+        ChangeListener, FocusListener, KeyboardListener {
+
+    /**
+     * The input node CSS classname.
+     */
+    public static final String CLASSNAME = "i-richtextarea";
+
+    protected String id;
+
+    protected ApplicationConnection client;
+
+    private boolean immediate = false;
+
+    private RichTextArea rta = new RichTextArea();
+
+    private VRichTextToolbar formatter = new VRichTextToolbar(rta);
+
+    private HTML html = new HTML();
+
+    private final FlowPanel fp = new FlowPanel();
+
+    private boolean enabled = true;
+
+    private int extraHorizontalPixels = -1;
+    private int extraVerticalPixels = -1;
+
+    private int maxLength = -1;
+
+    private int toolbarNaturalWidth = 500;
+
+    public VRichTextArea() {
+        fp.add(formatter);
+
+        rta.setWidth("100%");
+        rta.addFocusListener(this);
+
+        fp.add(rta);
+
+        initWidget(fp);
+        setStyleName(CLASSNAME);
+
+    }
+
+    public void setEnabled(boolean enabled) {
+        if (this.enabled != enabled) {
+            rta.setEnabled(enabled);
+            if (enabled) {
+                fp.remove(html);
+                fp.add(rta);
+            } else {
+                html.setHTML(rta.getHTML());
+                fp.remove(rta);
+                fp.add(html);
+            }
+
+            this.enabled = enabled;
+        }
+    }
+
+    public void updateFromUIDL(final UIDL uidl, ApplicationConnection client) {
+        this.client = client;
+        id = uidl.getId();
+
+        if (uidl.hasVariable("text")) {
+            if (BrowserInfo.get().isIE()) {
+                // rta is rather buggy in IE (as pretty much everything is)
+                // it needs some "shaking" not to fall into uneditable state
+                // see #2374
+                rta.getBasicFormatter().toggleBold();
+                rta.getBasicFormatter().toggleBold();
+            }
+            rta.setHTML(uidl.getStringVariable("text"));
+
+        }
+        setEnabled(!uidl.getBooleanAttribute("disabled"));
+
+        if (client.updateComponent(this, uidl, true)) {
+            return;
+        }
+
+        immediate = uidl.getBooleanAttribute("immediate");
+        int newMaxLength = uidl.hasAttribute("maxLength") ? uidl
+                .getIntAttribute("maxLength") : -1;
+        if (newMaxLength >= 0) {
+            if (maxLength == -1) {
+                rta.addKeyboardListener(this);
+            }
+            maxLength = newMaxLength;
+        } else if (maxLength != -1) {
+            getElement().setAttribute("maxlength", "");
+            maxLength = -1;
+            rta.removeKeyboardListener(this);
+        }
+    }
+
+    public void onChange(Widget sender) {
+        if (client != null && id != null) {
+            client.updateVariable(id, "text", rta.getText(), immediate);
+        }
+    }
+
+    public void onFocus(Widget sender) {
+
+    }
+
+    public void onLostFocus(Widget sender) {
+        final String html = rta.getHTML();
+        client.updateVariable(id, "text", html, immediate);
+
+    }
+
+    /**
+     * @return space used by components paddings and borders
+     */
+    private int getExtraHorizontalPixels() {
+        if (extraHorizontalPixels < 0) {
+            detectExtraSizes();
+        }
+        return extraHorizontalPixels;
+    }
+
+    /**
+     * @return space used by components paddings and borders
+     */
+    private int getExtraVerticalPixels() {
+        if (extraVerticalPixels < 0) {
+            detectExtraSizes();
+        }
+        return extraVerticalPixels;
+    }
+
+    /**
+     * Detects space used by components paddings and borders.
+     */
+    private void detectExtraSizes() {
+        Element clone = Util.cloneNode(getElement(), false);
+        DOM.setElementAttribute(clone, "id", "");
+        DOM.setStyleAttribute(clone, "visibility", "hidden");
+        DOM.setStyleAttribute(clone, "position", "absolute");
+        // due FF3 bug set size to 10px and later subtract it from extra pixels
+        DOM.setStyleAttribute(clone, "width", "10px");
+        DOM.setStyleAttribute(clone, "height", "10px");
+        DOM.appendChild(DOM.getParent(getElement()), clone);
+        extraHorizontalPixels = DOM.getElementPropertyInt(clone, "offsetWidth") - 10;
+        extraVerticalPixels = DOM.getElementPropertyInt(clone, "offsetHeight") - 10;
+
+        DOM.removeChild(DOM.getParent(getElement()), clone);
+    }
+
+    @Override
+    public void setHeight(String height) {
+        if (height.endsWith("px")) {
+            int h = Integer.parseInt(height.substring(0, height.length() - 2));
+            h -= getExtraVerticalPixels();
+            if (h < 0) {
+                h = 0;
+            }
+
+            super.setHeight(h + "px");
+        } else {
+            super.setHeight(height);
+        }
+
+        if (height == null || height.equals("")) {
+            rta.setHeight("");
+        } else {
+            int editorHeight = getOffsetHeight() - getExtraVerticalPixels()
+                    - formatter.getOffsetHeight();
+            rta.setHeight(editorHeight + "px");
+        }
+    }
+
+    @Override
+    public void setWidth(String width) {
+        if (width.endsWith("px")) {
+            int w = Integer.parseInt(width.substring(0, width.length() - 2));
+            w -= getExtraHorizontalPixels();
+            if (w < 0) {
+                w = 0;
+            }
+
+            super.setWidth(w + "px");
+        } else if (width.equals("")) {
+            /*
+             * IE cannot calculate the width of the 100% iframe correctly if
+             * there is no width specified for the parent. In this case we would
+             * use the toolbar but IE cannot calculate the width of that one
+             * correctly either in all cases. So we end up using a default width
+             * for a RichTextArea with no width definition in all browsers (for
+             * compatibility).
+             */
+
+            super.setWidth(toolbarNaturalWidth + "px");
+        } else {
+            super.setWidth(width);
+        }
+    }
+
+    public void onKeyDown(Widget sender, char keyCode, int modifiers) {
+        // NOP
+    }
+
+    public void onKeyPress(Widget sender, char keyCode, int modifiers) {
+        if (maxLength >= 0) {
+            DeferredCommand.addCommand(new Command() {
+                public void execute() {
+                    if (rta.getHTML().length() > maxLength) {
+                        rta.setHTML(rta.getHTML().substring(0, maxLength));
+                    }
+                }
+            });
+        }
+    }
+
+    public void onKeyUp(Widget sender, char keyCode, int modifiers) {
+        // NOP
+    }
+
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextToolbar$Strings.properties b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextToolbar$Strings.properties
new file mode 100644 (file)
index 0000000..363b704
--- /dev/null
@@ -0,0 +1,35 @@
+bold = Toggle Bold
+createLink = Create Link
+hr = Insert Horizontal Rule
+indent = Indent Right
+insertImage = Insert Image
+italic = Toggle Italic
+justifyCenter = Center
+justifyLeft = Left Justify
+justifyRight = Right Justify
+ol = Insert Ordered List
+outdent = Indent Left
+removeFormat = Remove Formatting
+removeLink = Remove Link
+strikeThrough = Toggle Strikethrough
+subscript = Toggle Subscript
+superscript = Toggle Superscript
+ul = Insert Unordered List
+underline = Toggle Underline
+color = Color
+black = Black
+white = White
+red = Red
+green = Green
+yellow = Yellow
+blue = Blue
+font = Font
+normal = Normal
+size = Size
+xxsmall = XX-Small
+xsmall = X-Small
+small = Small
+medium = Medium
+large = Large
+xlarge = X-Large
+xxlarge = XX-Large
\ No newline at end of file
diff --git a/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextToolbar.java b/src/com/vaadin/terminal/gwt/client/ui/richtextarea/VRichTextToolbar.java
new file mode 100644 (file)
index 0000000..5325550
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Copyright 2007 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.terminal.gwt.client.ui.richtextarea;
+
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.i18n.client.Constants;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.AbstractImagePrototype;
+import com.google.gwt.user.client.ui.ChangeListener;
+import com.google.gwt.user.client.ui.ClickListener;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.ImageBundle;
+import com.google.gwt.user.client.ui.KeyboardListener;
+import com.google.gwt.user.client.ui.ListBox;
+import com.google.gwt.user.client.ui.PushButton;
+import com.google.gwt.user.client.ui.RichTextArea;
+import com.google.gwt.user.client.ui.ToggleButton;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * A modified version of sample toolbar for use with {@link RichTextArea}. It
+ * provides a simple UI for all rich text formatting, dynamically displayed only
+ * for the available functionality.
+ */
+public class VRichTextToolbar extends Composite {
+
+    /**
+     * This {@link ImageBundle} is used for all the button icons. Using an image
+     * bundle allows all of these images to be packed into a single image, which
+     * saves a lot of HTTP requests, drastically improving startup time.
+     */
+    public interface Images extends ImageBundle {
+
+        @ImageBundle.Resource("bold.gif")
+        AbstractImagePrototype bold();
+
+        @ImageBundle.Resource("createLink.gif")
+        AbstractImagePrototype createLink();
+
+        @ImageBundle.Resource("hr.gif")
+        AbstractImagePrototype hr();
+
+        @ImageBundle.Resource("indent.gif")
+        AbstractImagePrototype indent();
+
+        @ImageBundle.Resource("insertImage.gif")
+        AbstractImagePrototype insertImage();
+
+        @ImageBundle.Resource("italic.gif")
+        AbstractImagePrototype italic();
+
+        @ImageBundle.Resource("justifyCenter.gif")
+        AbstractImagePrototype justifyCenter();
+
+        @ImageBundle.Resource("justifyLeft.gif")
+        AbstractImagePrototype justifyLeft();
+
+        @ImageBundle.Resource("justifyRight.gif")
+        AbstractImagePrototype justifyRight();
+
+        @ImageBundle.Resource("ol.gif")
+        AbstractImagePrototype ol();
+
+        @ImageBundle.Resource("outdent.gif")
+        AbstractImagePrototype outdent();
+
+        @ImageBundle.Resource("removeFormat.gif")
+        AbstractImagePrototype removeFormat();
+
+        @ImageBundle.Resource("removeLink.gif")
+        AbstractImagePrototype removeLink();
+
+        @ImageBundle.Resource("strikeThrough.gif")
+        AbstractImagePrototype strikeThrough();
+
+        @ImageBundle.Resource("subscript.gif")
+        AbstractImagePrototype subscript();
+
+        @ImageBundle.Resource("superscript.gif")
+        AbstractImagePrototype superscript();
+
+        @ImageBundle.Resource("ul.gif")
+        AbstractImagePrototype ul();
+
+        @ImageBundle.Resource("underline.gif")
+        AbstractImagePrototype underline();
+    }
+
+    /**
+     * This {@link Constants} interface is used to make the toolbar's strings
+     * internationalizable.
+     */
+    public interface Strings extends Constants {
+
+        String black();
+
+        String blue();
+
+        String bold();
+
+        String color();
+
+        String createLink();
+
+        String font();
+
+        String green();
+
+        String hr();
+
+        String indent();
+
+        String insertImage();
+
+        String italic();
+
+        String justifyCenter();
+
+        String justifyLeft();
+
+        String justifyRight();
+
+        String large();
+
+        String medium();
+
+        String normal();
+
+        String ol();
+
+        String outdent();
+
+        String red();
+
+        String removeFormat();
+
+        String removeLink();
+
+        String size();
+
+        String small();
+
+        String strikeThrough();
+
+        String subscript();
+
+        String superscript();
+
+        String ul();
+
+        String underline();
+
+        String white();
+
+        String xlarge();
+
+        String xsmall();
+
+        String xxlarge();
+
+        String xxsmall();
+
+        String yellow();
+    }
+
+    /**
+     * We use an inner EventListener class to avoid exposing event methods on
+     * the RichTextToolbar itself.
+     */
+    private class EventListener implements ClickListener, ChangeListener,
+            KeyboardListener {
+
+        public void onChange(Widget sender) {
+            if (sender == backColors) {
+                basic.setBackColor(backColors.getValue(backColors
+                        .getSelectedIndex()));
+                backColors.setSelectedIndex(0);
+            } else if (sender == foreColors) {
+                basic.setForeColor(foreColors.getValue(foreColors
+                        .getSelectedIndex()));
+                foreColors.setSelectedIndex(0);
+            } else if (sender == fonts) {
+                basic.setFontName(fonts.getValue(fonts.getSelectedIndex()));
+                fonts.setSelectedIndex(0);
+            } else if (sender == fontSizes) {
+                basic.setFontSize(fontSizesConstants[fontSizes
+                        .getSelectedIndex() - 1]);
+                fontSizes.setSelectedIndex(0);
+            }
+        }
+
+        public void onClick(Widget sender) {
+            if (sender == bold) {
+                basic.toggleBold();
+            } else if (sender == italic) {
+                basic.toggleItalic();
+            } else if (sender == underline) {
+                basic.toggleUnderline();
+            } else if (sender == subscript) {
+                basic.toggleSubscript();
+            } else if (sender == superscript) {
+                basic.toggleSuperscript();
+            } else if (sender == strikethrough) {
+                extended.toggleStrikethrough();
+            } else if (sender == indent) {
+                extended.rightIndent();
+            } else if (sender == outdent) {
+                extended.leftIndent();
+            } else if (sender == justifyLeft) {
+                basic.setJustification(RichTextArea.Justification.LEFT);
+            } else if (sender == justifyCenter) {
+                basic.setJustification(RichTextArea.Justification.CENTER);
+            } else if (sender == justifyRight) {
+                basic.setJustification(RichTextArea.Justification.RIGHT);
+            } else if (sender == insertImage) {
+                final String url = Window.prompt("Enter an image URL:",
+                        "http://");
+                if (url != null) {
+                    extended.insertImage(url);
+                }
+            } else if (sender == createLink) {
+                final String url = Window
+                        .prompt("Enter a link URL:", "http://");
+                if (url != null) {
+                    extended.createLink(url);
+                }
+            } else if (sender == removeLink) {
+                extended.removeLink();
+            } else if (sender == hr) {
+                extended.insertHorizontalRule();
+            } else if (sender == ol) {
+                extended.insertOrderedList();
+            } else if (sender == ul) {
+                extended.insertUnorderedList();
+            } else if (sender == removeFormat) {
+                extended.removeFormat();
+            } else if (sender == richText) {
+                // We use the RichTextArea's onKeyUp event to update the toolbar
+                // status.
+                // This will catch any cases where the user moves the cursur
+                // using the
+                // keyboard, or uses one of the browser's built-in keyboard
+                // shortcuts.
+                updateStatus();
+            }
+        }
+
+        public void onKeyDown(Widget sender, char keyCode, int modifiers) {
+        }
+
+        public void onKeyPress(Widget sender, char keyCode, int modifiers) {
+        }
+
+        public void onKeyUp(Widget sender, char keyCode, int modifiers) {
+            if (sender == richText) {
+                // We use the RichTextArea's onKeyUp event to update the toolbar
+                // status.
+                // This will catch any cases where the user moves the cursur
+                // using the
+                // keyboard, or uses one of the browser's built-in keyboard
+                // shortcuts.
+                updateStatus();
+            }
+        }
+    }
+
+    private static final RichTextArea.FontSize[] fontSizesConstants = new RichTextArea.FontSize[] {
+            RichTextArea.FontSize.XX_SMALL, RichTextArea.FontSize.X_SMALL,
+            RichTextArea.FontSize.SMALL, RichTextArea.FontSize.MEDIUM,
+            RichTextArea.FontSize.LARGE, RichTextArea.FontSize.X_LARGE,
+            RichTextArea.FontSize.XX_LARGE };
+
+    private final Images images = (Images) GWT.create(Images.class);
+    private final Strings strings = (Strings) GWT.create(Strings.class);
+    private final EventListener listener = new EventListener();
+
+    private final RichTextArea richText;
+    private final RichTextArea.BasicFormatter basic;
+    private final RichTextArea.ExtendedFormatter extended;
+
+    private final FlowPanel outer = new FlowPanel();
+    private final FlowPanel topPanel = new FlowPanel();
+    private final FlowPanel bottomPanel = new FlowPanel();
+    private ToggleButton bold;
+    private ToggleButton italic;
+    private ToggleButton underline;
+    private ToggleButton subscript;
+    private ToggleButton superscript;
+    private ToggleButton strikethrough;
+    private PushButton indent;
+    private PushButton outdent;
+    private PushButton justifyLeft;
+    private PushButton justifyCenter;
+    private PushButton justifyRight;
+    private PushButton hr;
+    private PushButton ol;
+    private PushButton ul;
+    private PushButton insertImage;
+    private PushButton createLink;
+    private PushButton removeLink;
+    private PushButton removeFormat;
+
+    private ListBox backColors;
+    private ListBox foreColors;
+    private ListBox fonts;
+    private ListBox fontSizes;
+
+    /**
+     * Creates a new toolbar that drives the given rich text area.
+     * 
+     * @param richText
+     *            the rich text area to be controlled
+     */
+    public VRichTextToolbar(RichTextArea richText) {
+        this.richText = richText;
+        basic = richText.getBasicFormatter();
+        extended = richText.getExtendedFormatter();
+
+        outer.add(topPanel);
+        outer.add(bottomPanel);
+        topPanel.setWidth("100%");
+        topPanel.setHeight("20px");
+        topPanel.getElement().getStyle().setProperty("overflow", "hidden");
+        bottomPanel.setWidth("100%");
+
+        initWidget(outer);
+        setStyleName("gwt-RichTextToolbar");
+
+        if (basic != null) {
+            topPanel.add(bold = createToggleButton(images.bold(), strings
+                    .bold()));
+            topPanel.add(italic = createToggleButton(images.italic(), strings
+                    .italic()));
+            topPanel.add(underline = createToggleButton(images.underline(),
+                    strings.underline()));
+            topPanel.add(subscript = createToggleButton(images.subscript(),
+                    strings.subscript()));
+            topPanel.add(superscript = createToggleButton(images.superscript(),
+                    strings.superscript()));
+            topPanel.add(justifyLeft = createPushButton(images.justifyLeft(),
+                    strings.justifyLeft()));
+            topPanel.add(justifyCenter = createPushButton(images
+                    .justifyCenter(), strings.justifyCenter()));
+            topPanel.add(justifyRight = createPushButton(images.justifyRight(),
+                    strings.justifyRight()));
+        }
+
+        if (extended != null) {
+            topPanel.add(strikethrough = createToggleButton(images
+                    .strikeThrough(), strings.strikeThrough()));
+            topPanel.add(indent = createPushButton(images.indent(), strings
+                    .indent()));
+            topPanel.add(outdent = createPushButton(images.outdent(), strings
+                    .outdent()));
+            topPanel.add(hr = createPushButton(images.hr(), strings.hr()));
+            topPanel.add(ol = createPushButton(images.ol(), strings.ol()));
+            topPanel.add(ul = createPushButton(images.ul(), strings.ul()));
+            topPanel.add(insertImage = createPushButton(images.insertImage(),
+                    strings.insertImage()));
+            topPanel.add(createLink = createPushButton(images.createLink(),
+                    strings.createLink()));
+            topPanel.add(removeLink = createPushButton(images.removeLink(),
+                    strings.removeLink()));
+            topPanel.add(removeFormat = createPushButton(images.removeFormat(),
+                    strings.removeFormat()));
+        }
+
+        if (basic != null) {
+            bottomPanel.add(backColors = createColorList("Background"));
+            bottomPanel.add(foreColors = createColorList("Foreground"));
+            bottomPanel.add(fonts = createFontList());
+            bottomPanel.add(fontSizes = createFontSizes());
+
+            // We only use these listeners for updating status, so don't hook
+            // them up
+            // unless at least basic editing is supported.
+            richText.addKeyboardListener(listener);
+            richText.addClickListener(listener);
+        }
+    }
+
+    private ListBox createColorList(String caption) {
+        final ListBox lb = new ListBox();
+        lb.addChangeListener(listener);
+        lb.setVisibleItemCount(1);
+
+        lb.addItem(caption);
+        lb.addItem(strings.white(), "white");
+        lb.addItem(strings.black(), "black");
+        lb.addItem(strings.red(), "red");
+        lb.addItem(strings.green(), "green");
+        lb.addItem(strings.yellow(), "yellow");
+        lb.addItem(strings.blue(), "blue");
+        return lb;
+    }
+
+    private ListBox createFontList() {
+        final ListBox lb = new ListBox();
+        lb.addChangeListener(listener);
+        lb.setVisibleItemCount(1);
+
+        lb.addItem(strings.font(), "");
+        lb.addItem(strings.normal(), "");
+        lb.addItem("Times New Roman", "Times New Roman");
+        lb.addItem("Arial", "Arial");
+        lb.addItem("Courier New", "Courier New");
+        lb.addItem("Georgia", "Georgia");
+        lb.addItem("Trebuchet", "Trebuchet");
+        lb.addItem("Verdana", "Verdana");
+        return lb;
+    }
+
+    private ListBox createFontSizes() {
+        final ListBox lb = new ListBox();
+        lb.addChangeListener(listener);
+        lb.setVisibleItemCount(1);
+
+        lb.addItem(strings.size());
+        lb.addItem(strings.xxsmall());
+        lb.addItem(strings.xsmall());
+        lb.addItem(strings.small());
+        lb.addItem(strings.medium());
+        lb.addItem(strings.large());
+        lb.addItem(strings.xlarge());
+        lb.addItem(strings.xxlarge());
+        return lb;
+    }
+
+    private PushButton createPushButton(AbstractImagePrototype img, String tip) {
+        final PushButton pb = new PushButton(img.createImage());
+        pb.addClickListener(listener);
+        pb.setTitle(tip);
+        return pb;
+    }
+
+    private ToggleButton createToggleButton(AbstractImagePrototype img,
+            String tip) {
+        final ToggleButton tb = new ToggleButton(img.createImage());
+        tb.addClickListener(listener);
+        tb.setTitle(tip);
+        return tb;
+    }
+
+    /**
+     * Updates the status of all the stateful buttons.
+     */
+    private void updateStatus() {
+        if (basic != null) {
+            bold.setDown(basic.isBold());
+            italic.setDown(basic.isItalic());
+            underline.setDown(basic.isUnderlined());
+            subscript.setDown(basic.isSubscript());
+            superscript.setDown(basic.isSuperscript());
+        }
+
+        if (extended != null) {
+            strikethrough.setDown(extended.isStrikethrough());
+        }
+    }
+}
index cf3f62eee4a0a160c3ee7457afe358fe582da02a..0852d7bc50c9143cc6a32257595a8bb74d719e19 100644 (file)
@@ -9,7 +9,7 @@ import java.util.Map;
 
 import com.vaadin.terminal.PaintException;
 import com.vaadin.terminal.PaintTarget;
-import com.vaadin.terminal.gwt.client.ui.IAbsoluteLayout;
+import com.vaadin.terminal.gwt.client.ui.VAbsoluteLayout;
 
 /**
  * AbsoluteLayout is a layout implementation that mimics html absolute
@@ -28,7 +28,7 @@ public class AbsoluteLayout extends AbstractLayout {
 
     @Override
     public String getTag() {
-        return IAbsoluteLayout.TAGNAME;
+        return VAbsoluteLayout.TAGNAME;
     }
 
     public Iterator<Component> getComponentIterator() {
index fc88187c066373e1415411c9c1fb34e6b3cbdfc7..d782efbb13749f86cb68c9456eb6b50eb77b7644 100644 (file)
@@ -109,7 +109,7 @@ public class DateField extends AbstractField {
     private String dateFormat;
 
     /**
-     * Read-only content of an ITextualDate field - null for other types of date
+     * Read-only content of an VTextualDate field - null for other types of date
      * fields.
      */
     private String dateString;
index 935ae363b538d699dbc0f336eb37414ddaeb215c..f735b860236df809b26755ad07405d687597f3f5 100644 (file)
@@ -6,7 +6,7 @@ package com.vaadin.ui;
 
 import java.io.Serializable;
 
-import com.vaadin.terminal.gwt.client.ui.IMarginInfo;
+import com.vaadin.terminal.gwt.client.ui.VMarginInfo;
 import com.vaadin.terminal.gwt.client.ui.AlignmentInfo.Bits;
 
 /**
@@ -224,7 +224,7 @@ public interface Layout extends ComponentContainer, Serializable {
     }
 
     @SuppressWarnings("serial")
-    public static class MarginInfo extends IMarginInfo implements Serializable {
+    public static class MarginInfo extends VMarginInfo implements Serializable {
 
         public MarginInfo(boolean enabled) {
             super(enabled, enabled, enabled, enabled);