merge trunk to common sl branch

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1691845 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/integrationtest/org/apache/poi/TestAllFiles.java b/src/integrationtest/org/apache/poi/TestAllFiles.java
index 85b0580..784b9ba 100644
--- a/src/integrationtest/org/apache/poi/TestAllFiles.java
+++ b/src/integrationtest/org/apache/poi/TestAllFiles.java
@@ -103,12 +103,12 @@
         HANDLERS.put(".vsd", new HDGFFileHandler());
         
         // Visio - ooxml (currently unsupported)
-        HANDLERS.put(".vsdm", new NullFileHandler());
-        HANDLERS.put(".vsdx", new NullFileHandler());
-        HANDLERS.put(".vssm", new NullFileHandler());
-        HANDLERS.put(".vssx", new NullFileHandler());
-        HANDLERS.put(".vstm", new NullFileHandler());
-        HANDLERS.put(".vstx", new NullFileHandler());
+        HANDLERS.put(".vsdm", new XDGFFileHandler());
+        HANDLERS.put(".vsdx", new XDGFFileHandler());
+        HANDLERS.put(".vssm", new XDGFFileHandler());
+        HANDLERS.put(".vssx", new XDGFFileHandler());
+        HANDLERS.put(".vstm", new XDGFFileHandler());
+        HANDLERS.put(".vstx", new XDGFFileHandler());
 
         // POIFS
         HANDLERS.put(".ole2", new POIFSFileHandler());
diff --git a/src/integrationtest/org/apache/poi/stress/POIXMLDocumentHandler.java b/src/integrationtest/org/apache/poi/stress/POIXMLDocumentHandler.java
index 7b0821d..1a8cbf6 100644
--- a/src/integrationtest/org/apache/poi/stress/POIXMLDocumentHandler.java
+++ b/src/integrationtest/org/apache/poi/stress/POIXMLDocumentHandler.java
@@ -20,17 +20,10 @@
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.List;
 
 import org.apache.poi.POIXMLDocument;
-import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
-import org.apache.poi.openxml4j.opc.OPCPackage;
-import org.apache.poi.openxml4j.opc.PackageAccess;
-import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.poifs.crypt.Decryptor;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
-import org.junit.Ignore;
-import org.junit.Test;
 
 public final class POIXMLDocumentHandler {
 	protected void handlePOIXMLDocument(POIXMLDocument doc) throws Exception {
@@ -44,33 +37,15 @@
     protected static boolean isEncrypted(InputStream stream) throws IOException {
         if (POIFSFileSystem.hasPOIFSHeader(stream)) {
             POIFSFileSystem poifs = new POIFSFileSystem(stream);
-            if (poifs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
-                return true;
+            try {
+                if (poifs.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) {
+                    return true;
+                }
+            } finally {
+                poifs.close();
             }
             throw new IOException("wrong file format or file extension for OO XML file");
         }
         return false;
     }
-	
-	// a test-case to test this locally without executing the full TestAllFiles
-    @Ignore("POIXMLDocument cannot handle this Visio file currently...")
-	@Test
-	public void test() throws Exception {
-		OPCPackage pkg = OPCPackage.open("test-data/diagram/test.vsdx", PackageAccess.READ);
-		try {
-			handlePOIXMLDocument(new TestPOIXMLDocument(pkg));
-		} finally {
-			pkg.close();
-		}
-	}
-	
-	private final static class TestPOIXMLDocument extends POIXMLDocument {
-		public TestPOIXMLDocument(OPCPackage pkg) {
-			super(pkg);
-		}
-
-		public List<PackagePart> getAllEmbedds() throws OpenXML4JException {
-			return null;
-		}
-	}
 }
diff --git a/src/integrationtest/org/apache/poi/stress/XDGFFileHandler.java b/src/integrationtest/org/apache/poi/stress/XDGFFileHandler.java
new file mode 100644
index 0000000..4c4fd60
--- /dev/null
+++ b/src/integrationtest/org/apache/poi/stress/XDGFFileHandler.java
@@ -0,0 +1,75 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+package org.apache.poi.stress;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.poi.POIXMLDocument;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.OPCPackage;
+import org.apache.poi.openxml4j.opc.PackageAccess;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
+import org.apache.poi.util.PackageHelper;
+import org.junit.Test;
+
+public class XDGFFileHandler extends AbstractFileHandler {
+    @Override
+    public void handleFile(InputStream stream) throws Exception {
+        // ignore password protected files
+        if (POIXMLDocumentHandler.isEncrypted(stream)) return;
+
+        TestXDGFXMLDocument doc = new TestXDGFXMLDocument(stream);
+        new POIXMLDocumentHandler().handlePOIXMLDocument(doc);
+    }
+
+    @Override
+    public void handleExtracting(File file) throws Exception {
+        // TODO: extraction/actual operations not supported yet
+    }
+
+    // a test-case to test this locally without executing the full TestAllFiles
+    @Test
+    public void test() throws Exception {
+        OPCPackage pkg = OPCPackage.open("test-data/diagram/test.vsdx", PackageAccess.READ);
+        try {
+            TestXDGFXMLDocument doc = new TestXDGFXMLDocument(pkg);
+            new POIXMLDocumentHandler().handlePOIXMLDocument(doc);
+        } finally {
+            pkg.close();
+        }
+    }
+
+    // TODO: Get rid of this when full visio ooxml support is added
+    private final static class TestXDGFXMLDocument extends POIXMLDocument {
+        public TestXDGFXMLDocument(OPCPackage pkg) {
+            super(pkg, PackageRelationshipTypes.VISIO_CORE_DOCUMENT);
+        }
+
+        public TestXDGFXMLDocument(InputStream is) throws IOException {
+            this(PackageHelper.open(is));
+        }
+
+        public List<PackagePart> getAllEmbedds() throws OpenXML4JException {
+            return new ArrayList<PackagePart>();
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/hssf/record/CFRule12Record.java b/src/java/org/apache/poi/hssf/record/CFRule12Record.java
index c9d0f17..e7974a0 100644
--- a/src/java/org/apache/poi/hssf/record/CFRule12Record.java
+++ b/src/java/org/apache/poi/hssf/record/CFRule12Record.java
@@ -19,6 +19,7 @@
 
 import java.util.Arrays;
 
+import org.apache.poi.hssf.record.cf.ColorGradientFormatting;
 import org.apache.poi.hssf.record.cf.IconMultiStateFormatting;
 import org.apache.poi.hssf.record.cf.Threshold;
 import org.apache.poi.hssf.record.common.FtrHeader;
@@ -56,9 +57,9 @@
     private byte[] template_params;
     
     private IconMultiStateFormatting multistate;
+    private ColorGradientFormatting color_gradient;
     
     // TODO Parse these
-    private byte[] gradient_data;
     private byte[] databar_data;
     private byte[] filter_data;
 
@@ -176,7 +177,7 @@
         
         byte type = getConditionType();
         if (type == CONDITION_TYPE_COLOR_SCALE) {
-            gradient_data = in.readRemainder();
+            color_gradient = new ColorGradientFormatting(in);
         } else if (type == CONDITION_TYPE_DATA_BAR) {
             databar_data = in.readRemainder();
         } else if (type == CONDITION_TYPE_FILTER) {
@@ -201,6 +202,21 @@
         return multistate;
     }
 
+    public boolean containsColorGradientBlock() {
+        return (color_gradient != null);
+    }
+    public ColorGradientFormatting getColorGradientFormatting() {
+        return color_gradient;
+    }
+    public ColorGradientFormatting createColorGradientFormatting() {
+        if (color_gradient != null) return color_gradient;
+        
+        // Convert, setup and return
+        setConditionType(CONDITION_TYPE_COLOR_SCALE);
+        color_gradient = new ColorGradientFormatting();
+        return color_gradient;
+    }
+
     /**
      * get the stack of the scale expression as a list
      *
@@ -261,7 +277,7 @@
         
         byte type = getConditionType();
         if (type == CONDITION_TYPE_COLOR_SCALE) {
-            out.write(gradient_data);
+            color_gradient.serialize(out);
         } else if (type == CONDITION_TYPE_DATA_BAR) {
             out.write(databar_data);
         } else if (type == CONDITION_TYPE_FILTER) {
@@ -285,7 +301,7 @@
         
         byte type = getConditionType();
         if (type == CONDITION_TYPE_COLOR_SCALE) {
-            len += gradient_data.length;
+            len += color_gradient.getDataLength();
         } else if (type == CONDITION_TYPE_DATA_BAR) {
             len += databar_data.length;
         } else if (type == CONDITION_TYPE_FILTER) {
@@ -319,9 +335,11 @@
         buffer.append("    .priority  =").append(priority).append("\n");
         buffer.append("    .template_type  =").append(template_type).append("\n");
         buffer.append("    .template_params=").append(HexDump.toHex(template_params)).append("\n");
-        buffer.append("    .gradient_data  =").append(HexDump.toHex(gradient_data)).append("\n");
         buffer.append("    .databar_data   =").append(HexDump.toHex(databar_data)).append("\n");
         buffer.append("    .filter_data    =").append(HexDump.toHex(filter_data)).append("\n");
+        if (color_gradient != null) {
+            buffer.append(color_gradient);
+        }
         if (multistate != null) {
             buffer.append(multistate);
         }
diff --git a/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java b/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java
new file mode 100644
index 0000000..3b58af7
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/record/cf/ColorGradientFormatting.java
@@ -0,0 +1,144 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.record.cf;
+
+import org.apache.poi.util.BitField;
+import org.apache.poi.util.BitFieldFactory;
+import org.apache.poi.util.LittleEndianInput;
+import org.apache.poi.util.LittleEndianOutput;
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Color Gradient / Color Scale Conditional Formatting Rule Record.
+ * (Called Color Gradient in the file format docs, but more commonly
+ *  Color Scale in the UI)
+ */
+public final class ColorGradientFormatting implements Cloneable {
+    private static POILogger log = POILogFactory.getLogger(ColorGradientFormatting.class);
+
+    private byte options = 0;
+    private Threshold[] thresholds;
+    private byte[] colors; // TODO Decode
+    
+    private static BitField clamp = BitFieldFactory.getInstance(0x01);
+    private static BitField background = BitFieldFactory.getInstance(0x02);
+    
+    public ColorGradientFormatting() {
+        options = 3;
+        thresholds = new Threshold[3];
+    }
+    public ColorGradientFormatting(LittleEndianInput in) {
+        in.readShort(); // Ignored
+        in.readByte();  // Reserved
+        int numI = in.readByte();
+        int numG = in.readByte();
+        if (numI != numG) {
+            log.log(POILogger.WARN, "Inconsistent Color Gradient defintion, found " + numI + " vs " + numG + " entries");
+        }
+        options = in.readByte();
+        
+        // TODO Are these correct?
+        thresholds = new Threshold[numI];
+        for (int i=0; i<thresholds.length; i++) {
+            thresholds[i] = new Threshold(in);
+            in.readDouble(); // Rather pointless value...
+        }
+        // TODO Decode colors
+        colors = new byte[in.available()];
+        in.readFully(colors);
+    }
+    
+    public int getNumControlPoints() {
+        return thresholds.length;
+    }
+    public void setNumControlPoints(int num) {
+        if (num != thresholds.length) {
+            thresholds = new Threshold[num];
+            // TODO Colors
+        }
+    }
+    
+    public Threshold[] getThresholds() {
+        return thresholds;
+    }
+    public void setThresholds(Threshold[] thresholds) {
+        this.thresholds = thresholds;
+    }
+
+    // TODO Colors
+    
+    public boolean isClampToCurve() {
+        return getOptionFlag(clamp);
+    }
+    public boolean isAppliesToBackground() {
+        return getOptionFlag(background);
+    }
+    private boolean getOptionFlag(BitField field) {
+        int value = field.getValue(options);
+        return value==0 ? false : true;
+    }
+    
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("    [Color Gradient Formatting]\n");
+        buffer.append("          .clamp     = ").append(isClampToCurve()).append("\n");
+        buffer.append("          .background= ").append(isAppliesToBackground()).append("\n");
+        for (Threshold t : thresholds) {
+            buffer.append(t.toString());
+        }
+        buffer.append("    [/Color Gradient Formatting]\n");
+        return buffer.toString();
+    }
+    
+    public Object clone()  {
+      ColorGradientFormatting rec = new ColorGradientFormatting();
+      rec.options = options;
+      rec.thresholds = new Threshold[thresholds.length];
+      System.arraycopy(thresholds, 0, rec.thresholds, 0, thresholds.length);
+      // TODO Colors
+      return rec;
+    }
+    
+    public int getDataLength() {
+        int len = 6;
+        for (Threshold t : thresholds) {
+            len += t.getDataLength();
+            len += 8;
+        }
+        len += colors.length;
+        return len;
+    }
+
+    public void serialize(LittleEndianOutput out) {
+        out.writeShort(0);
+        out.writeByte(0);
+        out.writeByte(thresholds.length);
+        out.writeByte(thresholds.length);
+        out.writeByte(options);
+        
+        double step = 1d / (thresholds.length-1);
+        for (int i=0; i<thresholds.length; i++) {
+            Threshold t = thresholds[i];
+            t.serialize(out);
+            out.writeDouble(step*i);
+        }
+        
+        out.write(colors);
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/record/cf/Threshold.java b/src/java/org/apache/poi/hssf/record/cf/Threshold.java
index 4620278..414bf0f 100644
--- a/src/java/org/apache/poi/hssf/record/cf/Threshold.java
+++ b/src/java/org/apache/poi/hssf/record/cf/Threshold.java
@@ -73,6 +73,14 @@
     }
     public void setType(byte type) {
         this.type = type;
+
+        // Ensure the value presense / absense is consistent for the new type
+        if (type == RangeType.MIN.id || type == RangeType.MAX.id ||
+               type == RangeType.FORMULA.id) {
+            this.value = null;
+        } else if (value == null) {
+            this.value = 0d;
+        }
     }
     public void setType(int type) {
         this.type = (byte)type;
@@ -86,6 +94,9 @@
     }
     public void setParsedExpression(Ptg[] ptgs) {
         formula = Formula.create(ptgs);
+        if (ptgs.length > 0) {
+            this.value = null;
+        }
     }
 
     public Double getValue() {
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFColorScaleFormatting.java b/src/java/org/apache/poi/hssf/usermodel/HSSFColorScaleFormatting.java
new file mode 100644
index 0000000..6e82072
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFColorScaleFormatting.java
@@ -0,0 +1,75 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.hssf.record.CFRule12Record;
+import org.apache.poi.hssf.record.cf.ColorGradientFormatting;
+import org.apache.poi.hssf.record.cf.Threshold;
+import org.apache.poi.ss.usermodel.Color;
+import org.apache.poi.ss.usermodel.ConditionalFormattingThreshold;
+
+/**
+ * High level representation for Color Scale / Color Gradient 
+ *  Formatting component of Conditional Formatting settings
+ */
+public final class HSSFColorScaleFormatting implements org.apache.poi.ss.usermodel.ColorScaleFormatting {
+    private final HSSFSheet sheet;
+    private final CFRule12Record cfRule12Record;
+    private final ColorGradientFormatting colorFormatting;
+
+    protected HSSFColorScaleFormatting(CFRule12Record cfRule12Record, HSSFSheet sheet) {
+        this.sheet = sheet;
+        this.cfRule12Record = cfRule12Record;
+        this.colorFormatting = this.cfRule12Record.getColorGradientFormatting();
+    }
+
+    public int getNumControlPoints() {
+        return colorFormatting.getNumControlPoints();
+    }
+    public void setNumControlPoints(int num) {
+        colorFormatting.setNumControlPoints(num);
+    }
+
+    public Color[] getColors() {
+        return null; // TODO
+    }
+    public void setColors(Color[] colors) {
+        // TODO
+    }
+
+    public HSSFConditionalFormattingThreshold[] getThresholds() {
+        Threshold[] t = colorFormatting.getThresholds();
+        HSSFConditionalFormattingThreshold[] ht = new HSSFConditionalFormattingThreshold[t.length];
+        for (int i=0; i<t.length; i++) {
+            ht[i] = new HSSFConditionalFormattingThreshold(t[i], sheet);
+        }
+        return ht;
+    }
+
+    public void setThresholds(ConditionalFormattingThreshold[] thresholds) {
+        Threshold[] t = new Threshold[thresholds.length];
+        for (int i=0; i<t.length; i++) {
+            t[i] = ((HSSFConditionalFormattingThreshold)thresholds[i]).getThreshold();
+        }
+        colorFormatting.setThresholds(t);
+    }
+
+    public HSSFConditionalFormattingThreshold createThreshold() {
+        return new HSSFConditionalFormattingThreshold(new Threshold(), sheet);
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
index a999488..a6cdbcf 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
@@ -23,6 +23,7 @@
 import org.apache.poi.hssf.record.CFRuleBase.ComparisonOperator;
 import org.apache.poi.hssf.record.CFRuleRecord;
 import org.apache.poi.hssf.record.cf.BorderFormatting;
+import org.apache.poi.hssf.record.cf.ColorGradientFormatting;
 import org.apache.poi.hssf.record.cf.FontFormatting;
 import org.apache.poi.hssf.record.cf.IconMultiStateFormatting;
 import org.apache.poi.hssf.record.cf.PatternFormatting;
@@ -55,10 +56,18 @@
         cfRuleRecord = pRuleRecord;
     }
 
-    CFRuleBase getCfRuleRecord()
-    {
+    CFRuleBase getCfRuleRecord() {
         return cfRuleRecord;
     }
+    private CFRule12Record getCFRule12Record(boolean create) {
+        if (cfRuleRecord instanceof CFRule12Record) {
+            // Good
+        } else {
+            if (create) throw new IllegalArgumentException("Can't convert a CF into a CF12 record");
+            return null;
+        }
+        return (CFRule12Record)cfRuleRecord;
+    }
 
     private HSSFFontFormatting getFontFormatting(boolean create)
     {
@@ -171,13 +180,7 @@
     }
     
     private HSSFIconMultiStateFormatting getMultiStateFormatting(boolean create) {
-        if (cfRuleRecord instanceof CFRule12Record) {
-            // Good
-        } else {
-            if (create) throw new IllegalArgumentException("Can't convert a CF into a CF12 record");
-            return null;
-        }
-        CFRule12Record cfRule12Record = (CFRule12Record)cfRuleRecord;
+        CFRule12Record cfRule12Record = getCFRule12Record(create);
         IconMultiStateFormatting iconFormatting = cfRule12Record.getMultiStateFormatting();
         if (iconFormatting != null)
         {
@@ -193,14 +196,12 @@
             return null;
         }
     }
-    
     /**
      * @return icon / multi-state formatting object if defined, <code>null</code> otherwise
      */
     public HSSFIconMultiStateFormatting getMultiStateFormatting() {
         return getMultiStateFormatting(false);
     }
-
     /**
      * create a new icon / multi-state formatting object if it does not exist,
      * otherwise just return the existing object.
@@ -209,6 +210,37 @@
         return getMultiStateFormatting(true);
     }
     
+    private HSSFColorScaleFormatting getColorScaleFormatting(boolean create) {
+        CFRule12Record cfRule12Record = getCFRule12Record(create);
+        ColorGradientFormatting colorFormatting = cfRule12Record.getColorGradientFormatting();
+        if (colorFormatting != null)
+        {
+            return new HSSFColorScaleFormatting(cfRule12Record, sheet);
+        }
+        else if( create )
+        {
+            colorFormatting = cfRule12Record.createColorGradientFormatting();
+            return new HSSFColorScaleFormatting(cfRule12Record, sheet);
+        }
+        else
+        {
+            return null;
+        }
+    }
+    /**
+     * @return color scale / gradient formatting object if defined, <code>null</code> otherwise
+     */
+    public HSSFColorScaleFormatting getColorScaleFormatting() {
+        return getColorScaleFormatting(false);
+    }
+    /**
+     * create a new color scale / gradient formatting object if it does not exist,
+     * otherwise just return the existing object.
+     */
+    public HSSFColorScaleFormatting createColorScaleFormatting() {
+        return getColorScaleFormatting(true);
+    }
+    
     /**
      * @return -  the conditiontype for the cfrule
      */
diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocument.java b/src/ooxml/java/org/apache/poi/POIXMLDocument.java
index 0e18ee1..0352d5c 100644
--- a/src/ooxml/java/org/apache/poi/POIXMLDocument.java
+++ b/src/ooxml/java/org/apache/poi/POIXMLDocument.java
@@ -57,6 +57,15 @@
 
     protected POIXMLDocument(OPCPackage pkg) {
         super(pkg);
+        init(pkg);
+    }
+    
+    protected POIXMLDocument(OPCPackage pkg, String coreDocumentRel) {
+        super(pkg, coreDocumentRel);
+        init(pkg);
+    }
+    
+    private void init(OPCPackage pkg) {
         this.pkg = pkg;
         
         // Workaround for XMLBEANS-512 - ensure that when we parse
diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
index f051eb3..857f0da 100644
--- a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
+++ b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java
@@ -63,7 +63,7 @@
         DEFAULT_XML_OPTIONS.setCharacterEncoding("UTF-8");
     }
 
-
+    private String coreDocumentRel = PackageRelationshipTypes.CORE_DOCUMENT;
     private PackagePart packagePart;
     private PackageRelationship packageRel;
     private POIXMLDocumentPart parent;
@@ -93,7 +93,16 @@
      * Construct POIXMLDocumentPart representing a "core document" package part.
      */
     public POIXMLDocumentPart(OPCPackage pkg) {
-        PackageRelationship coreRel = pkg.getRelationshipsByType(PackageRelationshipTypes.CORE_DOCUMENT).getRelationship(0);
+        this(pkg, PackageRelationshipTypes.CORE_DOCUMENT);
+    }
+    
+    /**
+     * Construct POIXMLDocumentPart representing a custom "core document" package part.
+     */
+    public POIXMLDocumentPart(OPCPackage pkg, String coreDocumentRel) {
+        this.coreDocumentRel = coreDocumentRel;
+        PackageRelationship coreRel = pkg.getRelationshipsByType(this.coreDocumentRel).getRelationship(0);
+
         if (coreRel == null) {
             coreRel = pkg.getRelationshipsByType(PackageRelationshipTypes.STRICT_CORE_DOCUMENT).getRelationship(0);
             if (coreRel != null) {
@@ -151,10 +160,10 @@
      */
     protected final void rebase(OPCPackage pkg) throws InvalidFormatException {
         PackageRelationshipCollection cores =
-            packagePart.getRelationshipsByType(PackageRelationshipTypes.CORE_DOCUMENT);
+            packagePart.getRelationshipsByType(coreDocumentRel);
         if(cores.size() != 1) {
             throw new IllegalStateException(
-                "Tried to rebase using " + PackageRelationshipTypes.CORE_DOCUMENT +
+                "Tried to rebase using " + coreDocumentRel +
                 " but found " + cores.size() + " parts of the right type"
             );
         }
diff --git a/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java b/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java
index 55f4093..2c41b18 100644
--- a/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java
+++ b/src/ooxml/testcases/org/apache/poi/TestPOIXMLDocument.java
@@ -31,6 +31,7 @@
 import org.apache.poi.openxml4j.opc.OPCPackage;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
 import org.apache.poi.util.PackageHelper;
 import org.apache.poi.util.TempFile;
 
@@ -44,6 +45,10 @@
         public OPCParser(OPCPackage pkg) {
             super(pkg);
         }
+        
+        public OPCParser(OPCPackage pkg, String coreDocumentRel) {
+            super(pkg, coreDocumentRel);
+        }
 
         @Override
         public List<PackagePart> getAllEmbedds() {
@@ -181,4 +186,33 @@
         part.onDocumentCreate();
         //part.getTargetPart(null);
     }
+    
+    public void testVSDX() throws Exception {
+        OPCPackage open = PackageHelper.open(POIDataSamples.getDiagramInstance().openResourceAsStream("test.vsdx"));
+        
+        POIXMLDocument part = new OPCParser(open, PackageRelationshipTypes.VISIO_CORE_DOCUMENT);
+        
+        assertNotNull(part);
+        assertEquals(0, part.getRelationCounter());
+    }
+    
+    public void testVSDXPart() throws Exception {
+        OPCPackage open = PackageHelper.open(POIDataSamples.getDiagramInstance().openResourceAsStream("test.vsdx"));
+        
+        POIXMLDocumentPart part = new POIXMLDocumentPart(open, PackageRelationshipTypes.VISIO_CORE_DOCUMENT);
+        
+        assertNotNull(part);
+        assertEquals(0, part.getRelationCounter());
+    }
+    
+    public void testInvalidCoreRel() throws Exception {
+        OPCPackage open = PackageHelper.open(POIDataSamples.getDiagramInstance().openResourceAsStream("test.vsdx"));
+        
+        try {
+            new POIXMLDocumentPart(open, "somethingillegal");
+            fail("Unknown core ref will throw exception");
+        } catch (POIXMLException e) {
+            // expected here
+        }
+    }
 }
diff --git a/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java b/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java
index b8eeb20..1a130b7 100644
--- a/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java
+++ b/src/testcases/org/apache/poi/ss/usermodel/BaseTestConditionalFormatting.java
@@ -101,6 +101,7 @@
     /**

      * Test format conditions based on a boolean formula

      */

+    @SuppressWarnings("deprecation")

     public void testBooleanFormulaConditions() {

         Workbook wb = _testDataProvider.createWorkbook();

         Sheet sh = wb.createSheet();

@@ -136,6 +137,7 @@
         assertEquals("B1:B3", ranges2[0].formatAsString());

     }

 

+    @SuppressWarnings("deprecation")

     public void testSingleFormulaConditions() {

         Workbook wb = _testDataProvider.createWorkbook();

         Sheet sh = wb.createSheet();

@@ -207,6 +209,7 @@
         assertEquals(ComparisonOperator.NOT_BETWEEN, rule9.getComparisonOperation());

     }

 

+    @SuppressWarnings("deprecation")

     public void testCopy() {

         Workbook wb = _testDataProvider.createWorkbook();

         Sheet sheet1 = wb.createSheet();

@@ -546,18 +549,17 @@
         Sheet s = wb.getSheet("CF");

         ConditionalFormatting cf = null;

         ConditionalFormattingRule cr = null;

-        IconMultiStateFormatting icon = null;

-        ConditionalFormattingThreshold th = null;

+

         

         // Sanity check data

         assertEquals("Values", s.getRow(0).getCell(0).toString());

         assertEquals("10.0", s.getRow(2).getCell(0).toString());

 

-        // Check we found all the conditional formattings rules we should have

+        // Check we found all the conditional formatting rules we should have

         SheetConditionalFormatting sheetCF = s.getSheetConditionalFormatting();

         int numCF = 3;

         int numCF12 = 15;

-        int numCFEX = 0; // TODO This should be 1, but we don't support CFEX formattings yet

+        int numCFEX = 0; // TODO This should be 2, but we don't support CFEX formattings yet, see #58149

         assertEquals(numCF+numCF12+numCFEX, sheetCF.getNumConditionalFormattings());

         

         int fCF = 0, fCF12 = 0, fCFEX = 0;

@@ -646,26 +648,18 @@
         // TODO Support Data Bars, then check the rest of this rule

         

         

-        // Colours R->G - Column F

+        // Colours Red->Yellow->Green - Column F

         cf = sheetCF.getConditionalFormattingAt(3);

         assertEquals(1, cf.getFormattingRanges().length);

         assertEquals("F2:F17", cf.getFormattingRanges()[0].formatAsString());

-        

-        assertEquals(1, cf.getNumberOfRules());

-        cr = cf.getRule(0);

-        assertEquals(ConditionType.COLOR_SCALE, cr.getConditionTypeType());

-        // TODO Support Color Scales, then check the rest of this rule

+        assertColorScale(cf, "F8696B", "FFEB84", "63BE7B");

 

         

-        // Colours BWR - Column G

+        // Colours Blue->White->Red - Column G

         cf = sheetCF.getConditionalFormattingAt(4);

         assertEquals(1, cf.getFormattingRanges().length);

         assertEquals("G2:G17", cf.getFormattingRanges()[0].formatAsString());

-        

-        assertEquals(1, cf.getNumberOfRules());

-        cr = cf.getRule(0);

-        assertEquals(ConditionType.COLOR_SCALE, cr.getConditionTypeType());

-        // TODO Support Color Scales, then check the rest of this rule

+        assertColorScale(cf, "5A8AC6", "FCFCFF", "F8696B");

 

         

         // Icons : Default - Column H, percentage thresholds

@@ -696,22 +690,95 @@
         assertIconSetPercentages(cf, IconSet.GYRB_4_TRAFFIC_LIGHTS, 0d, 25d, 50d, 75d);

 

         

-        // Icons : 3 symbols - Column L

-        // Icons : 3 flags - Column M

-        // Icons : 3 symbols 2 - Column N

-        // Icons : 3 arrows - Column O     

-        // Icons : 5 arrows grey - Column P    

-        // Icons : 3 stars (ext) - Column Q

-        // Icons : 4 ratings - Column R

-        // Icons : 5 ratings - Column S

-        // Custom Icon+Format - Column T

-        // Mixed icons - Column U

+        // Icons : 3 symbols with backgrounds - Column L

+        cf = sheetCF.getConditionalFormattingAt(9);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("L2:L17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.GYR_3_SYMBOLS_CIRCLE, 0d, 33d, 67d);

 

+        

+        // Icons : 3 flags - Column M2 Only

+        cf = sheetCF.getConditionalFormattingAt(10);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("M2", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.GYR_3_FLAGS, 0d, 33d, 67d);

+

+        // Icons : 3 flags - Column M (all)

+        cf = sheetCF.getConditionalFormattingAt(11);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("M2:M17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.GYR_3_FLAGS, 0d, 33d, 67d);

+

+        

+        // Icons : 3 symbols 2 (no background) - Column N

+        cf = sheetCF.getConditionalFormattingAt(12);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("N2:N17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.GYR_3_SYMBOLS, 0d, 33d, 67d);

+

+        

+        // Icons : 3 arrows - Column O

+        cf = sheetCF.getConditionalFormattingAt(13);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("O2:O17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.GYR_3_ARROW, 0d, 33d, 67d);

+

+        

+        // Icons : 5 arrows grey - Column P    

+        cf = sheetCF.getConditionalFormattingAt(14);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("P2:P17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.GREY_5_ARROWS, 0d, 20d, 40d, 60d, 80d);

+

+        

+        // Icons : 3 stars (ext) - Column Q

+        // TODO Support EXT formattings

+

+        

+        // Icons : 4 ratings - Column R

+        cf = sheetCF.getConditionalFormattingAt(15);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("R2:R17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.RATINGS_4, 0d, 25d, 50d, 75d);

+

+        

+        // Icons : 5 ratings - Column S

+        cf = sheetCF.getConditionalFormattingAt(16);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("S2:S17", cf.getFormattingRanges()[0].formatAsString());

+        assertIconSetPercentages(cf, IconSet.RATINGS_5, 0d, 20d, 40d, 60d, 80d);

+

+        

+        // Custom Icon+Format - Column T

+        cf = sheetCF.getConditionalFormattingAt(17);

+        assertEquals(1, cf.getFormattingRanges().length);

+        assertEquals("T2:T17", cf.getFormattingRanges()[0].formatAsString());

+        

+        // TODO Support IconSet + Other CFs with 2 rules

+//        assertEquals(2, cf.getNumberOfRules());

+//        cr = cf.getRule(0);

+//        assertIconSetPercentages(cr, IconSet.GYR_3_TRAFFIC_LIGHTS_BOX, 0d, 33d, 67d);

+//        cr = cf.getRule(1);

+//        assertEquals(ConditionType.FORMULA, cr.getConditionTypeType());

+//        assertEquals(ComparisonOperator.NO_COMPARISON, cr.getComparisonOperation());

+//        // TODO Why aren't these two the same between formats?

+//        if (cr instanceof HSSFConditionalFormattingRule) {

+//            assertEquals("MOD(ROW($T1),2)=1", cr.getFormula1());

+//        } else {

+//            assertEquals("MOD(ROW($T2),2)=1", cr.getFormula1());

+//        }

+//        assertEquals(null, cr.getFormula2());

+        

+        

+        // Mixed icons - Column U

+        // TODO Support EXT formattings

     }

     private void assertIconSetPercentages(ConditionalFormatting cf, IconSet iconset, Double...vals) {

         assertEquals(1, cf.getNumberOfRules());

         ConditionalFormattingRule cr = cf.getRule(0);

-        

+        assertIconSetPercentages(cr, iconset, vals);

+    }        

+    private void assertIconSetPercentages(ConditionalFormattingRule cr, IconSet iconset, Double...vals) {

         assertEquals(ConditionType.ICON_SET, cr.getConditionTypeType());

         assertEquals(ComparisonOperator.NO_COMPARISON, cr.getComparisonOperation());

         assertEquals(null, cr.getFormula1());

@@ -733,6 +800,50 @@
             assertEquals(null, th.getFormula());

         }

     }

+    

+    private void assertColorScale(ConditionalFormatting cf, String... colors) {

+        assertEquals(1, cf.getNumberOfRules());

+        ConditionalFormattingRule cr = cf.getRule(0);

+        assertColorScale(cr, colors);

+    }        

+    private void assertColorScale(ConditionalFormattingRule cr, String... colors) {

+        assertEquals(ConditionType.COLOR_SCALE, cr.getConditionTypeType());

+        assertEquals(ComparisonOperator.NO_COMPARISON, cr.getComparisonOperation());

+        assertEquals(null, cr.getFormula1());

+        assertEquals(null, cr.getFormula2());

+        

+        // TODO Implement

+/*

+        ColorScaleFormatting color = cr.getColorScaleFormatting();

+        assertNotNull(color);

+        assertNotNull(color.getColors());

+        assertNotNull(color.getThresholds());

+        assertEquals(colors.length, color.getNumControlPoints());

+        assertEquals(colors.length, color.getColors().length);

+        assertEquals(colors.length, color.getThresholds().length);

+        

+        // Thresholds should be Min / (evenly spaced) / Max

+        int steps = 100 / (colors.length-1);

+        for (int i=0; i<colors.length; i++) {

+            ConditionalFormattingThreshold th = color.getThresholds()[i];

+            if (i == 0) {

+                assertEquals(RangeType.MIN, th.getRangeType());

+            } else if (i == colors.length-1) {

+                assertEquals(RangeType.MAX, th.getRangeType());

+            } else {

+                assertEquals(RangeType.PERCENT, th.getRangeType());

+                assertEquals(steps*i, th.getValue());

+            }

+            assertEquals(null, th.getFormula());

+        }

+        

+        // Colors should match

+        for (int i=0; i<colors.length; i++) {

+            Color c = color.getColors()[i];

+            assertEquals(colors[i], c.toString());

+        }

+*/

+    }

 

     public void testCreateFontFormatting() {

         Workbook workbook = _testDataProvider.createWorkbook();

@@ -907,8 +1018,7 @@
         assertEquals(BorderFormatting.BORDER_HAIR, r1fp.getBorderRight());

     }

     

-    // TODO Fix this test to work for HSSF

-    public void DISABLEDtestCreateIconFormatting() {

+    public void testCreateIconFormatting() {

         Workbook workbook = _testDataProvider.createWorkbook();

         Sheet sheet = workbook.createSheet();