From e3c2e2efbed6452a365483aadfc147c4ae6ffdad Mon Sep 17 00:00:00 2001
From: Tapio Aali <tapio@vaadin.com>
Date: Wed, 30 May 2012 10:02:29 +0000
Subject: Added options for setting maximum and minimum split positions to
 SplitPanel (#1744).

svn changeset:23850/svn branch:6.8
---
 .../vaadin/terminal/gwt/client/ui/VSplitPanel.java | 119 +++++++--
 src/com/vaadin/ui/AbstractSplitPanel.java          | 110 +++++++-
 .../SplitPanelWithMinimumAndMaximum.html           | 207 ++++++++++++++++
 .../SplitPanelWithMinimumAndMaximum.java           | 276 +++++++++++++++++++++
 4 files changed, 691 insertions(+), 21 deletions(-)
 create mode 100644 tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.html
 create mode 100644 tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.java

diff --git a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
index 5a996954a0..4cb183917f 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VSplitPanel.java
@@ -147,6 +147,10 @@ public class VSplitPanel extends ComplexPanel implements Container,
     /* The current position of the split handle in either percentages or pixels */
     private String position;
 
+    private String maximumPosition;
+
+    private String minimumPosition;
+
     private final TouchScrollHandler touchScrollHandler;
 
     protected Element scrolledContainer;
@@ -272,6 +276,10 @@ public class VSplitPanel extends ComplexPanel implements Container,
         touchScrollHandler.setElements(firstContainer, secondContainer);
 
         position = uidl.getStringAttribute("position");
+
+        minimumPosition = uidl.getStringAttribute("minimumPosition");
+        maximumPosition = uidl.getStringAttribute("maximumPosition");
+
         setSplitPosition(position);
 
         final Paintable newFirstChild = client.getPaintable(uidl
@@ -346,11 +354,100 @@ public class VSplitPanel extends ComplexPanel implements Container,
         }
     }
 
+    /**
+     * Converts given split position string (in pixels or percentage) to a
+     * floating point pixel value.
+     * 
+     * @param pos
+     * @return
+     */
+    private float convertToPixels(String pos) {
+        float posAsFloat;
+        if (pos.indexOf("%") > 0) {
+            posAsFloat = Math.round(Float.parseFloat(pos.substring(0,
+                    pos.length() - 1))
+                    / 100
+                    * (orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
+                            : getOffsetHeight()));
+        } else {
+            posAsFloat = Float.parseFloat(pos.substring(0, pos.length() - 2));
+        }
+        return posAsFloat;
+    }
+
+    /**
+     * Converts given split position string (in pixels or percentage) to a float
+     * percentage value.
+     * 
+     * @param pos
+     * @return
+     */
+    private float convertToPercentage(String pos) {
+        float posAsFloat = 0;
+
+        if (pos.indexOf("px") > 0) {
+            int posAsInt = Integer.parseInt(pos.substring(0, pos.length() - 2));
+            int offsetLength = orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth()
+                    : getOffsetHeight();
+
+            // 100% needs special handling
+            if (posAsInt + getSplitterSize() >= offsetLength) {
+                posAsInt = offsetLength;
+            }
+            // Reversed position
+            if (positionReversed) {
+                posAsInt = offsetLength - posAsInt - getSplitterSize();
+            }
+            posAsFloat = ((float) posAsInt / (float) getOffsetWidth() * 100);
+
+        } else {
+            posAsFloat = Float.parseFloat(pos.substring(0, pos.length() - 1));
+        }
+        return posAsFloat;
+    }
+
+    private String checkSplitPositionLimits(String pos) {
+        float positionAsFloat = convertToPixels(pos);
+        float maximumAsFloat = convertToPixels(maximumPosition);
+        float minimumAsFloat = convertToPixels(minimumPosition);
+
+        if (maximumAsFloat < positionAsFloat) {
+            pos = maximumPosition;
+        } else if (minimumAsFloat > positionAsFloat) {
+            pos = minimumPosition;
+        }
+        return pos;
+    }
+
+    /**
+     * Converts given string to the same units as the split position is.
+     * 
+     * @param pos
+     *            position to be converted
+     * @return converted position string
+     */
+    private String convertToPositionUnits(String pos) {
+        if (position.indexOf("%") != -1 && pos.indexOf("%") == -1) {
+            // position is in percentage, pos in pixels
+            pos = convertToPercentage(pos) + "%";
+        } else if (position.indexOf("px") > 0 && pos.indexOf("px") == -1) {
+            // position is in pixels and pos in percentage
+            pos = convertToPixels(pos) + "px";
+        }
+
+        return pos;
+    }
+
     private void setSplitPosition(String pos) {
         if (pos == null) {
             return;
         }
 
+        pos = checkSplitPositionLimits(pos);
+        if (!pos.equals(position)) {
+            position = convertToPositionUnits(pos);
+        }
+
         // Convert percentage values to pixels
         if (pos.indexOf("%") > 0) {
             pos = Float.parseFloat(pos.substring(0, pos.length() - 1))
@@ -564,16 +661,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
         }
 
         if (position.indexOf("%") > 0) {
-            float pos = newX;
-            // 100% needs special handling
-            if (newX + getSplitterSize() >= getOffsetWidth()) {
-                pos = getOffsetWidth();
-            }
-            // Reversed position
-            if (positionReversed) {
-                pos = getOffsetWidth() - pos - getSplitterSize();
-            }
-            position = (pos / getOffsetWidth() * 100) + "%";
+            position = convertToPositionUnits(newX + "px");
         } else {
             // Reversed position
             if (positionReversed) {
@@ -606,16 +694,7 @@ public class VSplitPanel extends ComplexPanel implements Container,
         }
 
         if (position.indexOf("%") > 0) {
-            float pos = newY;
-            // 100% needs special handling
-            if (newY + getSplitterSize() >= getOffsetHeight()) {
-                pos = getOffsetHeight();
-            }
-            // Reversed position
-            if (positionReversed) {
-                pos = getOffsetHeight() - pos - getSplitterSize();
-            }
-            position = pos / getOffsetHeight() * 100 + "%";
+            position = convertToPositionUnits(newY + "px");
         } else {
             // Reversed position
             if (positionReversed) {
diff --git a/src/com/vaadin/ui/AbstractSplitPanel.java b/src/com/vaadin/ui/AbstractSplitPanel.java
index b507b88478..ebdee17de2 100644
--- a/src/com/vaadin/ui/AbstractSplitPanel.java
+++ b/src/com/vaadin/ui/AbstractSplitPanel.java
@@ -22,7 +22,7 @@ import com.vaadin.tools.ReflectTools;
  * AbstractSplitPanel.
  * 
  * <code>AbstractSplitPanel</code> is base class for a component container that
- * can contain two components. The comopnents are split by a divider element.
+ * can contain two components. The components are split by a divider element.
  * 
  * @author Vaadin Ltd.
  * @version
@@ -41,6 +41,14 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
 
     private boolean posReversed = false;
 
+    private int posMin = 0;
+
+    private int posMinUnit = UNITS_PERCENTAGE;
+
+    private int posMax = 100;
+
+    private int posMaxUnit = UNITS_PERCENTAGE;
+
     private boolean locked = false;
 
     private static final String SPLITTER_CLICK_EVENT = VSplitPanel.SPLITTER_CLICK_EVENT_IDENTIFIER;
@@ -210,8 +218,12 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
         super.paintContent(target);
 
         final String position = pos + UNIT_SYMBOLS[posUnit];
+        final String minimumPosition = posMin + UNIT_SYMBOLS[posMinUnit];
+        final String maximumPosition = posMax + UNIT_SYMBOLS[posMaxUnit];
 
         target.addAttribute("position", position);
+        target.addAttribute("minimumPosition", minimumPosition);
+        target.addAttribute("maximumPosition", maximumPosition);
 
         if (isLocked()) {
             target.addAttribute("locked", true);
@@ -322,6 +334,102 @@ public abstract class AbstractSplitPanel extends AbstractLayout {
         return posUnit;
     }
 
+    /**
+     * Sets the minimum split position to the given position and unit. If the
+     * split position is reversed, maximum and minimum are also reversed.
+     * 
+     * @param pos
+     *            the minimum position of the split
+     * @param unit
+     *            the unit (from {@link Sizeable}) in which the size is given.
+     *            Allowed units are UNITS_PERCENTAGE and UNITS_PIXELS
+     */
+    public void setMinimumSplitPosition(int pos, int unit) {
+        setSplitPositionLimits(pos, unit, posMax, posMaxUnit);
+    }
+
+    /**
+     * Returns the current minimum position of the splitter, in
+     * {@link #getMinSplitPositionUnit()} units.
+     * 
+     * @return the minimum position of the splitter
+     */
+    public int getMinSplitPosition() {
+        return posMin;
+    }
+
+    /**
+     * Returns the unit of the minimum position of the splitter.
+     * 
+     * @return the unit of the minimum position of the splitter
+     */
+    public int getMinSplitPositionUnit() {
+        return posMinUnit;
+    }
+
+    /**
+     * Sets the maximum split position to the given position and unit. If the
+     * split position is reversed, maximum and minimum are also reversed.
+     * 
+     * @param pos
+     *            the maximum position of the split
+     * @param unit
+     *            the unit (from {@link Sizeable}) in which the size is given.
+     *            Allowed units are UNITS_PERCENTAGE and UNITS_PIXELS
+     */
+    public void setMaxSplitPosition(int pos, int unit) {
+        setSplitPositionLimits(posMin, posMinUnit, pos, unit);
+    }
+
+    /**
+     * Returns the current maximum position of the splitter, in
+     * {@link #getMaxSplitPositionUnit()} units.
+     * 
+     * @return the maximum position of the splitter
+     */
+    public int getMaxSplitPosition() {
+        return posMax;
+    }
+
+    /**
+     * Returns the unit of the maximum position of the splitter
+     * 
+     * @return the unit of the maximum position of the splitter
+     */
+    public int getMaxSplitPositionUnit() {
+        return posMaxUnit;
+    }
+
+    /**
+     * Sets the maximum and minimum position of the splitter. If the split
+     * position is reversed, maximum and minimum are also reversed.
+     * 
+     * @param minPos
+     *            the new minimum position
+     * @param minPosUnit
+     *            the unit (from {@link Sizeable}) in which the minimum position
+     *            is given.
+     * @param maxPos
+     *            the new maximum position
+     * @param maxPosUnit
+     *            the unit (from {@link Sizeable}) in which the maximum position
+     *            is given.
+     */
+    private void setSplitPositionLimits(int minPos, int minPosUnit, int maxPos,
+            int maxPosUnit) {
+        if ((minPosUnit != UNITS_PERCENTAGE && minPosUnit != UNITS_PIXELS)
+                || (maxPosUnit != UNITS_PERCENTAGE && maxPosUnit != UNITS_PIXELS)) {
+            throw new IllegalArgumentException(
+                    "Only percentage and pixel units are allowed");
+        }
+
+        posMin = minPos;
+        posMinUnit = minPosUnit;
+        posMax = maxPos;
+        posMaxUnit = maxPosUnit;
+        requestRepaint();
+    }
+
     /**
      * Moves the position of the splitter.
      * 
diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.html b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.html
new file mode 100644
index 0000000000..3aefedeff3
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.html
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="" />
+<title>SplitPanelWithMinimumAndMaximum</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">SplitPanelWithMinimumAndMaximum</td></tr>
+</thead><tbody>
+<tr>
+	<td>open</td>
+	<td>/run/com.vaadin.tests.components.splitpanel.SplitPanelWithMinimumAndMaximum?restartApplication</td>
+	<td></td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-239,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-340,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[2]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-300,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[3]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-79,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[4]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-179,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[5]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-78,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[6]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-150,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[7]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>-371,0</td>
+</tr>
+<tr>
+	<td>screenCapture</td>
+	<td></td>
+	<td>horizontal-splits-left</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>418,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[1]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>418,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[2]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>450,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[3]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>450,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[4]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>418,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[5]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>418,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[6]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>450,0</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[7]/VSplitPanelHorizontal[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>450,0</td>
+</tr>
+<tr>
+	<td>screenCapture</td>
+	<td></td>
+	<td>horizontal-splits-right</td>
+</tr>
+<tr>
+	<td>mouseClick</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]/domChild[0]/domChild[0]/domChild[0]</td>
+	<td>44,2</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-206</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-348</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[2]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-300</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[3]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-55</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[4]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-155</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[5]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-13</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[7]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-300</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[6]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,-300</td>
+</tr>
+<tr>
+	<td>screenCapture</td>
+	<td></td>
+	<td>vertical-splits-up</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[0]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,361</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[1]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,361</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[2]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,350</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[3]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,350</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[4]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,361</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[5]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,361</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[6]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,300</td>
+</tr>
+<tr>
+	<td>dragAndDrop</td>
+	<td>vaadin=runcomvaadintestscomponentssplitpanelSplitPanelWithMinimumAndMaximum::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VTabsheet[0]/VTabsheetPanel[0]/VHorizontalLayout[0]/ChildComponentContainer[7]/VSplitPanelVertical[0]/domChild[0]/domChild[2]/domChild[0]</td>
+	<td>0,300</td>
+</tr>
+<tr>
+	<td>screenCapture</td>
+	<td></td>
+	<td>vertical-splits-down</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
diff --git a/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.java b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.java
new file mode 100644
index 0000000000..9fa6fc18a3
--- /dev/null
+++ b/tests/testbench/com/vaadin/tests/components/splitpanel/SplitPanelWithMinimumAndMaximum.java
@@ -0,0 +1,276 @@
+package com.vaadin.tests.components.splitpanel;
+
+import com.vaadin.terminal.Sizeable;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.HorizontalLayout;
+import com.vaadin.ui.HorizontalSplitPanel;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.TabSheet;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.VerticalSplitPanel;
+
+public class SplitPanelWithMinimumAndMaximum extends TestBase {
+
+    @Override
+    protected void setup() {
+        TabSheet tabs = new TabSheet();
+
+        VerticalLayout horizontalSplitsLayout = new VerticalLayout();
+        horizontalSplitsLayout.setCaption("Horizontal splits");
+
+        HorizontalSplitPanel percentagePositionWithPercentageLimitsHorizontal = new HorizontalSplitPanel();
+        percentagePositionWithPercentageLimitsHorizontal
+                .setMinimumSplitPosition(10, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsHorizontal.setMaxSplitPosition(
+                80, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsHorizontal
+                .setFirstComponent(new Label("Min 10 % - 50 % position"));
+        percentagePositionWithPercentageLimitsHorizontal
+                .setSecondComponent(new Label("Max 80 %"));
+        percentagePositionWithPercentageLimitsHorizontal.setSplitPosition(50,
+                Sizeable.UNITS_PERCENTAGE);
+        horizontalSplitsLayout
+                .addComponent(percentagePositionWithPercentageLimitsHorizontal);
+
+        HorizontalSplitPanel pixelPositionWithPercentageLimitsHorizontal = new HorizontalSplitPanel();
+        pixelPositionWithPercentageLimitsHorizontal.setMinimumSplitPosition(10,
+                Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsHorizontal.setMaxSplitPosition(80,
+                Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsHorizontal
+                .setFirstComponent(new Label("Min 10 % - 400 px position"));
+        pixelPositionWithPercentageLimitsHorizontal
+                .setSecondComponent(new Label("Max 80 %"));
+        pixelPositionWithPercentageLimitsHorizontal.setSplitPosition(400,
+                Sizeable.UNITS_PIXELS);
+        horizontalSplitsLayout
+                .addComponent(pixelPositionWithPercentageLimitsHorizontal);
+
+        HorizontalSplitPanel pixelPositionWithPixelLimitsHorizontal = new HorizontalSplitPanel();
+        pixelPositionWithPixelLimitsHorizontal.setMinimumSplitPosition(100,
+                Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsHorizontal.setMaxSplitPosition(550,
+                Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsHorizontal.setFirstComponent(new Label(
+                "Min 100 px - 400 px position"));
+        pixelPositionWithPixelLimitsHorizontal.setSecondComponent(new Label(
+                "Max 550 px"));
+        pixelPositionWithPixelLimitsHorizontal.setSplitPosition(400,
+                Sizeable.UNITS_PIXELS);
+        horizontalSplitsLayout
+                .addComponent(pixelPositionWithPixelLimitsHorizontal);
+
+        HorizontalSplitPanel percentagePositionWithPixelLimitsHorizontal = new HorizontalSplitPanel();
+        percentagePositionWithPixelLimitsHorizontal.setMinimumSplitPosition(
+                100, Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsHorizontal.setMaxSplitPosition(550,
+                Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsHorizontal
+                .setFirstComponent(new Label("Min 100 px - 30 % position"));
+        percentagePositionWithPixelLimitsHorizontal
+                .setSecondComponent(new Label("Max 550 px"));
+        percentagePositionWithPixelLimitsHorizontal.setSplitPosition(30,
+                Sizeable.UNITS_PERCENTAGE);
+        horizontalSplitsLayout
+                .addComponent(percentagePositionWithPixelLimitsHorizontal);
+
+        HorizontalSplitPanel percentagePositionWithPercentageLimitsHorizontalResersed = new HorizontalSplitPanel();
+        percentagePositionWithPercentageLimitsHorizontalResersed
+                .setMinimumSplitPosition(10, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsHorizontalResersed
+                .setMaxSplitPosition(80, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsHorizontalResersed
+                .setFirstComponent(new Label(
+                        "Max 80 % - Reversed 50 % position"));
+        percentagePositionWithPercentageLimitsHorizontalResersed
+                .setSecondComponent(new Label("Min 10 %"));
+        percentagePositionWithPercentageLimitsHorizontalResersed
+                .setSplitPosition(50, Sizeable.UNITS_PERCENTAGE, true);
+        horizontalSplitsLayout
+                .addComponent(percentagePositionWithPercentageLimitsHorizontalResersed);
+
+        HorizontalSplitPanel pixelPositionWithPercentageLimitsHorizontalResersed = new HorizontalSplitPanel();
+        pixelPositionWithPercentageLimitsHorizontalResersed
+                .setMinimumSplitPosition(10, Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsHorizontalResersed
+                .setMaxSplitPosition(80, Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsHorizontalResersed
+                .setFirstComponent(new Label(
+                        "Max 80 % - Reversed 400 px position"));
+        pixelPositionWithPercentageLimitsHorizontalResersed
+                .setSecondComponent(new Label("Min 10 %"));
+        pixelPositionWithPercentageLimitsHorizontalResersed.setSplitPosition(
+                400, Sizeable.UNITS_PIXELS, true);
+        horizontalSplitsLayout
+                .addComponent(pixelPositionWithPercentageLimitsHorizontalResersed);
+
+        HorizontalSplitPanel pixelPositionWithPixelLimitsHorizontalResersed = new HorizontalSplitPanel();
+        pixelPositionWithPixelLimitsHorizontalResersed.setMinimumSplitPosition(
+                100, Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsHorizontalResersed.setMaxSplitPosition(550,
+                Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsHorizontalResersed
+                .setFirstComponent(new Label(
+                        "Max 550 px - Reversed 400 px position"));
+        pixelPositionWithPixelLimitsHorizontalResersed
+                .setSecondComponent(new Label("Min 100 px"));
+        pixelPositionWithPixelLimitsHorizontalResersed.setSplitPosition(400,
+                Sizeable.UNITS_PIXELS, true);
+        horizontalSplitsLayout
+                .addComponent(pixelPositionWithPixelLimitsHorizontalResersed);
+
+        HorizontalSplitPanel percentagePositionWithPixelLimitsHorizontalResersed = new HorizontalSplitPanel();
+        percentagePositionWithPixelLimitsHorizontalResersed
+                .setMinimumSplitPosition(100, Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsHorizontalResersed
+                .setMaxSplitPosition(550, Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsHorizontalResersed
+                .setFirstComponent(new Label(
+                        "Max 550 px - Reversed 30 % position"));
+        percentagePositionWithPixelLimitsHorizontalResersed
+                .setSecondComponent(new Label("Min 100 px"));
+        percentagePositionWithPixelLimitsHorizontalResersed.setSplitPosition(
+                30, Sizeable.UNITS_PERCENTAGE, true);
+        horizontalSplitsLayout
+                .addComponent(percentagePositionWithPixelLimitsHorizontalResersed);
+
+        horizontalSplitsLayout.setSizeFull();
+        tabs.addComponent(horizontalSplitsLayout);
+
+        HorizontalLayout verticalSplitsLayout = new HorizontalLayout();
+        verticalSplitsLayout.setCaption("Vertical splits");
+
+        VerticalSplitPanel percentagePositionWithPercentageLimitsVertical = new VerticalSplitPanel();
+        percentagePositionWithPercentageLimitsVertical.setMinimumSplitPosition(
+                10, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsVertical.setMaxSplitPosition(80,
+                Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsVertical
+                .setFirstComponent(new Label("Min 10 % - 50 % position"));
+        percentagePositionWithPercentageLimitsVertical
+                .setSecondComponent(new Label("Max 80 %"));
+        percentagePositionWithPercentageLimitsVertical.setSplitPosition(50,
+                Sizeable.UNITS_PERCENTAGE);
+        verticalSplitsLayout
+                .addComponent(percentagePositionWithPercentageLimitsVertical);
+
+        VerticalSplitPanel pixelPositionWithPercentageLimitsVertical = new VerticalSplitPanel();
+        pixelPositionWithPercentageLimitsVertical.setMinimumSplitPosition(10,
+                Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsVertical.setMaxSplitPosition(80,
+                Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsVertical.setFirstComponent(new Label(
+                "Min 10 % - 400 px position"));
+        pixelPositionWithPercentageLimitsVertical.setSecondComponent(new Label(
+                "Max 80 %"));
+        pixelPositionWithPercentageLimitsVertical.setSplitPosition(400,
+                Sizeable.UNITS_PIXELS);
+        verticalSplitsLayout
+                .addComponent(pixelPositionWithPercentageLimitsVertical);
+
+        VerticalSplitPanel pixelPositionWithPixelLimitsVertical = new VerticalSplitPanel();
+        pixelPositionWithPixelLimitsVertical.setMinimumSplitPosition(100,
+                Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsVertical.setMaxSplitPosition(450,
+                Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsVertical.setFirstComponent(new Label(
+                "Min 100 px - 400 px position"));
+        pixelPositionWithPixelLimitsVertical.setSecondComponent(new Label(
+                "Max 450 px"));
+        pixelPositionWithPixelLimitsVertical.setSplitPosition(400,
+                Sizeable.UNITS_PIXELS);
+        verticalSplitsLayout.addComponent(pixelPositionWithPixelLimitsVertical);
+
+        VerticalSplitPanel percentagePositionWithPixelLimitsVertical = new VerticalSplitPanel();
+        percentagePositionWithPixelLimitsVertical.setMinimumSplitPosition(100,
+                Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsVertical.setMaxSplitPosition(450,
+                Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsVertical.setFirstComponent(new Label(
+                "Min 100 px - 30 % position"));
+        percentagePositionWithPixelLimitsVertical.setSecondComponent(new Label(
+                "Max 450 px"));
+        percentagePositionWithPixelLimitsVertical.setSplitPosition(30,
+                Sizeable.UNITS_PERCENTAGE);
+        verticalSplitsLayout
+                .addComponent(percentagePositionWithPixelLimitsVertical);
+
+        VerticalSplitPanel percentagePositionWithPercentageLimitsVerticalReversed = new VerticalSplitPanel();
+        percentagePositionWithPercentageLimitsVerticalReversed
+                .setMinimumSplitPosition(10, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsVerticalReversed
+                .setMaxSplitPosition(80, Sizeable.UNITS_PERCENTAGE);
+        percentagePositionWithPercentageLimitsVerticalReversed
+                .setFirstComponent(new Label(
+                        "Max 80 % - Reversed 50 % position"));
+        percentagePositionWithPercentageLimitsVerticalReversed
+                .setSecondComponent(new Label("Min 10 %"));
+        percentagePositionWithPercentageLimitsVerticalReversed
+                .setSplitPosition(50, Sizeable.UNITS_PERCENTAGE, true);
+        verticalSplitsLayout
+                .addComponent(percentagePositionWithPercentageLimitsVerticalReversed);
+
+        VerticalSplitPanel pixelPositionWithPercentageLimitsVerticalReversed = new VerticalSplitPanel();
+        pixelPositionWithPercentageLimitsVerticalReversed
+                .setMinimumSplitPosition(10, Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsVerticalReversed.setMaxSplitPosition(
+                80, Sizeable.UNITS_PERCENTAGE);
+        pixelPositionWithPercentageLimitsVerticalReversed
+                .setFirstComponent(new Label(
+                        "Max 80 % - Reversed 400 px position"));
+        pixelPositionWithPercentageLimitsVerticalReversed
+                .setSecondComponent(new Label("Min 10 %"));
+        pixelPositionWithPercentageLimitsVerticalReversed.setSplitPosition(400,
+                Sizeable.UNITS_PIXELS, true);
+        verticalSplitsLayout
+                .addComponent(pixelPositionWithPercentageLimitsVerticalReversed);
+
+        VerticalSplitPanel pixelPositionWithPixelLimitsVerticalReversed = new VerticalSplitPanel();
+        pixelPositionWithPixelLimitsVerticalReversed.setMinimumSplitPosition(
+                100, Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsVerticalReversed.setMaxSplitPosition(400,
+                Sizeable.UNITS_PIXELS);
+        pixelPositionWithPixelLimitsVerticalReversed
+                .setFirstComponent(new Label(
+                        "Max 400 px - Reversed 300 px position"));
+        pixelPositionWithPixelLimitsVerticalReversed
+                .setSecondComponent(new Label("Min 100 px"));
+        pixelPositionWithPixelLimitsVerticalReversed.setSplitPosition(300,
+                Sizeable.UNITS_PIXELS, true);
+        verticalSplitsLayout
+                .addComponent(pixelPositionWithPixelLimitsVerticalReversed);
+
+        VerticalSplitPanel percentagePositionWithPixelLimitsVerticalReversed = new VerticalSplitPanel();
+        percentagePositionWithPixelLimitsVerticalReversed
+                .setMinimumSplitPosition(100, Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsVerticalReversed.setMaxSplitPosition(
+                400, Sizeable.UNITS_PIXELS);
+        percentagePositionWithPixelLimitsVerticalReversed
+                .setFirstComponent(new Label(
+                        "Max 400 px - Reversed 30 % position"));
+        percentagePositionWithPixelLimitsVerticalReversed
+                .setSecondComponent(new Label("Min 100 px"));
+        percentagePositionWithPixelLimitsVerticalReversed.setSplitPosition(30,
+                Sizeable.UNITS_PERCENTAGE, true);
+        verticalSplitsLayout
+                .addComponent(percentagePositionWithPixelLimitsVerticalReversed);
+
+        tabs.addComponent(verticalSplitsLayout);
+        verticalSplitsLayout.setSizeFull();
+
+        addComponent(tabs);
+        tabs.setHeight("550px");
+        tabs.setWidth("600px");
+        getLayout().setSizeFull();
+    }
+
+    @Override
+    protected String getDescription() {
+        return "SplitPanel could have setMaxSplitPosition and setMinSplitPosition methods as a way to set maximum and minimum limits for the split position. This is not a very critical feature but could be useful in some situations.";
+    }
+
+    @Override
+    protected Integer getTicketNumber() {
+        return 1744;
+    }
+}
-- 
cgit v1.2.3