]> source.dussan.org Git - vaadin-framework.git/commitdiff
Split VScrollTable, VTreeTable and VMenuBar into paintable and
authorArtur Signell <artur@vaadin.com>
Thu, 26 Jan 2012 12:33:28 +0000 (14:33 +0200)
committerArtur Signell <artur@vaadin.com>
Thu, 26 Jan 2012 12:33:28 +0000 (14:33 +0200)
widget classes. Improved VAbstractPaintable

21 files changed:
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/client/Container.java
src/com/vaadin/terminal/gwt/client/Util.java
src/com/vaadin/terminal/gwt/client/VPaintable.java
src/com/vaadin/terminal/gwt/client/VPaintableMap.java
src/com/vaadin/terminal/gwt/client/VPaintableWidget.java
src/com/vaadin/terminal/gwt/client/ui/ShortcutActionHandler.java
src/com/vaadin/terminal/gwt/client/ui/VAbstractPaintableWidget.java
src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
src/com/vaadin/terminal/gwt/client/ui/VMenuBar.java
src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VUpload.java
src/com/vaadin/terminal/gwt/client/ui/label/VLabel.java
src/com/vaadin/terminal/gwt/client/ui/label/VLabelPaintable.java
src/com/vaadin/ui/MenuBar.java
src/com/vaadin/ui/Table.java
src/com/vaadin/ui/TreeTable.java

index f8ca0a6959c3ff0730b0d0e1411fc9d15b78c8c5..9b756382f365e1a9df61cfaba9925dbab9dac7e4 100644 (file)
@@ -36,6 +36,7 @@ import com.vaadin.terminal.gwt.client.ApplicationConfiguration.ErrorMessage;
 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.VAbstractPaintableWidget;
 import com.vaadin.terminal.gwt.client.ui.VContextMenu;
 import com.vaadin.terminal.gwt.client.ui.VNotification;
 import com.vaadin.terminal.gwt.client.ui.VNotification.HideEvent;
@@ -1586,9 +1587,10 @@ public class ApplicationConnection {
      * 
      * @return Returns true iff no further painting is needed by caller
      */
-    public boolean updateComponent(Widget component, UIDL uidl,
+    @Deprecated
+    public boolean updateComponent(VPaintableWidget paintable, UIDL uidl,
             boolean manageCaption) {
-        VPaintableWidget paintable = paintableMap.getPaintable(component);
+        Widget component = paintable.getWidgetForPaintable();
 
         String pid = paintableMap.getPid(paintable);
         if (pid == null) {
@@ -2029,6 +2031,10 @@ public class ApplicationConnection {
         if (!paintableMap.hasPaintable(pid)) {
             // Create and register a new paintable if no old was found
             VPaintableWidget p = widgetSet.createWidget(uidl, configuration);
+            if (p instanceof VAbstractPaintableWidget) {
+                ((VAbstractPaintableWidget) p).setConnection(this);
+                ((VAbstractPaintableWidget) p).init();
+            }
             paintableMap.registerPaintable(pid, p);
         }
         return (VPaintableWidget) paintableMap.getPaintable(pid);
@@ -2192,7 +2198,7 @@ public class ApplicationConnection {
         }
     };
 
-    private VPaintableMap paintableMap = new VPaintableMap();
+    private VPaintableMap paintableMap = GWT.create(VPaintableMap.class);
 
     /**
      * Components can call this function to run all layout functions. This is
@@ -2275,7 +2281,7 @@ public class ApplicationConnection {
      * @return true if at least one listener has been registered on server side
      *         for the event identified by eventIdentifier.
      */
-    public boolean hasEventListeners(VPaintable paintable,
+    public boolean hasEventListeners(VPaintableWidget paintable,
             String eventIdentifier) {
         return paintableMap.hasEventListeners(paintable, eventIdentifier);
     }
@@ -2330,4 +2336,31 @@ public class ApplicationConnection {
         paintableMap.unregisterPaintable(p);
     }
 
+    public VTooltip getVTooltip() {
+        return tooltip;
+    }
+
+    @Deprecated
+    public void handleWidgetTooltipEvent(Event event, Widget owner, Object key) {
+        handleTooltipEvent(event, getPaintableMap().getPaintable(owner), key);
+
+    }
+
+    @Deprecated
+    public void handleWidgetTooltipEvent(Event event, Widget owner) {
+        handleTooltipEvent(event, getPaintableMap().getPaintable(owner));
+
+    }
+
+    @Deprecated
+    public void registerWidgetTooltip(Widget owner, Object key, TooltipInfo info) {
+        registerTooltip(getPaintableMap().getPaintable(owner), key, info);
+    }
+
+    @Deprecated
+    public boolean hasWidgetEventListeners(Widget widget, String eventIdentifier) {
+        return hasEventListeners(getPaintableMap().getPaintable(widget),
+                eventIdentifier);
+    }
+
 }
index 7c92bc261bcc16fa9357e0801c5499340a57e5ba..db6bbf0ee40c1aa58378197637ae59b9ec190b91 100644 (file)
@@ -42,12 +42,12 @@ public interface Container extends VPaintableWidget {
      * must provide service for it's childen to show those elements for them.
      * </p>
      * 
-     * @param component
+     * @param paintable
      *            Child component for which service is requested.
      * @param uidl
      *            UIDL of the child component.
      */
-    void updateCaption(VPaintableWidget component, UIDL uidl);
+    void updateCaption(VPaintableWidget paintable, UIDL uidl);
 
     /**
      * Called when a child components size has been updated in the rendering
index 597ca3d49ca43bbc4fdc50a5151ba16c981a91b0..2a3fc07195b184c29564f55220a68dd9b61bc963 100644 (file)
@@ -829,6 +829,24 @@ public class Util {
         }
     }-*/;
 
+    /**
+     * Helper method to find the nearest parent paintable instance by traversing
+     * the DOM upwards from given element.
+     * 
+     * @param element
+     *            the element to start from
+     */
+    public static VPaintableWidget findPaintable(ApplicationConnection client,
+            Element element) {
+        Widget widget = Util.findWidget(element, null);
+        VPaintableMap vPaintableMap = VPaintableMap.get(client);
+        while (widget != null && !vPaintableMap.isPaintable(widget)) {
+            widget = widget.getParent();
+        }
+        return vPaintableMap.getPaintable(widget);
+
+    }
+
     /**
      * Helper method to find first instance of given Widget type found by
      * traversing DOM upwards from given element.
index 02b529b428d6af97313d2f12a1e10072a58142d0..d85c6d33e24065ac230fd8b978c75d4d23488d65 100644 (file)
@@ -4,8 +4,13 @@
 package com.vaadin.terminal.gwt.client;\r
 \r
 /**\r
- * TODO\r
+ * Interface implemented by all client side classes that can be communicate with\r
+ * the server. Classes implementing this interface are initialized by the\r
+ * framework when needed and have the ability to communicate with the server.\r
  * \r
+ * @author Vaadin Ltd\r
+ * @version @VERSION@\r
+ * @since 7.0.0\r
  */\r
 public interface VPaintable {\r
     /**\r
@@ -16,4 +21,54 @@ public interface VPaintable {
      */\r
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client);\r
 \r
+    // /**\r
+    // * Returns the id for this VPaintable. This must always be what has been\r
+    // set\r
+    // * using {@link #setId(String)}.\r
+    // *\r
+    // * @return The id for the VPaintable.\r
+    // */\r
+    // public String getId();\r
+    //\r
+    // /**\r
+    // * Sets the id for the VPaintable. This method is called once by the\r
+    // * framework when the VPaintable is initialized and should never be called\r
+    // * otherwise.\r
+    // * <p>\r
+    // * The VPaintable id is used to map the server and the client paintables\r
+    // * together. It is unique in this root and assigned by the framework.\r
+    // * </p>\r
+    // *\r
+    // * @param id\r
+    // * The id of the paintable.\r
+    // */\r
+    // public void setId(String id);\r
+\r
+    /**\r
+     * Gets ApplicationConnection instance that created this VPaintable.\r
+     * \r
+     * @return The ApplicationConnection as set by\r
+     *         {@link #setConnection(ApplicationConnection)}\r
+     */\r
+    // public ApplicationConnection getConnection();\r
+\r
+    /**\r
+     * Sets the reference to ApplicationConnection. This method is called by the\r
+     * framework when the VPaintable is created and should never be called\r
+     * otherwise.\r
+     * \r
+     * @param connection\r
+     *            The ApplicationConnection that created this VPaintable\r
+     */\r
+    // public void setConnection(ApplicationConnection connection);\r
+\r
+    /**\r
+     * Tests whether the component is enabled or not. A user can not interact\r
+     * with disabled components. Disabled components are rendered in a style\r
+     * that indicates the status, usually in gray color. Children of a disabled\r
+     * component are also disabled.\r
+     * \r
+     * @return true if the component is enabled, false otherwise\r
+     */\r
+    // public boolean isEnabled();\r
 }\r
index ef355d3cad92c86c68edfa798a72e8f2e9cb0916..f21d85558c2776703b0ed4a64201f3a09db0aac0 100644 (file)
@@ -335,7 +335,7 @@ public class VPaintableMap {
 \r
     }\r
 \r
-    private ComponentDetail getComponentDetail(VPaintable paintable) {\r
+    private ComponentDetail getComponentDetail(VPaintableWidget paintable) {\r
         return idToComponentDetail.get(getPid(paintable));\r
     }\r
 \r
@@ -344,7 +344,7 @@ public class VPaintableMap {
     }\r
 \r
     /**\r
-     * FIXME: Should not be here\r
+     * FIXME: Should be moved to VAbstractPaintableWidget\r
      * \r
      * @param paintable\r
      * @return\r
@@ -354,6 +354,11 @@ public class VPaintableMap {
         return getComponentDetail(paintable).getTooltipInfo(key);\r
     }\r
 \r
+    @Deprecated\r
+    public TooltipInfo getWidgetTooltipInfo(Widget widget, Object key) {\r
+        return getTooltipInfo(getPaintable(widget), key);\r
+    }\r
+\r
     public Collection<? extends VPaintable> getPaintables() {\r
         return Collections.unmodifiableCollection(paintableToId.keySet());\r
     }\r
@@ -378,7 +383,7 @@ public class VPaintableMap {
      * @return\r
      */\r
     @Deprecated\r
-    public boolean hasEventListeners(VPaintable paintable,\r
+    public boolean hasEventListeners(VPaintableWidget paintable,\r
             String eventIdentifier) {\r
         return getComponentDetail(paintable).hasEventListeners(eventIdentifier);\r
     }\r
index 9171fdcedad94923084a25488da10af3ab647cce..2f0cae1cc1eca9c0153fffb0ce89a6cab8edefd3 100644 (file)
@@ -17,7 +17,8 @@ import com.google.gwt.user.client.ui.Widget;
 public interface VPaintableWidget extends VPaintable {
 
     /**
-     * TODO: Renamed to getWidget
+     * TODO: Rename to getWidget
      */
     public Widget getWidgetForPaintable();
+
 }
index 38f7878ba419aa5cc7e75e33cbfd1bfd2aa454f4..2bd578a45d27523b545b55a795aab6f322e9905a 100644 (file)
@@ -15,13 +15,11 @@ import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.HasWidgets;
 import com.google.gwt.user.client.ui.KeyboardListener;
 import com.google.gwt.user.client.ui.KeyboardListenerCollection;
-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.UIDL;
 import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VPaintableMap;
 import com.vaadin.terminal.gwt.client.VPaintableWidget;
 import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea;
 
@@ -137,12 +135,7 @@ public class ShortcutActionHandler {
             VPaintableWidget target) {
         final Element et = DOM.eventGetTarget(event);
         if (target == null) {
-            Widget w = Util.findWidget(et, null);
-            VPaintableMap paintableMap = VPaintableMap.get(client);
-            while (w != null && !paintableMap.isPaintable(w)) {
-                w = w.getParent();
-            }
-            target = paintableMap.getPaintable(w);
+            target = Util.findPaintable(client, et);
         }
         final VPaintableWidget finalTarget = target;
 
index dff5a286ba92ca8e1b6c1ff7a5bfb94ffa09ab50..d4c8f7946701eeb7f19cd59fecda74d65da38ece 100644 (file)
@@ -1,12 +1,16 @@
 package com.vaadin.terminal.gwt.client.ui;\r
 \r
-import com.google.gwt.core.client.GWT;\r
 import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
 import com.vaadin.terminal.gwt.client.VPaintableWidget;\r
 \r
 public abstract class VAbstractPaintableWidget implements VPaintableWidget {\r
 \r
     private Widget widget;\r
+    private ApplicationConnection connection;\r
+\r
+    /* State variables */\r
+//    private boolean enabled = true;\r
 \r
     /**\r
      * Default constructor\r
@@ -14,15 +18,19 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget {
     public VAbstractPaintableWidget() {\r
     }\r
 \r
+    /**\r
+     * Called after the application connection reference has been set up\r
+     */\r
+    public void init() {\r
+    }\r
+\r
     /**\r
      * Creates and returns the widget for this VPaintableWidget. This method\r
      * should only be called once when initializing the paintable.\r
      * \r
      * @return\r
      */\r
-    protected Widget createWidget() {\r
-        return GWT.create(getWidgetClass());\r
-    }\r
+    protected abstract Widget createWidget();\r
 \r
     /**\r
      * Returns the widget associated with this paintable. The widget returned by\r
@@ -38,12 +46,27 @@ public abstract class VAbstractPaintableWidget implements VPaintableWidget {
         return widget;\r
     }\r
 \r
-    /**\r
-     * Returns the class of the widget for this paintable. Used to instansiate\r
-     * the widget.\r
+    /*\r
+     * (non-Javadoc)\r
+     * \r
+     * @see com.vaadin.terminal.gwt.client.VPaintable#getConnection()\r
+     */\r
+    public final ApplicationConnection getConnection() {\r
+        return connection;\r
+    }\r
+\r
+    /*\r
+     * (non-Javadoc)\r
      * \r
-     * @return The widget class.\r
+     * @see\r
+     * com.vaadin.terminal.gwt.client.VPaintable#setConnection(com.vaadin.terminal\r
+     * .gwt.client.ApplicationConnection)\r
      */\r
-    protected abstract Class<? extends Widget> getWidgetClass();\r
+    public final void setConnection(ApplicationConnection connection) {\r
+        this.connection = connection;\r
+    }\r
 \r
+//    public boolean isEnabled() {\r
+//        return enabled;\r
+//    }\r
 }\r
index da916f262e0c92e8f44149fc3a3e6afaaf596188..3251a03d6afad2535f57e4d2312c873b1f8d4852 100644 (file)
@@ -113,14 +113,9 @@ public class VDragAndDropWrapper extends VCustomComponent implements
             VTransferable transferable = new VTransferable();
             transferable.setDragSource(VDragAndDropWrapper.this);
 
-            Widget widget = Util.findWidget((Element) event.getEventTarget()
-                    .cast(), null);
-            VPaintableMap vPaintableMap = VPaintableMap.get(client);
-            while (widget != null && !vPaintableMap.isPaintable(widget)) {
-                widget = widget.getParent();
-            }
-            VPaintableWidget paintable = vPaintableMap.getPaintable(widget);
-
+            VPaintableWidget paintable = Util.findPaintable(client,
+                    (Element) event.getEventTarget().cast());
+            Widget widget = paintable.getWidgetForPaintable();
             transferable.setData("component", paintable);
             VDragEvent dragEvent = VDragAndDropManager.get().startDrag(
                     transferable, event, true);
index 306086e35777941a66ae2f10f0c25d4ce99780fb..372ddf25d21cf773dbc63edbc1920ec5d5737857 100644 (file)
@@ -4,9 +4,7 @@
 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.core.client.GWT;
 import com.google.gwt.core.client.Scheduler;
@@ -35,14 +33,12 @@ 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.VPaintableMap;
 import com.vaadin.terminal.gwt.client.TooltipInfo;
 import com.vaadin.terminal.gwt.client.UIDL;
 import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VPaintableWidget;
 import com.vaadin.terminal.gwt.client.VTooltip;
 
-public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
+public class VMenuBar extends SimpleFocusablePanel implements
         CloseHandler<PopupPanel>, ContainerResizedListener, KeyPressHandler,
         KeyDownHandler, FocusHandler, SubPartAware {
 
@@ -82,7 +78,7 @@ public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
     protected VMenuBar parentMenu;
     protected CustomMenuItem selected;
 
-    private boolean enabled = true;
+    boolean enabled = true;
 
     private String width = "notinited";
 
@@ -94,9 +90,9 @@ public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
                 }
             });
 
-    private boolean openRootOnHover;
+    boolean openRootOnHover;
 
-    private boolean htmlContentAllowed;
+    boolean htmlContentAllowed;
 
     public VMenuBar() {
         // Create an empty horizontal menubar
@@ -167,133 +163,6 @@ public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
         }
     }
 
-    /**
-     * 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;
-        }
-
-        htmlContentAllowed = uidl.hasAttribute(HTML_CONTENT_ALLOWED);
-
-        openRootOnHover = uidl.getBooleanAttribute(OPEN_ROOT_MENU_ON_HOWER);
-
-        enabled = !uidl.getBooleanAttribute("disabled");
-
-        // 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 (uidl.hasAttribute("width")) {
-            UIDL moreItemUIDL = options.getChildUIDL(0);
-            StringBuffer itemHTML = new StringBuffer();
-
-            if (moreItemUIDL.hasAttribute("icon")) {
-                itemHTML.append("<img src=\""
-                        + Util.escapeAttribute(client
-                                .translateVaadinUri(moreItemUIDL
-                                        .getStringAttribute("icon")))
-                        + "\" class=\"" + Icon.CLASSNAME + "\" alt=\"\" />");
-            }
-
-            String moreItemText = moreItemUIDL.getStringAttribute("text");
-            if ("".equals(moreItemText)) {
-                moreItemText = "&#x25BA;";
-            }
-            itemHTML.append(moreItemText);
-
-            moreItem = GWT.create(CustomMenuItem.class);
-            moreItem.setHTML(itemHTML.toString());
-            moreItem.setCommand(emptyCommand);
-
-            collapsedRootItems = new VMenuBar(true, (VMenuBar) VPaintableMap
-                    .get(client).getPaintable(uidlId));
-            moreItem.setSubMenu(collapsedRootItems);
-            moreItem.addStyleName(CLASSNAME + "-more-menuitem");
-        }
-
-        UIDL uidlItems = uidl.getChildUIDL(1);
-        Iterator<Object> itr = uidlItems.getChildIterator();
-        Stack<Iterator<Object>> iteratorStack = new Stack<Iterator<Object>>();
-        Stack<VMenuBar> menuStack = new Stack<VMenuBar>();
-        VMenuBar currentMenu = this;
-
-        while (itr.hasNext()) {
-            UIDL item = (UIDL) itr.next();
-            CustomMenuItem currentItem = null;
-
-            final int itemId = item.getIntAttribute("id");
-
-            boolean itemHasCommand = item.hasAttribute("command");
-            boolean itemIsCheckable = item.hasAttribute(ATTRIBUTE_CHECKED);
-
-            String itemHTML = buildItemHTML(item);
-
-            Command cmd = null;
-            if (!item.hasAttribute("separator")) {
-                if (itemHasCommand || itemIsCheckable) {
-                    // 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);
-            currentItem.updateFromUIDL(item, client);
-
-            if (item.getChildCount() > 0) {
-                menuStack.push(currentMenu);
-                iteratorStack.push(itr);
-                itr = item.getChildIterator();
-                currentMenu = new VMenuBar(true, currentMenu);
-                if (uidl.hasAttribute("style")) {
-                    for (String style : uidl.getStringAttribute("style").split(
-                            " ")) {
-                        currentMenu.addStyleDependentName(style);
-                    }
-                }
-                currentItem.setSubMenu(currentMenu);
-            }
-
-            while (!itr.hasNext() && !iteratorStack.empty()) {
-                boolean hasCheckableItem = false;
-                for (CustomMenuItem menuItem : currentMenu.getItems()) {
-                    hasCheckableItem = hasCheckableItem
-                            || menuItem.isCheckable();
-                }
-                if (hasCheckableItem) {
-                    currentMenu.addStyleDependentName("check-column");
-                } else {
-                    currentMenu.removeStyleDependentName("check-column");
-                }
-
-                itr = iteratorStack.pop();
-                currentMenu = menuStack.pop();
-            }
-        }// while
-
-        iLayout(false);
-
-    }// updateFromUIDL
-
     /**
      * Build the HTML content for a menu item.
      * 
@@ -473,7 +342,7 @@ public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
         // Handle tooltips
         if (targetItem == null && client != null) {
             // Handle root menubar tooltips
-            client.handleTooltipEvent(e, this);
+            client.handleWidgetTooltipEvent(e, this);
         } else if (targetItem != null) {
             // Handle item tooltips
             targetItem.onBrowserEvent(e);
@@ -1051,7 +920,7 @@ public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
                 TooltipInfo info = new TooltipInfo(description);
 
                 VMenuBar root = findRootMenu();
-                client.registerTooltip(root, this, info);
+                client.registerWidgetTooltip(root, this, info);
             }
         }
 
@@ -1059,7 +928,7 @@ public class VMenuBar extends SimpleFocusablePanel implements VPaintableWidget,
         public void onBrowserEvent(Event event) {
             super.onBrowserEvent(event);
             if (client != null) {
-                client.handleTooltipEvent(event, findRootMenu(), this);
+                client.handleWidgetTooltipEvent(event, findRootMenu(), this);
             }
         }
 
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VMenuBarPaintable.java
new file mode 100644 (file)
index 0000000..38b3cac
--- /dev/null
@@ -0,0 +1,161 @@
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import java.util.Iterator;\r
+import java.util.Stack;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.user.client.Command;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+import com.vaadin.terminal.gwt.client.Util;\r
+import com.vaadin.terminal.gwt.client.VPaintableMap;\r
+import com.vaadin.terminal.gwt.client.ui.VMenuBar.CustomMenuItem;\r
+\r
+public class VMenuBarPaintable extends VAbstractPaintableWidget {\r
+    /**\r
+     * This method must be implemented to update the client-side component from\r
+     * UIDL data received from server.\r
+     * \r
+     * This method is called when the page is loaded for the first time, and\r
+     * every time UI changes in the component are received from the server.\r
+     */\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        // This call should be made first. Ensure correct implementation,\r
+        // and let the containing layout manage caption, etc.\r
+        if (client.updateComponent(this, uidl, true)) {\r
+            return;\r
+        }\r
+\r
+        getWidgetForPaintable().htmlContentAllowed = uidl\r
+                .hasAttribute(VMenuBar.HTML_CONTENT_ALLOWED);\r
+\r
+        getWidgetForPaintable().openRootOnHover = uidl\r
+                .getBooleanAttribute(VMenuBar.OPEN_ROOT_MENU_ON_HOWER);\r
+\r
+        getWidgetForPaintable().enabled = !uidl.getBooleanAttribute("disabled");\r
+\r
+        // For future connections\r
+        getWidgetForPaintable().client = client;\r
+        getWidgetForPaintable().uidlId = uidl.getId();\r
+\r
+        // Empty the menu every time it receives new information\r
+        if (!getWidgetForPaintable().getItems().isEmpty()) {\r
+            getWidgetForPaintable().clearItems();\r
+        }\r
+\r
+        UIDL options = uidl.getChildUIDL(0);\r
+\r
+        if (uidl.hasAttribute("width")) {\r
+            UIDL moreItemUIDL = options.getChildUIDL(0);\r
+            StringBuffer itemHTML = new StringBuffer();\r
+\r
+            if (moreItemUIDL.hasAttribute("icon")) {\r
+                itemHTML.append("<img src=\""\r
+                        + Util.escapeAttribute(client\r
+                                .translateVaadinUri(moreItemUIDL\r
+                                        .getStringAttribute("icon")))\r
+                        + "\" class=\"" + Icon.CLASSNAME + "\" alt=\"\" />");\r
+            }\r
+\r
+            String moreItemText = moreItemUIDL.getStringAttribute("text");\r
+            if ("".equals(moreItemText)) {\r
+                moreItemText = "&#x25BA;";\r
+            }\r
+            itemHTML.append(moreItemText);\r
+\r
+            getWidgetForPaintable().moreItem = GWT.create(CustomMenuItem.class);\r
+            getWidgetForPaintable().moreItem.setHTML(itemHTML.toString());\r
+            getWidgetForPaintable().moreItem\r
+                    .setCommand(getWidgetForPaintable().emptyCommand);\r
+\r
+            getWidgetForPaintable().collapsedRootItems = new VMenuBar(true,\r
+                    (VMenuBar) VPaintableMap.get(client).getPaintable(\r
+                            getWidgetForPaintable().uidlId));\r
+            getWidgetForPaintable().moreItem\r
+                    .setSubMenu(getWidgetForPaintable().collapsedRootItems);\r
+            getWidgetForPaintable().moreItem.addStyleName(VMenuBar.CLASSNAME\r
+                    + "-more-menuitem");\r
+        }\r
+\r
+        UIDL uidlItems = uidl.getChildUIDL(1);\r
+        Iterator<Object> itr = uidlItems.getChildIterator();\r
+        Stack<Iterator<Object>> iteratorStack = new Stack<Iterator<Object>>();\r
+        Stack<VMenuBar> menuStack = new Stack<VMenuBar>();\r
+        VMenuBar currentMenu = getWidgetForPaintable();\r
+\r
+        while (itr.hasNext()) {\r
+            UIDL item = (UIDL) itr.next();\r
+            CustomMenuItem currentItem = null;\r
+\r
+            final int itemId = item.getIntAttribute("id");\r
+\r
+            boolean itemHasCommand = item.hasAttribute("command");\r
+            boolean itemIsCheckable = item\r
+                    .hasAttribute(VMenuBar.ATTRIBUTE_CHECKED);\r
+\r
+            String itemHTML = getWidgetForPaintable().buildItemHTML(item);\r
+\r
+            Command cmd = null;\r
+            if (!item.hasAttribute("separator")) {\r
+                if (itemHasCommand || itemIsCheckable) {\r
+                    // Construct a command that fires onMenuClick(int) with the\r
+                    // item's id-number\r
+                    cmd = new Command() {\r
+                        public void execute() {\r
+                            getWidgetForPaintable().hostReference\r
+                                    .onMenuClick(itemId);\r
+                        }\r
+                    };\r
+                }\r
+            }\r
+\r
+            currentItem = currentMenu.addItem(itemHTML.toString(), cmd);\r
+            currentItem.updateFromUIDL(item, client);\r
+\r
+            if (item.getChildCount() > 0) {\r
+                menuStack.push(currentMenu);\r
+                iteratorStack.push(itr);\r
+                itr = item.getChildIterator();\r
+                currentMenu = new VMenuBar(true, currentMenu);\r
+                if (uidl.hasAttribute("style")) {\r
+                    for (String style : uidl.getStringAttribute("style").split(\r
+                            " ")) {\r
+                        currentMenu.addStyleDependentName(style);\r
+                    }\r
+                }\r
+                currentItem.setSubMenu(currentMenu);\r
+            }\r
+\r
+            while (!itr.hasNext() && !iteratorStack.empty()) {\r
+                boolean hasCheckableItem = false;\r
+                for (CustomMenuItem menuItem : currentMenu.getItems()) {\r
+                    hasCheckableItem = hasCheckableItem\r
+                            || menuItem.isCheckable();\r
+                }\r
+                if (hasCheckableItem) {\r
+                    currentMenu.addStyleDependentName("check-column");\r
+                } else {\r
+                    currentMenu.removeStyleDependentName("check-column");\r
+                }\r
+\r
+                itr = iteratorStack.pop();\r
+                currentMenu = menuStack.pop();\r
+            }\r
+        }// while\r
+\r
+        getWidgetForPaintable().iLayout(false);\r
+\r
+    }// updateFromUIDL\r
+\r
+    @Override\r
+    protected Widget createWidget() {\r
+        return GWT.create(VMenuBar.class);\r
+    }\r
+\r
+    @Override\r
+    public VMenuBar getWidgetForPaintable() {\r
+        return (VMenuBar) super.getWidgetForPaintable();\r
+    }\r
+\r
+}\r
index 736635ecd0c32236be316a499d8ab2a7fcbac091..41b7efcf02d78031b4714711bb244dd1b144ad2a 100644 (file)
@@ -52,6 +52,7 @@ 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.HasWidgets;
 import com.google.gwt.user.client.ui.Panel;
 import com.google.gwt.user.client.ui.RootPanel;
 import com.google.gwt.user.client.ui.UIObject;
@@ -103,17 +104,31 @@ import com.vaadin.terminal.gwt.client.ui.label.VLabel;
  * 
  * TODO implement unregistering for child components in Cells
  */
-public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
-        VHasDropHandler, FocusHandler, BlurHandler, Focusable, ActionOwner {
+public class VScrollTable extends FlowPanel implements HasWidgets,
+        ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable,
+        ActionOwner {
 
-    public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft";
-    public static final String ATTRIBUTE_PAGEBUFFER_LAST = "pb-l";
+    public enum SelectMode {
+        NONE(0), SINGLE(1), MULTI(2);
+        private int id;
+
+        private SelectMode(int id) {
+            this.id = id;
+        }
+
+        public int getId() {
+            return id;
+        }
+    }
 
     private static final String ROW_HEADER_COLUMN_KEY = "0";
 
     public static final String CLASSNAME = "v-table";
     public static final String CLASSNAME_SELECTION_FOCUS = CLASSNAME + "-focus";
 
+    public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft";
+    public static final String ATTRIBUTE_PAGEBUFFER_LAST = "pb-l";
+
     public static final String ITEM_CLICK_EVENT_ID = "itemClick";
     public static final String HEADER_CLICK_EVENT_ID = "handleHeaderClick";
     public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick";
@@ -162,10 +177,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     protected ApplicationConnection client;
     protected String paintableId;
 
-    private boolean immediate;
+    boolean immediate;
     private boolean nullSelectionAllowed = true;
 
-    private int selectMode = Table.SELECT_MODE_NONE;
+    private SelectMode selectMode = SelectMode.NONE;
 
     private final HashSet<String> selectedRowKeys = new HashSet<String>();
 
@@ -178,15 +193,15 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     /*
      * These are used when jumping between pages when pressing Home and End
      */
-    private boolean selectLastItemInNextRender = false;
-    private boolean selectFirstItemInNextRender = false;
-    private boolean focusFirstItemInNextRender = false;
-    private boolean focusLastItemInNextRender = false;
+    boolean selectLastItemInNextRender = false;
+    boolean selectFirstItemInNextRender = false;
+    boolean focusFirstItemInNextRender = false;
+    boolean focusLastItemInNextRender = false;
 
     /*
      * The currently focused row
      */
-    private VScrollTableRow focusedRow;
+    VScrollTableRow focusedRow;
 
     /*
      * Helper to store selection range start in when using the keyboard
@@ -197,7 +212,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * Flag for notifying when the selection has changed and should be sent to
      * the server
      */
-    private boolean selectionChanged = false;
+    boolean selectionChanged = false;
 
     /*
      * The speed (in pixels) which the scrolling scrolls vertically/horizontally
@@ -206,7 +221,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
 
     private Timer scrollingVelocityTimer = null;
 
-    private String[] bodyActionKeys;
+    String[] bodyActionKeys;
 
     private boolean enableDebug = false;
 
@@ -282,19 +297,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
 
     private final HashSet<SelectionRange> selectedRowRanges = new HashSet<SelectionRange>();
 
-    private boolean initializedAndAttached = false;
+    boolean initializedAndAttached = false;
 
     /**
      * Flag to indicate if a column width recalculation is needed due update.
      */
-    private boolean headerChangedDuringUpdate = false;
+    boolean headerChangedDuringUpdate = false;
 
     protected final TableHead tHead = new TableHead();
 
-    private final TableFooter tFoot = new TableFooter();
+    final TableFooter tFoot = new TableFooter();
 
-    private final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(
-            true);
+    final FocusableScrollPanel scrollBodyPanel = new FocusableScrollPanel(true);
 
     private KeyPressHandler navKeyPressHandler = new KeyPressHandler() {
         public void onKeyPress(KeyPressEvent keyPressEvent) {
@@ -383,12 +397,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
             }
         }
     };
-    private int totalRows;
+    int totalRows;
 
     private Set<String> collapsedColumns;
 
-    private final RowRequestHandler rowRequestHandler;
-    private VScrollTableBody scrollBody;
+    final RowRequestHandler rowRequestHandler;
+    VScrollTableBody scrollBody;
     private int firstvisible = 0;
     private boolean sortAscending;
     private String sortColumn;
@@ -403,9 +417,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     private String[] visibleColOrder;
     private boolean initialContentReceived = false;
     private Element scrollPositionElement;
-    private boolean enabled;
-    private boolean showColHeaders;
-    private boolean showColFooters;
+    boolean enabled;
+    boolean showColHeaders;
+    boolean showColFooters;
 
     /** flag to indicate that table body has changed */
     private boolean isNewBody = true;
@@ -420,15 +434,15 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     private final ArrayList<Panel> lazyUnregistryBag = new ArrayList<Panel>();
     private String height;
     private String width = "";
-    private boolean rendering = false;
+    boolean rendering = false;
     private boolean hasFocus = false;
     private int dragmode;
 
     private int multiselectmode;
-    private int tabIndex;
+    int tabIndex;
     private TouchScrollDelegate touchScrollDelegate;
 
-    private int lastRenderedHeight;
+    int lastRenderedHeight;
 
     /**
      * Values (serverCacheFirst+serverCacheLast) sent by server that tells which
@@ -442,8 +456,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * scrolling in the client will cause empty buttons to be rendered
      * (cached=true request for non-existing components)
      */
-    private int serverCacheFirst = -1;
-    private int serverCacheLast = -1;
+    int serverCacheFirst = -1;
+    int serverCacheLast = -1;
 
     public VScrollTable() {
         setMultiSelectMode(MULTISELECT_MODE_DEFAULT);
@@ -810,211 +824,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         return KeyCodes.KEY_END;
     }
 
-    /*
-     * (non-Javadoc)
-     * 
-     * @see
-     * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal
-     * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)
-     */
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        rendering = true;
-
-        if (uidl.hasAttribute(ATTRIBUTE_PAGEBUFFER_FIRST)) {
-            serverCacheFirst = uidl.getIntAttribute(ATTRIBUTE_PAGEBUFFER_FIRST);
-            serverCacheLast = uidl.getIntAttribute(ATTRIBUTE_PAGEBUFFER_LAST);
-        } else {
-            serverCacheFirst = -1;
-            serverCacheLast = -1;
-        }
-        /*
-         * We need to do this before updateComponent since updateComponent calls
-         * this.setHeight() which will calculate a new body height depending on
-         * the space available.
-         */
-        if (uidl.hasAttribute("colfooters")) {
-            showColFooters = uidl.getBooleanAttribute("colfooters");
-        }
-
-        tFoot.setVisible(showColFooters);
-
-        if (client.updateComponent(this, uidl, true)) {
-            rendering = false;
-            return;
-        }
-
-        enabled = !uidl.hasAttribute("disabled");
-
-        if (BrowserInfo.get().isIE8() && !enabled) {
-            /*
-             * The disabled shim will not cover the table body if it is relative
-             * in IE8. See #7324
-             */
-            scrollBodyPanel.getElement().getStyle()
-                    .setPosition(Position.STATIC);
-        } else if (BrowserInfo.get().isIE8()) {
-            scrollBodyPanel.getElement().getStyle()
-                    .setPosition(Position.RELATIVE);
-        }
-
-        this.client = client;
-        paintableId = uidl.getStringAttribute("id");
-        immediate = uidl.getBooleanAttribute("immediate");
-
-        int previousTotalRows = totalRows;
-        updateTotalRows(uidl);
-        boolean totalRowsChanged = (totalRows != previousTotalRows);
-
-        updateDragMode(uidl);
-
-        updateSelectionProperties(uidl);
-
-        if (uidl.hasAttribute("alb")) {
-            bodyActionKeys = uidl.getStringArrayAttribute("alb");
-        } else {
-            // Need to clear the actions if the action handlers have been
-            // removed
-            bodyActionKeys = null;
-        }
-
-        setCacheRateFromUIDL(uidl);
-
-        recalcWidths = uidl.hasAttribute("recalcWidths");
-        if (recalcWidths) {
-            tHead.clear();
-            tFoot.clear();
-        }
-
-        updatePageLength(uidl);
-
-        updateFirstVisibleAndScrollIfNeeded(uidl);
-
-        showRowHeaders = uidl.getBooleanAttribute("rowheaders");
-        showColHeaders = uidl.getBooleanAttribute("colheaders");
-
-        updateSortingProperties(uidl);
-
-        boolean keyboardSelectionOverRowFetchInProgress = selectSelectedRows(uidl);
-
-        updateActionMap(uidl);
-
-        updateColumnProperties(uidl);
-
-        UIDL ac = uidl.getChildByTagName("-ac");
-        if (ac == null) {
-            if (dropHandler != null) {
-                // remove dropHandler if not present anymore
-                dropHandler = null;
-            }
-        } else {
-            if (dropHandler == null) {
-                dropHandler = new VScrollTableDropHandler();
-            }
-            dropHandler.updateAcceptRules(ac);
-        }
-
-        UIDL partialRowAdditions = uidl.getChildByTagName("prows");
-        UIDL partialRowUpdates = uidl.getChildByTagName("urows");
-        if (partialRowUpdates != null || partialRowAdditions != null) {
-            // we may have pending cache row fetch, cancel it. See #2136
-            rowRequestHandler.cancel();
-
-            updateRowsInBody(partialRowUpdates);
-            addAndRemoveRows(partialRowAdditions);
-        } else {
-            UIDL rowData = uidl.getChildByTagName("rows");
-            if (rowData != null) {
-                // we may have pending cache row fetch, cancel it. See #2136
-                rowRequestHandler.cancel();
-
-                if (!recalcWidths && initializedAndAttached) {
-                    updateBody(rowData, uidl.getIntAttribute("firstrow"),
-                            uidl.getIntAttribute("rows"));
-                    if (headerChangedDuringUpdate) {
-                        triggerLazyColumnAdjustment(true);
-                    } else if (!isScrollPositionVisible()
-                            || totalRowsChanged
-                            || lastRenderedHeight != scrollBody
-                                    .getOffsetHeight()) {
-                        // webkits may still bug with their disturbing scrollbar
-                        // bug, see #3457
-                        // Run overflow fix for the scrollable area
-                        // #6698 - If there's a scroll going on, don't abort it
-                        // by changing overflows as the length of the contents
-                        // *shouldn't* have changed (unless the number of rows
-                        // or the height of the widget has also changed)
-                        Scheduler.get().scheduleDeferred(new Command() {
-                            public void execute() {
-                                Util.runWebkitOverflowAutoFix(scrollBodyPanel
-                                        .getElement());
-                            }
-                        });
-                    }
-                } else {
-                    initializeRows(uidl, rowData);
-                }
-            }
-        }
-
-        if (!isSelectable()) {
-            scrollBody.addStyleName(CLASSNAME + "-body-noselection");
-        } else {
-            scrollBody.removeStyleName(CLASSNAME + "-body-noselection");
-        }
-
-        hideScrollPositionAnnotation();
-        purgeUnregistryBag();
-
-        // selection is no in sync with server, avoid excessive server visits by
-        // clearing to flag used during the normal operation
-        if (!keyboardSelectionOverRowFetchInProgress) {
-            selectionChanged = false;
-        }
-
-        /*
-         * This is called when the Home or page up button has been pressed in
-         * selectable mode and the next selected row was not yet rendered in the
-         * client
-         */
-        if (selectFirstItemInNextRender || focusFirstItemInNextRender) {
-            selectFirstRenderedRowInViewPort(focusFirstItemInNextRender);
-            selectFirstItemInNextRender = focusFirstItemInNextRender = false;
-        }
-
-        /*
-         * This is called when the page down or end button has been pressed in
-         * selectable mode and the next selected row was not yet rendered in the
-         * client
-         */
-        if (selectLastItemInNextRender || focusLastItemInNextRender) {
-            selectLastRenderedRowInViewPort(focusLastItemInNextRender);
-            selectLastItemInNextRender = focusLastItemInNextRender = false;
-        }
-        multiselectPending = false;
-
-        if (focusedRow != null) {
-            if (!focusedRow.isAttached() && !rowRequestHandler.isRunning()) {
-                // focused row has been orphaned, can't focus
-                focusRowFromBody();
-            }
-        }
-
-        tabIndex = uidl.hasAttribute("tabindex") ? uidl
-                .getIntAttribute("tabindex") : 0;
-        setProperTabIndex();
-
-        resizeSortedColumnForSortIndicator();
-
-        // Remember this to detect situations where overflow hack might be
-        // needed during scrolling
-        lastRenderedHeight = scrollBody.getOffsetHeight();
-
-        rendering = false;
-        headerChangedDuringUpdate = false;
-
-    }
-
-    private void initializeRows(UIDL uidl, UIDL rowData) {
+    void initializeRows(UIDL uidl, UIDL rowData) {
         if (scrollBody != null) {
             scrollBody.removeFromParent();
             lazyUnregistryBag.add(scrollBody);
@@ -1037,7 +847,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         scrollBody.restoreRowVisibility();
     }
 
-    private void updateColumnProperties(UIDL uidl) {
+    void updateColumnProperties(UIDL uidl) {
         updateColumnOrder(uidl);
 
         updateCollapsedColumns(uidl);
@@ -1072,7 +882,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         }
     }
 
-    private boolean selectSelectedRows(UIDL uidl) {
+    boolean selectSelectedRows(UIDL uidl) {
         boolean keyboardSelectionOverRowFetchInProgress = false;
 
         if (uidl.hasVariable("selected")) {
@@ -1109,7 +919,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         return keyboardSelectionOverRowFetchInProgress;
     }
 
-    private void updateSortingProperties(UIDL uidl) {
+    void updateSortingProperties(UIDL uidl) {
         oldSortColumn = sortColumn;
         if (uidl.hasVariable("sortascending")) {
             sortAscending = uidl.getBooleanVariable("sortascending");
@@ -1117,7 +927,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         }
     }
 
-    private void resizeSortedColumnForSortIndicator() {
+    void resizeSortedColumnForSortIndicator() {
         // Force recalculation of the captionContainer element inside the header
         // cell to accomodate for the size of the sort arrow.
         HeaderCell sortedHeader = tHead.getHeaderCell(sortColumn);
@@ -1132,7 +942,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         }
     }
 
-    private void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) {
+    void updateFirstVisibleAndScrollIfNeeded(UIDL uidl) {
         firstvisible = uidl.hasVariable("firstvisible") ? uidl
                 .getIntVariable("firstvisible") : 0;
         if (firstvisible != lastRequestedFirstvisible && scrollBody != null) {
@@ -1147,7 +957,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         return (int) (rowIx * scrollBody.getRowHeight());
     }
 
-    private void updatePageLength(UIDL uidl) {
+    void updatePageLength(UIDL uidl) {
         int oldPageLength = pageLength;
         if (uidl.hasAttribute("pagelength")) {
             pageLength = uidl.getIntAttribute("pagelength");
@@ -1162,7 +972,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         }
     }
 
-    private void updateSelectionProperties(UIDL uidl) {
+    void updateSelectionProperties(UIDL uidl) {
         setMultiSelectMode(uidl.hasAttribute("multiselectmode") ? uidl
                 .getIntAttribute("multiselectmode") : MULTISELECT_MODE_DEFAULT);
 
@@ -1171,18 +981,18 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
 
         if (uidl.hasAttribute("selectmode")) {
             if (uidl.getBooleanAttribute("readonly")) {
-                selectMode = Table.SELECT_MODE_NONE;
+                selectMode = SelectMode.NONE;
             } else if (uidl.getStringAttribute("selectmode").equals("multi")) {
-                selectMode = Table.SELECT_MODE_MULTI;
+                selectMode = SelectMode.MULTI;
             } else if (uidl.getStringAttribute("selectmode").equals("single")) {
-                selectMode = Table.SELECT_MODE_SINGLE;
+                selectMode = SelectMode.SINGLE;
             } else {
-                selectMode = Table.SELECT_MODE_NONE;
+                selectMode = SelectMode.NONE;
             }
         }
     }
 
-    private void updateDragMode(UIDL uidl) {
+    void updateDragMode(UIDL uidl) {
         dragmode = uidl.hasAttribute("dragmode") ? uidl
                 .getIntAttribute("dragmode") : 0;
         if (BrowserInfo.get().isIE()) {
@@ -1219,7 +1029,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         return totalRows;
     }
 
-    private void focusRowFromBody() {
+    void focusRowFromBody() {
         if (selectedRowKeys.size() == 1) {
             // try to focus a row currently selected and in viewport
             String selectedRowKey = selectedRowKeys.iterator().next();
@@ -1247,7 +1057,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * @param focusOnly
      *            Should the focus only be moved to the last row
      */
-    private void selectLastRenderedRowInViewPort(boolean focusOnly) {
+    void selectLastRenderedRowInViewPort(boolean focusOnly) {
         int index = firstRowInViewPort + getFullyVisibleRowCount();
         VScrollTableRow lastRowInViewport = scrollBody.getRowByRowIndex(index);
         if (lastRowInViewport == null) {
@@ -1272,7 +1082,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * @param focusOnly
      *            Should the focus only be moved to the first row
      */
-    private void selectFirstRenderedRowInViewPort(boolean focusOnly) {
+    void selectFirstRenderedRowInViewPort(boolean focusOnly) {
         int index = firstRowInViewPort;
         VScrollTableRow firstInViewport = scrollBody.getRowByRowIndex(index);
         if (firstInViewport == null) {
@@ -1286,7 +1096,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         }
     }
 
-    private void setCacheRateFromUIDL(UIDL uidl) {
+    void setCacheRateFromUIDL(UIDL uidl) {
         setCacheRate(uidl.hasAttribute("cr") ? uidl.getDoubleAttribute("cr")
                 : CACHE_RATE_DEFAULT);
     }
@@ -1303,7 +1113,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * IScrollTableRows). This is done lazily as Table must survive from
      * "subtreecaching" logic.
      */
-    private void purgeUnregistryBag() {
+    void purgeUnregistryBag() {
         for (Iterator<Panel> iterator = lazyUnregistryBag.iterator(); iterator
                 .hasNext();) {
             VPaintableMap.get(client)
@@ -1312,7 +1122,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         lazyUnregistryBag.clear();
     }
 
-    private void updateActionMap(UIDL mainUidl) {
+    void updateActionMap(UIDL mainUidl) {
         UIDL actionsUidl = mainUidl.getChildByTagName("actions");
         if (actionsUidl == null) {
             return;
@@ -1414,7 +1224,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * @param reqRows
      *            amount of rows in data set
      */
-    private void updateBody(UIDL uidl, int firstRow, int reqRows) {
+    void updateBody(UIDL uidl, int firstRow, int reqRows) {
         if (uidl == null || reqRows < 1) {
             // container is empty, remove possibly existing rows
             if (firstRow <= 0) {
@@ -1431,7 +1241,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         discardRowsOutsideCacheWindow();
     }
 
-    private void updateRowsInBody(UIDL partialRowUpdates) {
+    void updateRowsInBody(UIDL partialRowUpdates) {
         if (partialRowUpdates == null) {
             return;
         }
@@ -1564,20 +1374,20 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     }
 
     private boolean isMultiSelectModeSimple() {
-        return selectMode == Table.SELECT_MODE_MULTI
+        return selectMode == SelectMode.MULTI
                 && multiselectmode == MULTISELECT_MODE_SIMPLE;
     }
 
     private boolean isSingleSelectMode() {
-        return selectMode == Table.SELECT_MODE_SINGLE;
+        return selectMode == SelectMode.SINGLE;
     }
 
     private boolean isMultiSelectModeAny() {
-        return selectMode == Table.SELECT_MODE_MULTI;
+        return selectMode == SelectMode.MULTI;
     }
 
     private boolean isMultiSelectModeDefault() {
-        return selectMode == Table.SELECT_MODE_MULTI
+        return selectMode == SelectMode.MULTI
                 && multiselectmode == MULTISELECT_MODE_DEFAULT;
     }
 
@@ -1593,7 +1403,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     }
 
     protected boolean isSelectable() {
-        return selectMode > Table.SELECT_MODE_NONE;
+        return selectMode.getId() > SelectMode.NONE.getId();
     }
 
     private boolean isCollapsedColumn(String colKey) {
@@ -1769,7 +1579,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
             }
         }
         client.updateVariable(paintableId, "columnorder", columnOrder, false);
-        if (client.hasEventListeners(this, COLUMN_REORDER_EVENT_ID)) {
+        if (client.hasWidgetEventListeners(this, COLUMN_REORDER_EVENT_ID)) {
             client.sendPendingVariableChanges();
         }
     }
@@ -2108,19 +1918,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
         style.setDisplay(Display.BLOCK);
     }
 
-    private void hideScrollPositionAnnotation() {
+    void hideScrollPositionAnnotation() {
         if (scrollPositionElement != null) {
             DOM.setStyleAttribute(scrollPositionElement, "display", "none");
         }
     }
 
-    private boolean isScrollPositionVisible() {
+    boolean isScrollPositionVisible() {
         return scrollPositionElement != null
                 && !scrollPositionElement.getStyle().getDisplay()
                         .equals(Display.NONE.toString());
     }
 
-    private class RowRequestHandler extends Timer {
+    class RowRequestHandler extends Timer {
 
         private int reqFirstRow = 0;
         private int reqRows = 0;
@@ -2512,7 +2322,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
          *            The click event
          */
         private void fireHeaderClickedEvent(Event event) {
-            if (client.hasEventListeners(VScrollTable.this,
+            if (client.hasWidgetEventListeners(VScrollTable.this,
                     HEADER_CLICK_EVENT_ID)) {
                 MouseEventDetails details = new MouseEventDetails(event);
                 client.updateVariable(paintableId, "headerClickEvent",
@@ -3543,7 +3353,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
          *            The click event
          */
         private void fireFooterClickedEvent(Event event) {
-            if (client.hasEventListeners(VScrollTable.this,
+            if (client.hasWidgetEventListeners(VScrollTable.this,
                     FOOTER_CLICK_EVENT_ID)) {
                 MouseEventDetails details = new MouseEventDetails(event);
                 client.updateVariable(paintableId, "footerClickEvent",
@@ -4295,12 +4105,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
             final VScrollTableRow toBeRemoved = (VScrollTableRow) renderedRows
                     .get(index);
             // Unregister row tooltip
-            client.registerTooltip(VScrollTable.this, toBeRemoved.getElement(),
-                    null);
+            client.registerWidgetTooltip(VScrollTable.this,
+                    toBeRemoved.getElement(), null);
             for (int i = 0; i < toBeRemoved.getElement().getChildCount(); i++) {
                 // Unregister cell tooltips
                 Element td = toBeRemoved.getElement().getChild(i).cast();
-                client.registerTooltip(VScrollTable.this, td, null);
+                client.registerWidgetTooltip(VScrollTable.this, td, null);
             }
             lazyUnregistryBag.add(toBeRemoved);
             tBodyElement.removeChild(toBeRemoved.getElement());
@@ -4559,10 +4369,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
                 String rowDescription = uidl.getStringAttribute("rowdescr");
                 if (rowDescription != null && !rowDescription.equals("")) {
                     TooltipInfo info = new TooltipInfo(rowDescription);
-                    client.registerTooltip(VScrollTable.this, rowElement, info);
+                    client.registerWidgetTooltip(VScrollTable.this, rowElement,
+                            info);
                 } else {
                     // Remove possibly previously set tooltip
-                    client.registerTooltip(VScrollTable.this, rowElement, null);
+                    client.registerWidgetTooltip(VScrollTable.this, rowElement,
+                            null);
                 }
 
                 tHead.getColumnAlignments();
@@ -4797,10 +4609,10 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
 
                 if (description != null && !description.equals("")) {
                     TooltipInfo info = new TooltipInfo(description);
-                    client.registerTooltip(VScrollTable.this, td, info);
+                    client.registerWidgetTooltip(VScrollTable.this, td, info);
                 } else {
                     // Remove possibly previously set tooltip
-                    client.registerTooltip(VScrollTable.this, td, null);
+                    client.registerWidgetTooltip(VScrollTable.this, td, null);
                 }
 
                 td.appendChild(container);
@@ -4879,7 +4691,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
              */
             private boolean handleClickEvent(Event event, Element targetTdOrTr,
                     boolean immediate) {
-                if (!client.hasEventListeners(VScrollTable.this,
+                if (!client.hasWidgetEventListeners(VScrollTable.this,
                         ITEM_CLICK_EVENT_ID)) {
                     // Don't send an event if nobody is listening
                     return false;
@@ -4923,22 +4735,24 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
 
                     if (!containsWidget) {
                         // Only text nodes has tooltips
-                        if (client.getTooltipTitleInfo(VScrollTable.this,
-                                target) != null) {
+                        if (VPaintableMap.get(client).getWidgetTooltipInfo(
+                                VScrollTable.this, target) != null) {
                             // Cell has description, use it
-                            client.handleTooltipEvent(event, VScrollTable.this,
-                                    target);
+                            client.handleWidgetTooltipEvent(event,
+                                    VScrollTable.this, target);
                         } else {
                             // Cell might have row description, use row
                             // description
-                            client.handleTooltipEvent(event, VScrollTable.this,
+                            client.handleWidgetTooltipEvent(event,
+                                    VScrollTable.this,
                                     target.getParentElement());
                         }
                     }
 
                 } else {
                     // Table row (tr)
-                    client.handleTooltipEvent(event, VScrollTable.this, target);
+                    client.handleWidgetTooltipEvent(event, VScrollTable.this,
+                            target);
                 }
             }
 
@@ -4954,7 +4768,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
                         showContextMenu(event);
                         if (enabled
                                 && (actionKeys != null || client
-                                        .hasEventListeners(VScrollTable.this,
+                                        .hasWidgetEventListeners(
+                                                VScrollTable.this,
                                                 ITEM_CLICK_EVENT_ID))) {
                             /*
                              * Prevent browser context menu only if there are
@@ -5243,7 +5058,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
                     Element targetTdOrTr) {
                 mDown = true;
                 VTransferable transferable = new VTransferable();
-                transferable.setDragSource(VScrollTable.this);
+                transferable.setDragSource(VPaintableMap.get(client)
+                        .getPaintable(VScrollTable.this));
                 transferable.setData("itemId", "" + rowKey);
                 NodeList<TableCellElement> cells = rowElement.getCells();
                 for (int i = 0; i < cells.getLength(); i++) {
@@ -5972,9 +5788,9 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
     private int contentAreaBorderHeight = -1;
     private int scrollLeft;
     private int scrollTop;
-    private VScrollTableDropHandler dropHandler;
+    VScrollTableDropHandler dropHandler;
     private boolean navKeyDown;
-    private boolean multiselectPending;
+    boolean multiselectPending;
 
     /**
      * @return border top + border bottom of the scrollable area of table
@@ -6315,7 +6131,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
 
         @Override
         public VPaintableWidget getPaintable() {
-            return VScrollTable.this;
+            return VPaintableMap.get(client).getPaintable(VScrollTable.this);
         }
 
         public ApplicationConnection getApplicationConnection() {
@@ -6752,7 +6568,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
      * actions may need focus.
      * 
      */
-    private void setProperTabIndex() {
+    void setProperTabIndex() {
         int storedScrollTop = 0;
         int storedScrollLeft = 0;
 
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTablePaintable.java
new file mode 100644 (file)
index 0000000..c747a29
--- /dev/null
@@ -0,0 +1,251 @@
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.core.client.Scheduler;\r
+import com.google.gwt.dom.client.Style.Position;\r
+import com.google.gwt.user.client.Command;\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.UIDL;\r
+import com.vaadin.terminal.gwt.client.Util;\r
+\r
+public class VScrollTablePaintable extends VAbstractPaintableWidget {\r
+\r
+    /*\r
+     * (non-Javadoc)\r
+     * \r
+     * @see\r
+     * com.vaadin.terminal.gwt.client.Paintable#updateFromUIDL(com.vaadin.terminal\r
+     * .gwt.client.UIDL, com.vaadin.terminal.gwt.client.ApplicationConnection)\r
+     */\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        getWidgetForPaintable().rendering = true;\r
+\r
+        if (uidl.hasAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST)) {\r
+            getWidgetForPaintable().serverCacheFirst = uidl\r
+                    .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST);\r
+            getWidgetForPaintable().serverCacheLast = uidl\r
+                    .getIntAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_LAST);\r
+        } else {\r
+            getWidgetForPaintable().serverCacheFirst = -1;\r
+            getWidgetForPaintable().serverCacheLast = -1;\r
+        }\r
+        /*\r
+         * We need to do this before updateComponent since updateComponent calls\r
+         * this.setHeight() which will calculate a new body height depending on\r
+         * the space available.\r
+         */\r
+        if (uidl.hasAttribute("colfooters")) {\r
+            getWidgetForPaintable().showColFooters = uidl\r
+                    .getBooleanAttribute("colfooters");\r
+        }\r
+\r
+        getWidgetForPaintable().tFoot\r
+                .setVisible(getWidgetForPaintable().showColFooters);\r
+\r
+        if (client.updateComponent(this, uidl, true)) {\r
+            getWidgetForPaintable().rendering = false;\r
+            return;\r
+        }\r
+\r
+        getWidgetForPaintable().enabled = !uidl.hasAttribute("disabled");\r
+\r
+        if (BrowserInfo.get().isIE8() && !getWidgetForPaintable().enabled) {\r
+            /*\r
+             * The disabled shim will not cover the table body if it is relative\r
+             * in IE8. See #7324\r
+             */\r
+            getWidgetForPaintable().scrollBodyPanel.getElement().getStyle()\r
+                    .setPosition(Position.STATIC);\r
+        } else if (BrowserInfo.get().isIE8()) {\r
+            getWidgetForPaintable().scrollBodyPanel.getElement().getStyle()\r
+                    .setPosition(Position.RELATIVE);\r
+        }\r
+\r
+        getWidgetForPaintable().client = client;\r
+        getWidgetForPaintable().paintableId = uidl.getStringAttribute("id");\r
+        getWidgetForPaintable().immediate = uidl\r
+                .getBooleanAttribute("immediate");\r
+\r
+        int previousTotalRows = getWidgetForPaintable().totalRows;\r
+        getWidgetForPaintable().updateTotalRows(uidl);\r
+        boolean totalRowsChanged = (getWidgetForPaintable().totalRows != previousTotalRows);\r
+\r
+        getWidgetForPaintable().updateDragMode(uidl);\r
+\r
+        getWidgetForPaintable().updateSelectionProperties(uidl);\r
+\r
+        if (uidl.hasAttribute("alb")) {\r
+            getWidgetForPaintable().bodyActionKeys = uidl\r
+                    .getStringArrayAttribute("alb");\r
+        } else {\r
+            // Need to clear the actions if the action handlers have been\r
+            // removed\r
+            getWidgetForPaintable().bodyActionKeys = null;\r
+        }\r
+\r
+        getWidgetForPaintable().setCacheRateFromUIDL(uidl);\r
+\r
+        getWidgetForPaintable().recalcWidths = uidl\r
+                .hasAttribute("recalcWidths");\r
+        if (getWidgetForPaintable().recalcWidths) {\r
+            getWidgetForPaintable().tHead.clear();\r
+            getWidgetForPaintable().tFoot.clear();\r
+        }\r
+\r
+        getWidgetForPaintable().updatePageLength(uidl);\r
+\r
+        getWidgetForPaintable().updateFirstVisibleAndScrollIfNeeded(uidl);\r
+\r
+        getWidgetForPaintable().showRowHeaders = uidl\r
+                .getBooleanAttribute("rowheaders");\r
+        getWidgetForPaintable().showColHeaders = uidl\r
+                .getBooleanAttribute("colheaders");\r
+\r
+        getWidgetForPaintable().updateSortingProperties(uidl);\r
+\r
+        boolean keyboardSelectionOverRowFetchInProgress = getWidgetForPaintable()\r
+                .selectSelectedRows(uidl);\r
+\r
+        getWidgetForPaintable().updateActionMap(uidl);\r
+\r
+        getWidgetForPaintable().updateColumnProperties(uidl);\r
+\r
+        UIDL ac = uidl.getChildByTagName("-ac");\r
+        if (ac == null) {\r
+            if (getWidgetForPaintable().dropHandler != null) {\r
+                // remove dropHandler if not present anymore\r
+                getWidgetForPaintable().dropHandler = null;\r
+            }\r
+        } else {\r
+            if (getWidgetForPaintable().dropHandler == null) {\r
+                getWidgetForPaintable().dropHandler = getWidgetForPaintable().new VScrollTableDropHandler();\r
+            }\r
+            getWidgetForPaintable().dropHandler.updateAcceptRules(ac);\r
+        }\r
+\r
+        UIDL partialRowAdditions = uidl.getChildByTagName("prows");\r
+        UIDL partialRowUpdates = uidl.getChildByTagName("urows");\r
+        if (partialRowUpdates != null || partialRowAdditions != null) {\r
+            // we may have pending cache row fetch, cancel it. See #2136\r
+            getWidgetForPaintable().rowRequestHandler.cancel();\r
+\r
+            getWidgetForPaintable().updateRowsInBody(partialRowUpdates);\r
+            getWidgetForPaintable().addAndRemoveRows(partialRowAdditions);\r
+        } else {\r
+            UIDL rowData = uidl.getChildByTagName("rows");\r
+            if (rowData != null) {\r
+                // we may have pending cache row fetch, cancel it. See #2136\r
+                getWidgetForPaintable().rowRequestHandler.cancel();\r
+\r
+                if (!getWidgetForPaintable().recalcWidths\r
+                        && getWidgetForPaintable().initializedAndAttached) {\r
+                    getWidgetForPaintable().updateBody(rowData,\r
+                            uidl.getIntAttribute("firstrow"),\r
+                            uidl.getIntAttribute("rows"));\r
+                    if (getWidgetForPaintable().headerChangedDuringUpdate) {\r
+                        getWidgetForPaintable().triggerLazyColumnAdjustment(\r
+                                true);\r
+                    } else if (!getWidgetForPaintable()\r
+                            .isScrollPositionVisible()\r
+                            || totalRowsChanged\r
+                            || getWidgetForPaintable().lastRenderedHeight != getWidgetForPaintable().scrollBody\r
+                                    .getOffsetHeight()) {\r
+                        // webkits may still bug with their disturbing scrollbar\r
+                        // bug, see #3457\r
+                        // Run overflow fix for the scrollable area\r
+                        // #6698 - If there's a scroll going on, don't abort it\r
+                        // by changing overflows as the length of the contents\r
+                        // *shouldn't* have changed (unless the number of rows\r
+                        // or the height of the widget has also changed)\r
+                        Scheduler.get().scheduleDeferred(new Command() {\r
+                            public void execute() {\r
+                                Util.runWebkitOverflowAutoFix(getWidgetForPaintable().scrollBodyPanel\r
+                                        .getElement());\r
+                            }\r
+                        });\r
+                    }\r
+                } else {\r
+                    getWidgetForPaintable().initializeRows(uidl, rowData);\r
+                }\r
+            }\r
+        }\r
+\r
+        if (!getWidgetForPaintable().isSelectable()) {\r
+            getWidgetForPaintable().scrollBody\r
+                    .addStyleName(VScrollTable.CLASSNAME + "-body-noselection");\r
+        } else {\r
+            getWidgetForPaintable().scrollBody\r
+                    .removeStyleName(VScrollTable.CLASSNAME\r
+                            + "-body-noselection");\r
+        }\r
+\r
+        getWidgetForPaintable().hideScrollPositionAnnotation();\r
+        getWidgetForPaintable().purgeUnregistryBag();\r
+\r
+        // selection is no in sync with server, avoid excessive server visits by\r
+        // clearing to flag used during the normal operation\r
+        if (!keyboardSelectionOverRowFetchInProgress) {\r
+            getWidgetForPaintable().selectionChanged = false;\r
+        }\r
+\r
+        /*\r
+         * This is called when the Home or page up button has been pressed in\r
+         * selectable mode and the next selected row was not yet rendered in the\r
+         * client\r
+         */\r
+        if (getWidgetForPaintable().selectFirstItemInNextRender\r
+                || getWidgetForPaintable().focusFirstItemInNextRender) {\r
+            getWidgetForPaintable().selectFirstRenderedRowInViewPort(\r
+                    getWidgetForPaintable().focusFirstItemInNextRender);\r
+            getWidgetForPaintable().selectFirstItemInNextRender = getWidgetForPaintable().focusFirstItemInNextRender = false;\r
+        }\r
+\r
+        /*\r
+         * This is called when the page down or end button has been pressed in\r
+         * selectable mode and the next selected row was not yet rendered in the\r
+         * client\r
+         */\r
+        if (getWidgetForPaintable().selectLastItemInNextRender\r
+                || getWidgetForPaintable().focusLastItemInNextRender) {\r
+            getWidgetForPaintable().selectLastRenderedRowInViewPort(\r
+                    getWidgetForPaintable().focusLastItemInNextRender);\r
+            getWidgetForPaintable().selectLastItemInNextRender = getWidgetForPaintable().focusLastItemInNextRender = false;\r
+        }\r
+        getWidgetForPaintable().multiselectPending = false;\r
+\r
+        if (getWidgetForPaintable().focusedRow != null) {\r
+            if (!getWidgetForPaintable().focusedRow.isAttached()\r
+                    && !getWidgetForPaintable().rowRequestHandler.isRunning()) {\r
+                // focused row has been orphaned, can't focus\r
+                getWidgetForPaintable().focusRowFromBody();\r
+            }\r
+        }\r
+\r
+        getWidgetForPaintable().tabIndex = uidl.hasAttribute("tabindex") ? uidl\r
+                .getIntAttribute("tabindex") : 0;\r
+        getWidgetForPaintable().setProperTabIndex();\r
+\r
+        getWidgetForPaintable().resizeSortedColumnForSortIndicator();\r
+\r
+        // Remember this to detect situations where overflow hack might be\r
+        // needed during scrolling\r
+        getWidgetForPaintable().lastRenderedHeight = getWidgetForPaintable().scrollBody\r
+                .getOffsetHeight();\r
+\r
+        getWidgetForPaintable().rendering = false;\r
+        getWidgetForPaintable().headerChangedDuringUpdate = false;\r
+\r
+    }\r
+\r
+    @Override\r
+    protected Widget createWidget() {\r
+        return GWT.create(VScrollTable.class);\r
+    }\r
+\r
+    @Override\r
+    public VScrollTable getWidgetForPaintable() {\r
+        return (VScrollTable) super.getWidgetForPaintable();\r
+    }\r
+}\r
index 77dd1cc39e1f927aad16f45c9c8e1243cc650590..0eddca0ed33818822b73ec71e0f9b6e14073c304 100644 (file)
@@ -24,21 +24,19 @@ 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.Widget;
-import com.vaadin.terminal.gwt.client.ApplicationConnection;
 import com.vaadin.terminal.gwt.client.BrowserInfo;
 import com.vaadin.terminal.gwt.client.ComputedStyle;
 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;
 import com.vaadin.terminal.gwt.client.ui.VTreeTable.VTreeTableScrollBody.VTreeTableRow;
 
 public class VTreeTable extends VScrollTable {
 
-    private static class PendingNavigationEvent {
-        private final int keycode;
-        private final boolean ctrl;
-        private final boolean shift;
+    static class PendingNavigationEvent {
+        final int keycode;
+        final boolean ctrl;
+        final boolean shift;
 
         public PendingNavigationEvent(int keycode, boolean ctrl, boolean shift) {
             this.keycode = keycode;
@@ -59,82 +57,14 @@ public class VTreeTable extends VScrollTable {
         }
     }
 
-    public static final String ATTRIBUTE_HIERARCHY_COLUMN_INDEX = "hci";
-    private boolean collapseRequest;
+    boolean collapseRequest;
     private boolean selectionPending;
-    private int colIndexOfHierarchy;
-    private String collapsedRowKey;
-    private VTreeTableScrollBody scrollBody;
-    private boolean animationsEnabled;
-    private LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTable.PendingNavigationEvent>();
-    private boolean focusParentResponsePending;
-
-    @Override
-    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        FocusableScrollPanel widget = null;
-        int scrollPosition = 0;
-        if (collapseRequest) {
-            widget = (FocusableScrollPanel) getWidget(1);
-            scrollPosition = widget.getScrollPosition();
-        }
-        animationsEnabled = uidl.getBooleanAttribute("animate");
-        colIndexOfHierarchy = uidl
-                .hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl
-                .getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0;
-        int oldTotalRows = getTotalRows();
-        super.updateFromUIDL(uidl, client);
-        if (collapseRequest) {
-            if (collapsedRowKey != null && scrollBody != null) {
-                VScrollTableRow row = getRenderedRowByKey(collapsedRowKey);
-                if (row != null) {
-                    setRowFocus(row);
-                    focus();
-                }
-            }
-
-            int scrollPosition2 = widget.getScrollPosition();
-            if (scrollPosition != scrollPosition2) {
-                widget.setScrollPosition(scrollPosition);
-            }
-
-            // check which rows are needed from the server and initiate a
-            // deferred fetch
-            onScroll(null);
-        }
-        // Recalculate table size if collapse request, or if page length is zero
-        // (not sent by server) and row count changes (#7908).
-        if (collapseRequest
-                || (!uidl.hasAttribute("pagelength") && getTotalRows() != oldTotalRows)) {
-            /*
-             * Ensure that possibly removed/added scrollbars are considered.
-             * Triggers row calculations, removes cached rows etc. Basically
-             * cleans up state. Be careful if touching this, you will break
-             * pageLength=0 if you remove this.
-             */
-            triggerLazyColumnAdjustment(true);
-
-            collapseRequest = false;
-        }
-        if (uidl.hasAttribute("focusedRow")) {
-            String key = uidl.getStringAttribute("focusedRow");
-            setRowFocus(getRenderedRowByKey(key));
-            focusParentResponsePending = false;
-        } else if (uidl.hasAttribute("clearFocusPending")) {
-            // Special case to detect a response to a focusParent request that
-            // does not return any focusedRow because the selected node has no
-            // parent
-            focusParentResponsePending = false;
-        }
-
-        while (!collapseRequest && !focusParentResponsePending
-                && !pendingNavigationEvents.isEmpty()) {
-            // Keep replaying any queued events as long as we don't have any
-            // potential content changes pending
-            PendingNavigationEvent event = pendingNavigationEvents
-                    .removeFirst();
-            handleNavigation(event.keycode, event.ctrl, event.shift);
-        }
-    }
+    int colIndexOfHierarchy;
+    String collapsedRowKey;
+    VTreeTableScrollBody scrollBody;
+    boolean animationsEnabled;
+    LinkedList<PendingNavigationEvent> pendingNavigationEvents = new LinkedList<VTreeTable.PendingNavigationEvent>();
+    boolean focusParentResponsePending;
 
     @Override
     protected VScrollTableBody createScrollBody() {
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java b/src/com/vaadin/terminal/gwt/client/ui/VTreeTablePaintable.java
new file mode 100644 (file)
index 0000000..8fec055
--- /dev/null
@@ -0,0 +1,98 @@
+package com.vaadin.terminal.gwt.client.ui;\r
+\r
+import com.google.gwt.core.client.GWT;\r
+import com.google.gwt.user.client.ui.Widget;\r
+import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
+import com.vaadin.terminal.gwt.client.UIDL;\r
+import com.vaadin.terminal.gwt.client.ui.VScrollTable.VScrollTableBody.VScrollTableRow;\r
+import com.vaadin.terminal.gwt.client.ui.VTreeTable.PendingNavigationEvent;\r
+\r
+public class VTreeTablePaintable extends VScrollTablePaintable {\r
+    public static final String ATTRIBUTE_HIERARCHY_COLUMN_INDEX = "hci";\r
+\r
+    @Override\r
+    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
+        FocusableScrollPanel widget = null;\r
+        int scrollPosition = 0;\r
+        if (getWidgetForPaintable().collapseRequest) {\r
+            widget = (FocusableScrollPanel) getWidgetForPaintable()\r
+                    .getWidget(1);\r
+            scrollPosition = widget.getScrollPosition();\r
+        }\r
+        getWidgetForPaintable().animationsEnabled = uidl\r
+                .getBooleanAttribute("animate");\r
+        getWidgetForPaintable().colIndexOfHierarchy = uidl\r
+                .hasAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) ? uidl\r
+                .getIntAttribute(ATTRIBUTE_HIERARCHY_COLUMN_INDEX) : 0;\r
+        int oldTotalRows = getWidgetForPaintable().getTotalRows();\r
+        super.updateFromUIDL(uidl, client);\r
+        if (getWidgetForPaintable().collapseRequest) {\r
+            if (getWidgetForPaintable().collapsedRowKey != null\r
+                    && getWidgetForPaintable().scrollBody != null) {\r
+                VScrollTableRow row = getWidgetForPaintable()\r
+                        .getRenderedRowByKey(\r
+                                getWidgetForPaintable().collapsedRowKey);\r
+                if (row != null) {\r
+                    getWidgetForPaintable().setRowFocus(row);\r
+                    getWidgetForPaintable().focus();\r
+                }\r
+            }\r
+\r
+            int scrollPosition2 = widget.getScrollPosition();\r
+            if (scrollPosition != scrollPosition2) {\r
+                widget.setScrollPosition(scrollPosition);\r
+            }\r
+\r
+            // check which rows are needed from the server and initiate a\r
+            // deferred fetch\r
+            getWidgetForPaintable().onScroll(null);\r
+        }\r
+        // Recalculate table size if collapse request, or if page length is zero\r
+        // (not sent by server) and row count changes (#7908).\r
+        if (getWidgetForPaintable().collapseRequest\r
+                || (!uidl.hasAttribute("pagelength") && getWidgetForPaintable()\r
+                        .getTotalRows() != oldTotalRows)) {\r
+            /*\r
+             * Ensure that possibly removed/added scrollbars are considered.\r
+             * Triggers row calculations, removes cached rows etc. Basically\r
+             * cleans up state. Be careful if touching this, you will break\r
+             * pageLength=0 if you remove this.\r
+             */\r
+            getWidgetForPaintable().triggerLazyColumnAdjustment(true);\r
+\r
+            getWidgetForPaintable().collapseRequest = false;\r
+        }\r
+        if (uidl.hasAttribute("focusedRow")) {\r
+            String key = uidl.getStringAttribute("focusedRow");\r
+            getWidgetForPaintable().setRowFocus(\r
+                    getWidgetForPaintable().getRenderedRowByKey(key));\r
+            getWidgetForPaintable().focusParentResponsePending = false;\r
+        } else if (uidl.hasAttribute("clearFocusPending")) {\r
+            // Special case to detect a response to a focusParent request that\r
+            // does not return any focusedRow because the selected node has no\r
+            // parent\r
+            getWidgetForPaintable().focusParentResponsePending = false;\r
+        }\r
+\r
+        while (!getWidgetForPaintable().collapseRequest\r
+                && !getWidgetForPaintable().focusParentResponsePending\r
+                && !getWidgetForPaintable().pendingNavigationEvents.isEmpty()) {\r
+            // Keep replaying any queued events as long as we don't have any\r
+            // potential content changes pending\r
+            PendingNavigationEvent event = getWidgetForPaintable().pendingNavigationEvents\r
+                    .removeFirst();\r
+            getWidgetForPaintable().handleNavigation(event.keycode, event.ctrl,\r
+                    event.shift);\r
+        }\r
+    }\r
+\r
+    @Override\r
+    protected Widget createWidget() {\r
+        return GWT.create(VTreeTable.class);\r
+    }\r
+\r
+    @Override\r
+    public VTreeTable getWidgetForPaintable() {\r
+        return (VTreeTable) super.getWidgetForPaintable();\r
+    }\r
+}\r
index 3d49b8d9d103a7152e50d1059ee1c92e276b6f32..66894417f3ce9d5fbb8f821896c51e9dc8860140 100644 (file)
@@ -24,9 +24,9 @@ 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.VPaintableWidget;
 import com.vaadin.terminal.gwt.client.UIDL;
 import com.vaadin.terminal.gwt.client.VConsole;
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
 import com.vaadin.terminal.gwt.client.VTooltip;
 
 /**
index 09f435227dbdb8859d6ad2501c6a7c6fe056837c..8828582b5711201398a1c70045ce1a9f41b986b9 100644 (file)
@@ -34,15 +34,10 @@ public class VLabel extends HTML {
     public void onBrowserEvent(Event event) {
         super.onBrowserEvent(event);
         if (event.getTypeInt() == Event.ONLOAD) {
-            // FIXME: Should not be here but in paintable
             Util.notifyParentOfSizeChange(this, true);
-            event.cancelBubble(true);
+            event.stopPropagation();
             return;
         }
-        // FIXME: Move to paintable
-        // if (client != null) {
-        // client.handleTooltipEvent(event, this);
-        // }
     }
 
     @Override
index 796bce265e0c978173c649ef885c8f2497b80baf..269afde25d62a31de36ee5d4f8d0da10fa46d48a 100644 (file)
@@ -6,27 +6,21 @@ package com.vaadin.terminal.gwt.client.ui.label;
 import com.google.gwt.core.client.GWT;\r
 import com.google.gwt.dom.client.Document;\r
 import com.google.gwt.dom.client.PreElement;\r
+import com.google.gwt.user.client.ui.Widget;\r
 import com.vaadin.terminal.gwt.client.ApplicationConnection;\r
 import com.vaadin.terminal.gwt.client.UIDL;\r
 import com.vaadin.terminal.gwt.client.Util;\r
-import com.vaadin.terminal.gwt.client.VPaintableWidget;\r
-\r
-public class VLabelPaintable implements VPaintableWidget {\r
-\r
-    private VLabel widget = GWT.create(VLabel.class);\r
-    private ApplicationConnection client;\r
+import com.vaadin.terminal.gwt.client.ui.VAbstractPaintableWidget;\r
 \r
+public class VLabelPaintable extends VAbstractPaintableWidget {\r
     public VLabelPaintable() {\r
     }\r
 \r
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {\r
-\r
-        if (client.updateComponent(getWidgetForPaintable(), uidl, true)) {\r
+        if (client.updateComponent(this, uidl, true)) {\r
             return;\r
         }\r
 \r
-        this.client = client;\r
-\r
         boolean sinkOnloads = false;\r
 \r
         final String mode = uidl.getStringAttribute("mode");\r
@@ -64,8 +58,14 @@ public class VLabelPaintable implements VPaintableWidget {
         }\r
     }\r
 \r
+    @Override\r
+    protected Widget createWidget() {\r
+        return GWT.create(VLabel.class);\r
+    }\r
+\r
+    @Override\r
     public VLabel getWidgetForPaintable() {\r
-        return widget;\r
+        return (VLabel) super.getWidgetForPaintable();\r
     }\r
 \r
 }\r
index 7ed432a12b3c498745660de75f43a7f12be48982..54a094a4e75f1b99989f60156d7490d1171a34d2 100644 (file)
@@ -14,6 +14,7 @@ import com.vaadin.terminal.PaintException;
 import com.vaadin.terminal.PaintTarget;
 import com.vaadin.terminal.Resource;
 import com.vaadin.terminal.gwt.client.ui.VMenuBar;
+import com.vaadin.terminal.gwt.client.ui.VMenuBarPaintable;
 import com.vaadin.ui.ClientWidget.LoadStyle;
 
 /**
@@ -24,7 +25,7 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
  * </p>
  */
 @SuppressWarnings("serial")
-@ClientWidget(value = VMenuBar.class, loadStyle = LoadStyle.LAZY)
+@ClientWidget(value = VMenuBarPaintable.class, loadStyle = LoadStyle.LAZY)
 public class MenuBar extends AbstractComponent {
 
     // Items of the top-level menu
index 8b9dc3ef81144276165a5d815630a77747773caf..ec620ddcd5723b00cea9b905426844cf04c9a131 100644 (file)
@@ -47,6 +47,7 @@ import com.vaadin.terminal.PaintTarget;
 import com.vaadin.terminal.Resource;
 import com.vaadin.terminal.gwt.client.MouseEventDetails;
 import com.vaadin.terminal.gwt.client.ui.VScrollTable;
+import com.vaadin.terminal.gwt.client.ui.VScrollTablePaintable;
 import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
 
 /**
@@ -73,7 +74,7 @@ import com.vaadin.terminal.gwt.client.ui.dd.VLazyInitItemIdentifiers;
  * @since 3.0
  */
 @SuppressWarnings({ "deprecation" })
-@ClientWidget(VScrollTable.class)
+@ClientWidget(VScrollTablePaintable.class)
 public class Table extends AbstractSelect implements Action.Container,
         Container.Ordered, Container.Sortable, ItemClickSource,
         ItemClickNotifier, DragSource, DropTarget {
index 43bc7a80fe19c4917234e9baf027ab996fedce94..09417e1e16b71618abadd76ad7dc075f69132d0c 100644 (file)
@@ -22,7 +22,7 @@ import com.vaadin.data.util.HierarchicalContainer;
 import com.vaadin.terminal.PaintException;
 import com.vaadin.terminal.PaintTarget;
 import com.vaadin.terminal.Resource;
-import com.vaadin.terminal.gwt.client.ui.VTreeTable;
+import com.vaadin.terminal.gwt.client.ui.VTreeTablePaintable;
 import com.vaadin.ui.Tree.CollapseEvent;
 import com.vaadin.ui.Tree.CollapseListener;
 import com.vaadin.ui.Tree.ExpandEvent;
@@ -48,7 +48,7 @@ import com.vaadin.ui.treetable.HierarchicalContainerOrderedWrapper;
  * share UI state in the container.
  */
 @SuppressWarnings({ "serial" })
-@ClientWidget(VTreeTable.class)
+@ClientWidget(VTreeTablePaintable.class)
 public class TreeTable extends Table implements Hierarchical {
 
     private static final Logger logger = Logger.getLogger(TreeTable.class
@@ -454,7 +454,8 @@ public class TreeTable extends Table implements Hierarchical {
                 Object object = visibleColumns2[i];
                 if (hierarchyColumnId.equals(object)) {
                     target.addAttribute(
-                            VTreeTable.ATTRIBUTE_HIERARCHY_COLUMN_INDEX, i);
+                            VTreeTablePaintable.ATTRIBUTE_HIERARCHY_COLUMN_INDEX,
+                            i);
                     break;
                 }
             }