Bug 568002 - Column resize in mixed percentage/pixel width configuration
incorrect

Change-Id: Ida29929c52483f5da6280f6cdb9b69ec41e5f3fc
Signed-off-by: Dirk Fauth <dirk.fauth@googlemail.com>
diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/DataLayerPersistenceTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/DataLayerPersistenceTest.java
index f1a84af..c17dfd7 100644
--- a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/DataLayerPersistenceTest.java
+++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/DataLayerPersistenceTest.java
@@ -14,6 +14,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.Properties;
@@ -42,7 +43,8 @@
 
         assertEquals(11, properties.size());
         assertEquals("100", properties.getProperty("prefix.columnWidth.defaultSize"));
-        assertEquals("5:10,", properties.getProperty("prefix.columnWidth.sizes"));
+        assertNull(properties.getProperty("prefix.columnWidth.sizes"));
+        assertEquals("5:10.0,", properties.getProperty("prefix.columnWidth.percentageSizes"));
         assertTrue(Boolean.valueOf(properties.getProperty("prefix.columnWidth.resizableByDefault")));
         assertTrue(Boolean.valueOf(properties.getProperty("prefix.columnWidth.percentageSizing")));
         assertTrue(Boolean.valueOf(properties.getProperty("prefix.columnWidth.distributeRemainingSpace")));
diff --git a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfigPercentageTest.java b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfigPercentageTest.java
index b51255a..a1b62e9 100644
--- a/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfigPercentageTest.java
+++ b/org.eclipse.nebula.widgets.nattable.core.test/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfigPercentageTest.java
@@ -1494,4 +1494,70 @@
         assertEquals(500, this.sizeConfigMixedMode.getAggregateSize(3));
     }
 
+    @Test
+    public void shouldInitiallySetSizeAsPercentage() {
+        SizeConfig sizeConfig = new SizeConfig(DEFAULT_SIZE);
+        sizeConfig.setPercentageSizing(true);
+        sizeConfig.setSize(0, 25);
+        sizeConfig.setSize(1, 25);
+        sizeConfig.setSize(2, 50);
+        sizeConfig.calculatePercentages(1000, 3);
+
+        assertEquals(250, sizeConfig.getSize(0));
+        assertEquals(250, sizeConfig.getSize(1));
+        assertEquals(500, sizeConfig.getSize(2));
+    }
+
+    @Test
+    public void shouldInitiallySetSizeAsPercentageAfter() {
+        SizeConfig sizeConfig = new SizeConfig(DEFAULT_SIZE);
+        sizeConfig.setSize(0, 25);
+        sizeConfig.setSize(1, 25);
+        sizeConfig.setSize(2, 50);
+        sizeConfig.setPercentageSizing(true);
+        sizeConfig.calculatePercentages(1000, 3);
+
+        assertEquals(250, sizeConfig.getSize(0));
+        assertEquals(250, sizeConfig.getSize(1));
+        assertEquals(500, sizeConfig.getSize(2));
+    }
+
+    @Test
+    public void shouldKeepConsistentPercentagesOnExceedingSpace() {
+        SizeConfig sizeConfig = new SizeConfig(DEFAULT_SIZE);
+        sizeConfig.setPercentageSizing(true);
+        sizeConfig.calculatePercentages(900, 3);
+
+        assertEquals(300, sizeConfig.getSize(0));
+        assertEquals(300, sizeConfig.getSize(1));
+        assertEquals(300, sizeConfig.getSize(2));
+
+        // resize column 0 to be larger than available
+        sizeConfig.setSize(0, 1000);
+
+        assertEquals(882, sizeConfig.getSize(0));
+        assertEquals(9, sizeConfig.getSize(1));
+        assertEquals(9, sizeConfig.getSize(2));
+
+        // resize column 0 to 300
+        sizeConfig.setSize(0, 300);
+
+        assertEquals(300, sizeConfig.getSize(0));
+        assertEquals(591, sizeConfig.getSize(1));
+        assertEquals(9, sizeConfig.getSize(2));
+
+        // resize column 1 to 300
+        sizeConfig.setSize(1, 300);
+
+        assertEquals(301, sizeConfig.getSize(0));
+        assertEquals(300, sizeConfig.getSize(1));
+        assertEquals(299, sizeConfig.getSize(2));
+
+        // increase column 1 by 9 pixels (1%)
+        sizeConfig.setSize(1, 309);
+
+        assertEquals(301, sizeConfig.getSize(0));
+        assertEquals(309, sizeConfig.getSize(1));
+        assertEquals(290, sizeConfig.getSize(2));
+    }
 }
diff --git a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfig.java b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfig.java
index 3592512..df89564 100644
--- a/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfig.java
+++ b/org.eclipse.nebula.widgets.nattable.core/src/org/eclipse/nebula/widgets/nattable/layer/SizeConfig.java
@@ -641,6 +641,20 @@
                     // take the remaining space
                     this.percentageSizeMap.remove(position);
                 }
+
+                // if the percentage sum is bigger than 100 after setSize, we
+                // need to modify the set value so 100 is not exceeded to avoid
+                // resize errors as a follow up
+                if (percentage > 100) {
+                    double adjusted = 100 - this.percentageSizeMap.select((key, value) -> key != position).sum();
+                    this.percentageSizeMap.put(position, adjusted);
+                }
+
+            } else {
+                // if a size is set, the position is configured for percentage
+                // sizing but the available space is 0 we simply store the size
+                // value as percentage value
+                this.percentageSizeMap.put(position, size);
             }
 
             calculatePercentages(this.availableSpace, this.realSizeMap.size());
@@ -898,6 +912,16 @@
     public void setPercentageSizing(boolean percentageSizing) {
         this.percentageSizing = percentageSizing;
         this.isAggregatedSizeCacheValid = false;
+
+        // if sizes are already configured, check if the sizes need to be
+        // transferred to percentages
+        if (!this.sizeMap.isEmpty()) {
+            MutableIntIntMap transfer = this.sizeMap.select((key, value) -> isPercentageSizing(key));
+            transfer.forEachKeyValue((key, value) -> {
+                this.percentageSizeMap.put(key, value);
+                this.sizeMap.remove(key);
+            });
+        }
     }
 
     /**