]> source.dussan.org Git - vaadin-framework.git/commitdiff
Update CssLayout to use MeasureManager (#8313)
authorLeif Åstrand <leif@vaadin.com>
Fri, 10 Feb 2012 09:29:40 +0000 (11:29 +0200)
committerLeif Åstrand <leif@vaadin.com>
Fri, 10 Feb 2012 09:29:40 +0000 (11:29 +0200)
WebContent/VAADIN/themes/base/panel/panel.css
WebContent/VAADIN/themes/reindeer/panel/panel.css
src/com/vaadin/terminal/gwt/client/MeasureManager.java
src/com/vaadin/terminal/gwt/client/ui/LayoutPhaseListener.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/ResizeRequired.java [new file with mode: 0644]
src/com/vaadin/terminal/gwt/client/ui/VPanel.java
src/com/vaadin/terminal/gwt/client/ui/VPanelPaintable.java
tests/testbench/com/vaadin/tests/components/panel/BasicPanelTest.java [new file with mode: 0644]

index 126d3da91cf39c7e68fb5d571ac8e817687e776e..5ef0d91e49203e1d9f4e4f4907d877fd5f57fa59 100644 (file)
@@ -30,6 +30,8 @@
 }
 .v-panel-content {
        overflow: auto;
+       box-sizing: border-box;
+       -moz-box-sizing: border-box;
 }
 .v-panel-deco {
 }
\ No newline at end of file
index ac0074a9e0869f7513216272ea8c20718b5d14bb..08f130271d34d4e57b3cdf70799ec68a3299f41e 100644 (file)
@@ -35,6 +35,7 @@
 .v-panel-content > div {
        background: #fff;
        min-height: 100%;
+       overflow: visible; /* min-height causes problems with borders and paddings if overflow is e.g. hidden */
 }
 .blue .v-panel-deco {
        border-color: #92a3ac;
index 0bffc7c032bfe124a3b9b096bb1e8827a1ccafbd..26f922ca5f82a13f5b0a3d020bc72f4575c62e21 100644 (file)
@@ -1,8 +1,8 @@
 package com.vaadin.terminal.gwt.client;
 
 import com.google.gwt.core.client.JsArrayString;
-import com.google.gwt.user.client.ui.RequiresResize;
-import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.terminal.gwt.client.ui.LayoutPhaseListener;
+import com.vaadin.terminal.gwt.client.ui.ResizeRequired;
 
 public class MeasureManager {
 
@@ -11,6 +11,12 @@ public class MeasureManager {
         VPaintableWidget[] paintableWidgets = paintableMap
                 .getRegisteredPaintableWidgets();
 
+        for (VPaintableWidget vPaintableWidget : paintableWidgets) {
+            if (vPaintableWidget instanceof LayoutPhaseListener) {
+                ((LayoutPhaseListener) vPaintableWidget).beforeLayout();
+            }
+        }
+
         int passes = 0;
         long start = System.currentTimeMillis();
         while (true) {
@@ -49,15 +55,12 @@ public class MeasureManager {
                 VPaintableWidget paintable = (VPaintableWidget) paintableMap
                         .getPaintable(pid);
                 if (!affectedContainers.contains(pid)) {
-                    Widget widget = paintable.getWidgetForPaintable();
-                    if (widget instanceof RequiresResize) {
-                        // TODO Do nothing here if parent instanceof
-                        // ProvidesRepaint?
-                        ((RequiresResize) widget).onResize();
-                    } else if (paintable instanceof CalculatingLayout) {
+                    if (paintable instanceof CalculatingLayout) {
                         CalculatingLayout calculating = (CalculatingLayout) paintable;
                         calculating.updateHorizontalSizes();
                         calculating.updateVerticalSizes();
+                    } else if (paintable instanceof ResizeRequired) {
+                        ((ResizeRequired) paintable).onResize();
                     }
                 }
             }
@@ -96,6 +99,13 @@ public class MeasureManager {
             }
             VConsole.log(b.toString());
         }
+
+        for (VPaintableWidget vPaintableWidget : paintableWidgets) {
+            if (vPaintableWidget instanceof LayoutPhaseListener) {
+                ((LayoutPhaseListener) vPaintableWidget).afterLayout();
+            }
+        }
+
         long end = System.currentTimeMillis();
         VConsole.log("Total layout time: " + (end - start) + "ms");
     }
diff --git a/src/com/vaadin/terminal/gwt/client/ui/LayoutPhaseListener.java b/src/com/vaadin/terminal/gwt/client/ui/LayoutPhaseListener.java
new file mode 100644 (file)
index 0000000..3ab7b8a
--- /dev/null
@@ -0,0 +1,7 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+public interface LayoutPhaseListener {
+    public void beforeLayout();
+
+    public void afterLayout();
+}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/ResizeRequired.java b/src/com/vaadin/terminal/gwt/client/ui/ResizeRequired.java
new file mode 100644 (file)
index 0000000..a03fff0
--- /dev/null
@@ -0,0 +1,7 @@
+package com.vaadin.terminal.gwt.client.ui;
+
+import com.vaadin.terminal.gwt.client.VPaintableWidget;
+
+public interface ResizeRequired extends VPaintableWidget {
+    public void onResize();
+}
index 82b362a385dbdcef29c563d3d9100034b3de2a29..45ded13d00fac6143caa4d08c3f8e9c2b2a0f542 100644 (file)
@@ -4,8 +4,6 @@
 
 package com.vaadin.terminal.gwt.client.ui;
 
-import java.util.Set;
-
 import com.google.gwt.dom.client.DivElement;
 import com.google.gwt.dom.client.Document;
 import com.google.gwt.event.dom.client.TouchStartEvent;
@@ -14,21 +12,14 @@ import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.Event;
 import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
-import com.vaadin.terminal.gwt.client.BrowserInfo;
-import com.vaadin.terminal.gwt.client.Container;
 import com.vaadin.terminal.gwt.client.Focusable;
-import com.vaadin.terminal.gwt.client.RenderInformation;
-import com.vaadin.terminal.gwt.client.RenderSpace;
 import com.vaadin.terminal.gwt.client.UIDL;
-import com.vaadin.terminal.gwt.client.Util;
-import com.vaadin.terminal.gwt.client.VPaintableMap;
 import com.vaadin.terminal.gwt.client.VPaintableWidget;
 import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner;
 
-public class VPanel extends SimplePanel implements Container,
-        ShortcutActionHandlerOwner, Focusable {
+public class VPanel extends SimplePanel implements ShortcutActionHandlerOwner,
+        Focusable {
 
     public static final String CLASSNAME = "v-panel";
 
@@ -48,36 +39,16 @@ public class VPanel extends SimplePanel implements Container,
 
     private Element errorIndicatorElement;
 
-    private String height;
-
     VPaintableWidget layout;
 
     ShortcutActionHandler shortcutHandler;
 
     private String width = "";
 
-    private Element geckoCaptionMeter;
-
     int scrollTop;
 
     int scrollLeft;
 
-    private RenderInformation renderInformation = new RenderInformation();
-
-    private int borderPaddingHorizontal = -1;
-
-    private int borderPaddingVertical = -1;
-
-    private int captionPaddingHorizontal = -1;
-
-    private int captionMarginLeft = -1;
-
-    boolean rendering;
-
-    private int contentMarginLeft = -1;
-
-    private String previousStyleName;
-
     private TouchScrollDelegate touchScrollDelegate;
 
     public VPanel() {
@@ -106,7 +77,6 @@ public class VPanel extends SimplePanel implements Container,
         setStyleName(CLASSNAME);
         DOM.sinkEvents(getElement(), Event.ONKEYDOWN);
         DOM.sinkEvents(contentNode, Event.ONSCROLL | Event.TOUCHEVENTS);
-        contentNode.getStyle().setProperty("position", "relative");
         getElement().getStyle().setProperty("overflow", "hidden");
         addHandler(new TouchStartHandler() {
             public void onTouchStart(TouchStartEvent event) {
@@ -148,15 +118,6 @@ public class VPanel extends SimplePanel implements Container,
         DOM.setInnerHTML(captionText, text);
     }
 
-    @Override
-    public void setStyleName(String style) {
-        if (!style.equals(previousStyleName)) {
-            super.setStyleName(style);
-            detectContainerBorders();
-            previousStyleName = style;
-        }
-    }
-
     void handleError(UIDL uidl) {
         if (uidl.hasAttribute("error")) {
             if (errorIndicatorElement == null) {
@@ -190,54 +151,6 @@ public class VPanel extends SimplePanel implements Container,
         }
     }
 
-    public void runHacks(boolean runGeckoFix) {
-        if ((BrowserInfo.get().isIE()) && (width == null || width.equals(""))) {
-            /*
-             * IE (what version??) needs width to be specified for the root DIV
-             * so we calculate that from the sizes of the caption and layout
-             */
-            int captionWidth = captionText.getOffsetWidth()
-                    + getCaptionMarginLeft() + getCaptionPaddingHorizontal();
-            int layoutWidth = layout.getWidgetForPaintable().getOffsetWidth()
-                    + getContainerBorderWidth();
-            int width = layoutWidth;
-            if (captionWidth > width) {
-                width = captionWidth;
-            }
-
-            super.setWidth(width + "px");
-        }
-
-        if (runGeckoFix && BrowserInfo.get().isGecko()) {
-            // workaround for #1764
-            if (width == null || width.equals("")) {
-                if (geckoCaptionMeter == null) {
-                    geckoCaptionMeter = DOM.createDiv();
-                    DOM.appendChild(captionNode, geckoCaptionMeter);
-                }
-                int captionWidth = DOM.getElementPropertyInt(captionText,
-                        "offsetWidth");
-                int availWidth = DOM.getElementPropertyInt(geckoCaptionMeter,
-                        "offsetWidth");
-                if (captionWidth == availWidth) {
-                    /*
-                     * Caption width defines panel width -> Gecko based browsers
-                     * somehow fails to float things right, without the
-                     * "noncode" below
-                     */
-                    setWidth(getOffsetWidth() + "px");
-                } else {
-                    DOM.setStyleAttribute(captionNode, "width", "");
-                }
-            }
-        }
-
-        client.runDescendentsLayout(this);
-
-        Util.runWebkitOverflowAutoFix(contentNode);
-
-    }
-
     @Override
     public void onBrowserEvent(Event event) {
         super.onBrowserEvent(event);
@@ -275,159 +188,6 @@ public class VPanel extends SimplePanel implements Container,
 
     }
 
-    @Override
-    public void setHeight(String height) {
-        this.height = height;
-        super.setHeight(height);
-        if (height != null && !"".equals(height)) {
-            final int targetHeight = getOffsetHeight();
-            int containerHeight = targetHeight
-                    - captionNode.getParentElement().getOffsetHeight()
-                    - bottomDecoration.getOffsetHeight()
-                    - getContainerBorderHeight();
-            if (containerHeight < 0) {
-                containerHeight = 0;
-            }
-            DOM.setStyleAttribute(contentNode, "height", containerHeight + "px");
-        } else {
-            DOM.setStyleAttribute(contentNode, "height", "");
-        }
-        if (!rendering) {
-            runHacks(true);
-        }
-    }
-
-    private int getCaptionMarginLeft() {
-        if (captionMarginLeft < 0) {
-            detectContainerBorders();
-        }
-        return captionMarginLeft;
-    }
-
-    private int getContentMarginLeft() {
-        if (contentMarginLeft < 0) {
-            detectContainerBorders();
-        }
-        return contentMarginLeft;
-    }
-
-    private int getCaptionPaddingHorizontal() {
-        if (captionPaddingHorizontal < 0) {
-            detectContainerBorders();
-        }
-        return captionPaddingHorizontal;
-    }
-
-    private int getContainerBorderHeight() {
-        if (borderPaddingVertical < 0) {
-            detectContainerBorders();
-        }
-        return borderPaddingVertical;
-    }
-
-    @Override
-    public void setWidth(String width) {
-        if (this.width.equals(width)) {
-            return;
-        }
-
-        this.width = width;
-        super.setWidth(width);
-        if (!rendering) {
-            runHacks(true);
-
-            if (height.equals("")) {
-                // Width change may affect height
-                Util.updateRelativeChildrenAndSendSizeUpdateEvent(client, this,
-                        this);
-            }
-
-        }
-    }
-
-    private int getContainerBorderWidth() {
-        if (borderPaddingHorizontal < 0) {
-            detectContainerBorders();
-        }
-        return borderPaddingHorizontal;
-    }
-
-    private void detectContainerBorders() {
-        DOM.setStyleAttribute(contentNode, "overflow", "hidden");
-
-        borderPaddingHorizontal = Util.measureHorizontalBorder(contentNode);
-        borderPaddingVertical = Util.measureVerticalBorder(contentNode);
-
-        DOM.setStyleAttribute(contentNode, "overflow", "auto");
-
-        captionPaddingHorizontal = Util.measureHorizontalPaddingAndBorder(
-                captionNode, 26);
-
-        captionMarginLeft = Util.measureMarginLeft(captionNode);
-        contentMarginLeft = Util.measureMarginLeft(contentNode);
-
-    }
-
-    public boolean hasChildComponent(Widget component) {
-        if (component != null && component == layout) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    public void replaceChildComponent(Widget oldComponent, Widget newComponent) {
-        // TODO This is untested as no layouts require this
-        if (oldComponent != layout.getWidgetForPaintable()) {
-            return;
-        }
-
-        setWidget(newComponent);
-        layout = VPaintableMap.get(client).getPaintable(newComponent);
-    }
-
-    public RenderSpace getAllocatedSpace(Widget child) {
-        int w = 0;
-        int h = 0;
-
-        if (width != null && !width.equals("")) {
-            w = getOffsetWidth() - getContainerBorderWidth();
-            if (w < 0) {
-                w = 0;
-            }
-        }
-
-        if (height != null && !height.equals("")) {
-            h = contentNode.getOffsetHeight() - getContainerBorderHeight();
-            if (h < 0) {
-                h = 0;
-            }
-        }
-
-        return new RenderSpace(w, h, true);
-    }
-
-    public boolean requestLayout(Set<Widget> children) {
-        // content size change might cause change to its available space
-        // (scrollbars)
-        client.handleComponentRelativeSize(layout.getWidgetForPaintable());
-        if (height != null && height != "" && width != null && width != "") {
-            /*
-             * If the height and width has been specified the child components
-             * cannot make the size of the layout change
-             */
-            return true;
-        }
-        runHacks(false);
-        return !renderInformation.updateSize(getElement());
-    }
-
-    @Override
-    protected void onAttach() {
-        super.onAttach();
-        detectContainerBorders();
-    }
-
     public ShortcutActionHandler getShortcutActionHandler() {
         return shortcutHandler;
     }
index 9c34a68528e05dd5d6e70656c08ab3492e3df377..eade1d7d0e095bbb4c2b15a66a0a109f9ed31a26 100644 (file)
@@ -4,18 +4,24 @@
 package com.vaadin.terminal.gwt.client.ui;
 
 import com.google.gwt.core.client.GWT;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.event.dom.client.DomEvent.Type;
 import com.google.gwt.event.shared.EventHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.user.client.ui.Widget;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
+import com.vaadin.terminal.gwt.client.MeasuredSize;
 import com.vaadin.terminal.gwt.client.UIDL;
 import com.vaadin.terminal.gwt.client.VPaintableWidget;
 
-public class VPanelPaintable extends VAbstractPaintableWidgetContainer {
+public class VPanelPaintable extends VAbstractPaintableWidgetContainer
+        implements ResizeRequired, LayoutPhaseListener {
 
     public static final String CLICK_EVENT_IDENTIFIER = "click";
 
+    private Integer uidlScrollTop;
+
     private ClickEventHandler clickEventHandler = new ClickEventHandler(this,
             CLICK_EVENT_IDENTIFIER) {
 
@@ -26,14 +32,24 @@ public class VPanelPaintable extends VAbstractPaintableWidgetContainer {
         }
     };
 
+    private Integer uidlScrollLeft;
+
+    public VPanelPaintable() {
+        VPanel panel = getWidgetForPaintable();
+        MeasuredSize measuredSize = getMeasuredSize();
+
+        measuredSize.registerDependency(panel.captionNode);
+        measuredSize.registerDependency(panel.bottomDecoration);
+        measuredSize.registerDependency(panel.contentNode);
+    }
+
     @Override
     protected boolean delegateCaptionHandling() {
         return false;
-    };
+    }
 
     @Override
     public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
-        getWidgetForPaintable().rendering = true;
         if (isRealUpdate(uidl)) {
 
             // Handle caption displaying and style names, prior generics.
@@ -86,7 +102,6 @@ public class VPanelPaintable extends VAbstractPaintableWidgetContainer {
         super.updateFromUIDL(uidl, client);
 
         if (!isRealUpdate(uidl)) {
-            getWidgetForPaintable().rendering = false;
             return;
         }
 
@@ -130,42 +145,23 @@ public class VPanelPaintable extends VAbstractPaintableWidgetContainer {
 
         if (uidl.hasVariable("scrollTop")
                 && uidl.getIntVariable("scrollTop") != getWidgetForPaintable().scrollTop) {
-            getWidgetForPaintable().scrollTop = uidl
-                    .getIntVariable("scrollTop");
-            getWidgetForPaintable().contentNode
-                    .setScrollTop(getWidgetForPaintable().scrollTop);
-            // re-read the actual scrollTop in case invalid value was set
-            // (scrollTop != 0 when no scrollbar exists, other values would be
-            // caught by scroll listener), see #3784
-            getWidgetForPaintable().scrollTop = getWidgetForPaintable().contentNode
-                    .getScrollTop();
+            // Sizes are not yet up to date, so changing the scroll position
+            // is deferred to after the layout phase
+            uidlScrollTop = new Integer(uidl.getIntVariable("scrollTop"));
         }
 
         if (uidl.hasVariable("scrollLeft")
                 && uidl.getIntVariable("scrollLeft") != getWidgetForPaintable().scrollLeft) {
-            getWidgetForPaintable().scrollLeft = uidl
-                    .getIntVariable("scrollLeft");
-            getWidgetForPaintable().contentNode
-                    .setScrollLeft(getWidgetForPaintable().scrollLeft);
-            // re-read the actual scrollTop in case invalid value was set
-            // (scrollTop != 0 when no scrollbar exists, other values would be
-            // caught by scroll listener), see #3784
-            getWidgetForPaintable().scrollLeft = getWidgetForPaintable().contentNode
-                    .getScrollLeft();
+            // Sizes are not yet up to date, so changing the scroll position
+            // is deferred to after the layout phase
+            uidlScrollLeft = new Integer(uidl.getIntVariable("scrollLeft"));
         }
 
-        // Must be run after scrollTop is set as Webkit overflow fix re-sets the
-        // scrollTop
-        getWidgetForPaintable().runHacks(false);
-
         // And apply tab index
         if (uidl.hasVariable("tabindex")) {
             getWidgetForPaintable().contentNode.setTabIndex(uidl
                     .getIntVariable("tabindex"));
         }
-
-        getWidgetForPaintable().rendering = false;
-
     }
 
     public void updateCaption(VPaintableWidget component, UIDL uidl) {
@@ -182,4 +178,66 @@ public class VPanelPaintable extends VAbstractPaintableWidgetContainer {
         return GWT.create(VPanel.class);
     }
 
+    public void onResize() {
+        updateSizes();
+    }
+
+    void updateSizes() {
+        MeasuredSize measuredSize = getMeasuredSize();
+        VPanel panel = getWidgetForPaintable();
+
+        Style contentStyle = panel.contentNode.getStyle();
+        if (isUndefinedHeight()) {
+            contentStyle.clearHeight();
+        } else {
+            contentStyle.setHeight(100, Unit.PCT);
+        }
+
+        if (isUndefinedWidth()) {
+            contentStyle.clearWidth();
+        } else {
+            contentStyle.setWidth(100, Unit.PCT);
+        }
+
+        int top = measuredSize.getDependencyOuterHeight(panel.captionNode);
+        int bottom = measuredSize
+                .getDependencyOuterHeight(panel.bottomDecoration);
+
+        Style style = panel.getElement().getStyle();
+        panel.captionNode.getStyle().setMarginTop(-top, Unit.PX);
+        panel.bottomDecoration.getStyle().setMarginBottom(-bottom, Unit.PX);
+        style.setPaddingTop(top, Unit.PX);
+        style.setPaddingBottom(bottom, Unit.PX);
+
+        // Update scroll positions
+        panel.contentNode.setScrollTop(panel.scrollTop);
+        panel.contentNode.setScrollLeft(panel.scrollLeft);
+        // Read actual value back to ensure update logic is correct
+        panel.scrollTop = panel.contentNode.getScrollTop();
+        panel.scrollLeft = panel.contentNode.getScrollLeft();
+    }
+
+    public void beforeLayout() {
+        // Nothing to do
+    }
+
+    public void afterLayout() {
+        VPanel panel = getWidgetForPaintable();
+        if (uidlScrollTop != null) {
+            panel.contentNode.setScrollTop(uidlScrollTop.intValue());
+            // Read actual value back to ensure update logic is correct
+            // TODO Does this trigger reflows?
+            panel.scrollTop = panel.contentNode.getScrollTop();
+            uidlScrollTop = null;
+        }
+
+        if (uidlScrollLeft != null) {
+            panel.contentNode.setScrollLeft(uidlScrollLeft.intValue());
+            // Read actual value back to ensure update logic is correct
+            // TODO Does this trigger reflows?
+            panel.scrollLeft = panel.contentNode.getScrollLeft();
+            uidlScrollLeft = null;
+        }
+    }
+
 }
diff --git a/tests/testbench/com/vaadin/tests/components/panel/BasicPanelTest.java b/tests/testbench/com/vaadin/tests/components/panel/BasicPanelTest.java
new file mode 100644 (file)
index 0000000..d23e317
--- /dev/null
@@ -0,0 +1,88 @@
+package com.vaadin.tests.components.panel;
+
+import java.util.Map;
+
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.data.Property.ValueChangeListener;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.TextArea;
+import com.vaadin.ui.themes.Reindeer;
+
+public class BasicPanelTest extends TestBase {
+    private final Label scrollPosition = new Label();
+    private final Panel panel = new Panel("Panel caption") {
+        @Override
+        public void changeVariables(Object source, Map<String, Object> variables) {
+            super.changeVariables(source, variables);
+            updateLabelText();
+        }
+    };
+
+    @Override
+    protected void setup() {
+        getLayout().setWidth("600px");
+        getLayout().setHeight("100%");
+
+        HorizontalLayout actions = new HorizontalLayout();
+        actions.setSpacing(true);
+
+        actions.addComponent(scrollPosition);
+        actions.addComponent(new Button("Sync"));
+
+        final CheckBox heightSelection = new CheckBox("Undefined height");
+        heightSelection.setImmediate(true);
+        heightSelection.addListener(new ValueChangeListener() {
+            public void valueChange(ValueChangeEvent event) {
+                if (heightSelection.getValue() == Boolean.TRUE) {
+                    panel.setHeight(null);
+                } else {
+                    panel.setHeight("100%");
+                }
+            }
+        });
+        actions.addComponent(heightSelection);
+
+        panel.setWidth("200px");
+        panel.setHeight("100%");
+        panel.setStyleName(Reindeer.PANEL_LIGHT);
+
+        panel.getContent().setCaption("Content caption");
+
+        TextArea textArea = new TextArea("TextArea caption");
+        textArea.setWidth("300px");
+        textArea.setHeight("500px");
+        panel.addComponent(textArea);
+
+        getLayout().addComponent(actions);
+        getLayout().addComponent(panel);
+        getLayout().setExpandRatio(panel, 1);
+
+        panel.setScrollable(true);
+        panel.setScrollTop(50);
+        panel.setScrollLeft(50);
+        panel.setImmediate(true);
+
+        updateLabelText();
+    }
+
+    private void updateLabelText() {
+        scrollPosition.setValue("Scrolled to " + panel.getScrollTop());
+    }
+
+    @Override
+    protected String getDescription() {
+        return "Simple test for basic panel functionality";
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+}