]> source.dussan.org Git - poi.git/commitdiff
initial support for reading shapes, see patch from June 8 in Bugzilla 53372
authorYegor Kozlov <yegor@apache.org>
Fri, 8 Jun 2012 17:47:37 +0000 (17:47 +0000)
committerYegor Kozlov <yegor@apache.org>
Fri, 8 Jun 2012 17:47:37 +0000 (17:47 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1348168 13f79535-47bb-0310-9956-ffa450edef68

15 files changed:
src/java/org/apache/poi/hssf/record/EscherAggregate.java
src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java
src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java
src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/model/TestDrawingAggregate.java
src/testcases/org/apache/poi/hssf/usermodel/HSSFTestHelper.java
test-data/spreadsheet/SolverContainerAfterSPGR.xls [new file with mode: 0755]

index 3bb7127356a5d7eefb1445afab1e3ad187369986..1d48ff751f4bb67182109c8c94b737ebcd942eb9 100644 (file)
@@ -43,16 +43,7 @@ import org.apache.poi.hssf.model.CommentShape;
 import org.apache.poi.hssf.model.ConvertAnchor;
 import org.apache.poi.hssf.model.DrawingManager2;
 import org.apache.poi.hssf.model.TextboxShape;
-import org.apache.poi.hssf.usermodel.HSSFAnchor;
-import org.apache.poi.hssf.usermodel.HSSFChildAnchor;
-import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
-import org.apache.poi.hssf.usermodel.HSSFPatriarch;
-import org.apache.poi.hssf.usermodel.HSSFPicture;
-import org.apache.poi.hssf.usermodel.HSSFShape;
-import org.apache.poi.hssf.usermodel.HSSFShapeContainer;
-import org.apache.poi.hssf.usermodel.HSSFShapeGroup;
-import org.apache.poi.hssf.usermodel.HSSFSimpleShape;
-import org.apache.poi.hssf.usermodel.HSSFTextbox;
+import org.apache.poi.hssf.usermodel.*;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 
@@ -322,7 +313,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
     /**
      * list of "tail" records that need to be serialized after all drawing group records
      */
-    private List tailRec = new ArrayList();
+    private List<Record> tailRec = new ArrayList<Record>();
 
     public EscherAggregate(DrawingManager2 drawingManager) {
         this.drawingManager = drawingManager;
@@ -413,7 +404,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
         }
 
         // Decode the shapes
-        //             agg.escherRecords = new ArrayList();
+        // agg.escherRecords = new ArrayList();
         int pos = 0;
         while (pos < buffer.size()) {
             EscherRecord r = recordFactory.createRecord(buffer.toByteArray(), pos);
@@ -486,7 +477,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
 
                 public void afterRecordSerialize(int offset, short recordId, int size, EscherRecord record) {
                     if (recordId == EscherClientDataRecord.RECORD_ID || recordId == EscherTextboxRecord.RECORD_ID) {
-                        spEndingOffsets.add(Integer.valueOf(offset));
+                        spEndingOffsets.add(offset);
                         shapes.add(record);
                     }
                 }
@@ -501,12 +492,17 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
         pos = offset;
         int writtenEscherBytes = 0;
         for (int i = 1; i < shapes.size(); i++) {
-            int endOffset = ((Integer) spEndingOffsets.get(i)).intValue() - 1;
+            int endOffset;
+            if (i == shapes.size()-1){
+                endOffset = buffer.length - 1;
+            } else {
+                endOffset = (Integer) spEndingOffsets.get(i) - 1;
+            }
             int startOffset;
             if (i == 1)
                 startOffset = 0;
             else
-                startOffset = ((Integer) spEndingOffsets.get(i - 1)).intValue();
+                startOffset = (Integer) spEndingOffsets.get(i - 1);
 
 
             byte[] drawingData = new byte[endOffset - startOffset + 1];
@@ -790,7 +786,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
             container.getChildren().add(shape);
     }
 
-    private static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) {
+    public static HSSFClientAnchor toClientAnchor(EscherClientAnchorRecord anchorRecord) {
         HSSFClientAnchor anchor = new HSSFClientAnchor();
         anchor.setAnchorType(anchorRecord.getFlag());
         anchor.setCol1(anchorRecord.getCol1());
@@ -804,7 +800,7 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
         return anchor;
     }
 
-    private static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) {
+    public static HSSFChildAnchor toChildAnchor(EscherChildAnchorRecord anchorRecord) {
         HSSFChildAnchor anchor = new HSSFChildAnchor();
 //        anchor.setAnchorType(anchorRecord.getFlag());
 //        anchor.setCol1( anchorRecord.getCol1() );
@@ -1081,4 +1077,24 @@ public final class EscherAggregate extends AbstractEscherHolderRecord {
         return null;
     }
 
+    /**
+     * Returns the mapping  of {@link EscherClientDataRecord} and {@link EscherTextboxRecord}
+     * to their {@link TextObjectRecord} or {@link ObjRecord} .
+     *
+     * We need to access it outside of EscherAggregate when building shapes
+     *
+     * @return
+     */
+    public Map<EscherRecord, Record> getShapeToObjMapping(){
+        return Collections.unmodifiableMap(shapeToObj);
+    }
+
+    /**
+     *
+     * @return tails records. We need to access them when building shapes.
+     * Every HSSFComment shape has a link to a NoteRecord from the tailRec collection.
+     */
+    public List<Record> getTailRecords(){
+        return Collections.unmodifiableList(tailRec);
+    }
 }
index 513ac619f4f1c8a7851d5dadb8e1ed4e98ab4383..ccd0e620cfc04526dc9ef6bd0d4c53a90aa5db3b 100644 (file)
 package org.apache.poi.hssf.usermodel;
 
 
+import org.apache.poi.ddf.EscherChildAnchorRecord;
+
 public final class HSSFChildAnchor extends HSSFAnchor {
+
+    private EscherChildAnchorRecord escherChildAnchorRecord;
+
+    public HSSFChildAnchor(EscherChildAnchorRecord escherChildAnchorRecord) {
+        this.escherChildAnchorRecord = escherChildAnchorRecord;
+    }
+
     public HSSFChildAnchor()
     {
     }
index cffb00cd5582324a7d9dc905277b05082c8c4c40..a040144c2709cec947f4bc6f3de0abec0eda4d41 100644 (file)
@@ -17,6 +17,7 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import org.apache.poi.ddf.EscherClientAnchorRecord;
 import org.apache.poi.ss.usermodel.ClientAnchor;
 
 
@@ -33,6 +34,13 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
     int row2;
     int anchorType;
 
+    private EscherClientAnchorRecord escherClientAnchorRecord;
+
+    public HSSFClientAnchor(EscherClientAnchorRecord escherClientAnchorRecord) {
+        this.escherClientAnchorRecord = escherClientAnchorRecord;
+        //TODO set properties or read properties from EscherRecord ?
+    }
+
     /**
      * Creates a new client anchor and defaults all the anchor positions to 0.
      */
index 672f82cc734db4939d814ff3752e02fad93210fb..71549bbf312ea7782b70f63f9fe123029da0d185 100644 (file)
@@ -22,9 +22,11 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.poi.ddf.EscherComplexProperty;
+import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherOptRecord;
 import org.apache.poi.ddf.EscherProperty;
 import org.apache.poi.ddf.EscherBSERecord;
+import org.apache.poi.ddf.EscherSpgrRecord;
 import org.apache.poi.hssf.record.EscherAggregate;
 import org.apache.poi.ss.usermodel.Chart;
 import org.apache.poi.util.StringUtil;
@@ -314,4 +316,23 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing {
                throw new RuntimeException("NotImplemented");
        }
 
+
+    void buildShapeTree(){
+        EscherContainerRecord dgContainer = _boundAggregate.getEscherContainer();
+        EscherContainerRecord spgrConrainer = dgContainer.getChildContainers().get(0);
+        List<EscherContainerRecord> spgrChildren = spgrConrainer.getChildContainers();
+
+        for(int i = 0; i < spgrChildren.size(); i++){
+            EscherContainerRecord spContainer = spgrChildren.get(i);
+            if (i == 0){
+                EscherSpgrRecord spgr = (EscherSpgrRecord)spContainer.getChildById(EscherSpgrRecord.RECORD_ID);
+                setCoordinates(
+                        spgr.getRectX1(), spgr.getRectY1(),
+                        spgr.getRectX2(), spgr.getRectY2()
+                );
+            } else {
+                HSSFShapeFactory.createShapeTree(spContainer, _boundAggregate, this);
+            }
+        }
+    }
 }
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java
new file mode 100644 (file)
index 0000000..0a0468c
--- /dev/null
@@ -0,0 +1,15 @@
+package org.apache.poi.hssf.usermodel;\r
+\r
+import org.apache.poi.ddf.EscherContainerRecord;\r
+import org.apache.poi.hssf.record.ObjRecord;\r
+\r
+/**\r
+ * @author Evgeniy Berlog\r
+ * @date 08.06.12\r
+ */\r
+public class HSSFRectangle extends HSSFShape{\r
+\r
+    public HSSFRectangle(EscherContainerRecord spContainer, ObjRecord objRecord) {\r
+        super(spContainer, objRecord);\r
+    }\r
+}\r
index 3c586340fe096cfd434feb45183bad388041b5b8..7ffdfdb9baec19c6cf5d4e5817498fa1072b9b66 100644 (file)
@@ -17,6 +17,9 @@
 
 package org.apache.poi.hssf.usermodel;
 
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.hssf.record.ObjRecord;
+
 /**
  * An abstract shape.
  *
@@ -40,7 +43,7 @@ public abstract class HSSFShape {
     public static final int LINESTYLE_NONE = -1;
 
     // TODO - make all these fields private
-    final HSSFShape parent;  
+    HSSFShape parent;
     HSSFAnchor anchor;
     HSSFPatriarch _patriarch;  
     private int _lineStyleColor = 0x08000040;
@@ -49,15 +52,30 @@ public abstract class HSSFShape {
     private int _lineStyle = LINESTYLE_SOLID;
     private boolean _noFill = false;
 
+    private EscherContainerRecord spContainer;
+    private ObjRecord objRecord;
+
+    public HSSFShape(EscherContainerRecord spContainer, ObjRecord objRecord){
+        this.spContainer = spContainer;
+        this.objRecord = objRecord;
+    }
     /**
      * Create a new shape with the specified parent and anchor.
      */
-    HSSFShape( HSSFShape parent, HSSFAnchor anchor )
+    public HSSFShape( HSSFShape parent, HSSFAnchor anchor )
     {
         this.parent = parent;
         this.anchor = anchor;
     }
 
+    public EscherContainerRecord getSpContainer() {
+        return spContainer;
+    }
+
+    public ObjRecord getObjRecord() {
+        return objRecord;
+    }
+
     /**
      * Gets the parent shape.
      */
index 99e6a5de6a9abb1875116d50466e820d1a1d3d66..181b3d17a99e3f6c025198a27a757767109f4218 100644 (file)
@@ -31,4 +31,15 @@ public interface HSSFShapeContainer
      */
     List getChildren();
 
+    /**
+     * add shape to the list of child records
+     * @param shape
+     */
+    public void addShape(HSSFShape shape);
+
+    /**
+     * set coordinates of this group relative to the parent
+     */
+    void setCoordinates( int x1, int y1, int x2, int y2 );
+
 }
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java
new file mode 100644 (file)
index 0000000..fc88a2a
--- /dev/null
@@ -0,0 +1,157 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ *    contributor license agreements.  See the NOTICE file distributed with\r
+ *    this work for additional information regarding copyright ownership.\r
+ *    The ASF licenses this file to You under the Apache License, Version 2.0\r
+ *    (the "License"); you may not use this file except in compliance with\r
+ *    the License.  You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *    Unless required by applicable law or agreed to in writing, software\r
+ *    distributed under the License is distributed on an "AS IS" BASIS,\r
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *    See the License for the specific language governing permissions and\r
+ *    limitations under the License.\r
+ */\r
+\r
+package org.apache.poi.hssf.usermodel;\r
+\r
+import org.apache.poi.ddf.EscherClientDataRecord;\r
+import org.apache.poi.ddf.EscherContainerRecord;\r
+import org.apache.poi.ddf.EscherRecord;\r
+import org.apache.poi.ddf.EscherSpRecord;\r
+import org.apache.poi.ddf.EscherSpgrRecord;\r
+import org.apache.poi.ddf.EscherTextboxRecord;\r
+import org.apache.poi.hssf.model.TextboxShape;\r
+import org.apache.poi.hssf.record.CommonObjectDataSubRecord;\r
+import org.apache.poi.hssf.record.EscherAggregate;\r
+import org.apache.poi.hssf.record.NoteRecord;\r
+import org.apache.poi.hssf.record.ObjRecord;\r
+import org.apache.poi.hssf.record.Record;\r
+import org.apache.poi.hssf.record.TextObjectRecord;\r
+import org.apache.poi.hssf.usermodel.drawing.HSSFShapeType;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+/**\r
+ * @author evgeniy\r
+ * date: 05.06.12\r
+ */\r
+public class HSSFShapeFactory {\r
+\r
+    private static final Map<Short, Class> shapeTypeToClass = new HashMap<Short, Class>(HSSFShapeType.values().length);\r
+    private static final ReflectionConstructorShapeCreator shapeCreator = new ReflectionConstructorShapeCreator(shapeTypeToClass);\r
+\r
+    static {\r
+        for (HSSFShapeType type: HSSFShapeType.values()){\r
+            shapeTypeToClass.put(type.getType(), type.getShape());\r
+        }\r
+    }\r
+\r
+    private static class ReflectionConstructorShapeCreator {\r
+\r
+        private final Map<Short, Class> shapeTypeToClass;\r
+\r
+        private ReflectionConstructorShapeCreator(Map<Short, Class> shapeTypeToClass) {\r
+            this.shapeTypeToClass = shapeTypeToClass;\r
+        }\r
+\r
+        public HSSFShape createNewShape(Short type, EscherContainerRecord spContainer, ObjRecord objRecord){\r
+            if (!shapeTypeToClass.containsKey(type)){\r
+                return new HSSFUnknownShape(spContainer, objRecord);\r
+            }\r
+            Class clazz = shapeTypeToClass.get(type);\r
+            if (null == clazz){\r
+                System.out.println("No class attached to shape type: "+type);\r
+                return new HSSFUnknownShape(spContainer, objRecord);\r
+            }\r
+            try{\r
+                Constructor constructor = clazz.getConstructor(new Class[]{EscherContainerRecord.class, ObjRecord.class});\r
+                return (HSSFShape) constructor.newInstance(spContainer, objRecord);\r
+            } catch (NoSuchMethodException e) {\r
+                throw new IllegalStateException(clazz.getName() +" doesn't have required for shapes constructor");\r
+            } catch (Exception e) {\r
+                throw new IllegalStateException("Couldn't create new instance of " + clazz.getName());\r
+            }\r
+        }\r
+    }\r
+\r
+    public static HSSFShape createShape(EscherRecord container, ObjRecord objRecord){\r
+        if (0 == container.getChildRecords().size()){\r
+            throw new IllegalArgumentException("Couldn't create shape from empty escher container");\r
+        }\r
+        if (container.getChild(0) instanceof EscherSpgrRecord){\r
+            return new HSSFShapeGroup((EscherContainerRecord) container, objRecord);\r
+        }\r
+\r
+        //TODO implement cases for all shapes\r
+        return new HSSFUnknownShape(container, objRecord);\r
+    }\r
+\r
+    public static HSSFShapeGroup createShapeGroup(){\r
+        return null;\r
+    }\r
+\r
+    public static HSSFShapeGroup createSimpleShape(EscherRecord container, ObjRecord objRecord){\r
+        return null;\r
+    }\r
+\r
+    public static void createShapeTree(EscherContainerRecord container, EscherAggregate agg, HSSFShapeContainer out){\r
+        if(container.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){\r
+            HSSFShapeGroup group = new HSSFShapeGroup(container,\r
+                    null /* shape containers don't have a associated Obj record*/);\r
+            List<EscherContainerRecord> children = container.getChildContainers();\r
+            // skip the first child record, it is group descriptor\r
+            for(int i = 0; i < children.size(); i++) {\r
+                EscherContainerRecord spContainer = children.get(i);\r
+                if(i == 0){\r
+                    EscherSpgrRecord spgr = (EscherSpgrRecord)spContainer.getChildById(EscherSpgrRecord.RECORD_ID);\r
+                    group.setCoordinates(\r
+                            spgr.getRectX1(), spgr.getRectY1(),\r
+                            spgr.getRectX2(), spgr.getRectY2()\r
+                    );\r
+                } else {\r
+                    createShapeTree(spContainer, agg, group);\r
+                }\r
+            }\r
+            out.addShape(group);\r
+        } else if (container.getRecordId() == EscherContainerRecord.SP_CONTAINER){\r
+            Map<EscherRecord, Record> shapeToObj = agg.getShapeToObjMapping();\r
+            EscherSpRecord spRecord = null;\r
+            ObjRecord objRecord = null;\r
+            TextObjectRecord txtRecord = null;\r
+\r
+            for(EscherRecord record : container.getChildRecords()) {\r
+                switch(record.getRecordId()) {\r
+                    case EscherSpRecord.RECORD_ID:\r
+                        spRecord = (EscherSpRecord)record;\r
+                        break;\r
+                    case EscherClientDataRecord.RECORD_ID:\r
+                        objRecord = (ObjRecord)shapeToObj.get(record);\r
+                        break;\r
+                    case EscherTextboxRecord.RECORD_ID:\r
+                        txtRecord = (TextObjectRecord)shapeToObj.get(record);\r
+                        break;\r
+                }\r
+            }\r
+            if (null != objRecord){\r
+                HSSFShape shape = shapeCreator.createNewShape(spRecord.getShapeType(), container, objRecord);\r
+                out.addShape(shape);\r
+            }\r
+            if (null != txtRecord){\r
+                //TODO resolve textbox\r
+//                TextboxShape shape = new TextboxShape(container, txtRecord);\r
+//                out.a\r
+            }\r
+//\r
+//            //TODO decide what shape to create based on ObjRecord / EscherSpRecord\r
+//            HSSFShape shape = new HSSFUnknownShape(container, objRecord);\r
+//            out.addShape(shape);\r
+        }\r
+    }\r
+}\r
index 905dad3fc2622940c26cb90f8223a71be9771bed..7cab3e493d528080d322f6b60d32102d287b0bcd 100644 (file)
 
 package org.apache.poi.hssf.usermodel;
 
+import org.apache.poi.ddf.EscherChildAnchorRecord;
+import org.apache.poi.ddf.EscherClientAnchorRecord;
+import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherSpgrRecord;
+import org.apache.poi.hssf.model.TextboxShape;
+import org.apache.poi.hssf.record.EscherAggregate;
+import org.apache.poi.hssf.record.ObjRecord;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Iterator;
@@ -37,6 +46,32 @@ public class HSSFShapeGroup
     int x2 = 1023;
     int y2 = 255;
 
+    public HSSFShapeGroup(EscherContainerRecord spgrContainer, ObjRecord objRecord) {
+        super(spgrContainer, objRecord);
+
+        // read internal and external coordinates from spgrContainer
+        EscherContainerRecord spContainer = spgrContainer.getChildContainers().get(0);
+        for(EscherRecord ch : spContainer.getChildRecords()){
+            switch(ch.getRecordId()) {
+                case EscherSpgrRecord.RECORD_ID:
+                    EscherSpgrRecord spgr = (EscherSpgrRecord)ch;
+                    setCoordinates(
+                            spgr.getRectX1(), spgr.getRectY1(),
+                            spgr.getRectX2(), spgr.getRectY2()
+                    );
+                    break;
+                case EscherClientAnchorRecord.RECORD_ID:
+                    this.anchor = EscherAggregate.toClientAnchor((EscherClientAnchorRecord)ch);
+                    // TODO anchor = new HSSFClientAnchor((EscherChildAnchorRecord)ch);
+                    break;
+                case EscherChildAnchorRecord.RECORD_ID:
+                    this.anchor = EscherAggregate.toChildAnchor((EscherChildAnchorRecord)ch);
+                    // TODO anchor = new HSSFChildAnchor((EscherClientAnchorRecord)ch);
+                    break;
+            }
+        }
+
+    }
 
     public HSSFShapeGroup( HSSFShape parent, HSSFAnchor anchor )
     {
@@ -61,6 +96,11 @@ public class HSSFShapeGroup
         shapes.add(shape);
     }
 
+    public void addTextBox(TextboxShape textboxShape){
+//        HSSFTextbox shape = new HSSFTextbox(this, textboxShape.geanchor);
+//        shapes.add(textboxShape);
+    }
+
     /**
      * Create a new simple shape under this group.
      * @param anchor    the position of the shape.
index fe332eb83e5b0766f3caf14e710d7be0884423ec..da7a404b28dcab3a4b5fe2d2d46f78a5cd105a67 100644 (file)
@@ -1738,12 +1738,16 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
         if(agg == null) return null;
 
         _patriarch = new HSSFPatriarch(this, agg);
-        agg.setPatriarch(_patriarch);
+        _patriarch.buildShapeTree();
+
+        //HSSFShapeFactory.createShapeTree();
+        //agg.setPatriarch(_patriarch);
+        //EscherAggregate.createShapeTree(EscherAggregate.getMainSpgrContainer(agg), agg.getPatriarch(), agg);
 
         // Have it process the records into high level objects
         //  as best it can do (this step may eat anything
         //  that isn't supported, you were warned...)
-        agg.convertRecordsToUserModel();
+//        agg.convertRecordsToUserModel();
 
         // Return what we could cope with
         return _patriarch;
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFUnknownShape.java
new file mode 100644 (file)
index 0000000..d4cac9b
--- /dev/null
@@ -0,0 +1,33 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ *    contributor license agreements.  See the NOTICE file distributed with\r
+ *    this work for additional information regarding copyright ownership.\r
+ *    The ASF licenses this file to You under the Apache License, Version 2.0\r
+ *    (the "License"); you may not use this file except in compliance with\r
+ *    the License.  You may obtain a copy of the License at\r
+ *\r
+ *        http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ *    Unless required by applicable law or agreed to in writing, software\r
+ *    distributed under the License is distributed on an "AS IS" BASIS,\r
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ *    See the License for the specific language governing permissions and\r
+ *    limitations under the License.\r
+ */\r
+\r
+package org.apache.poi.hssf.usermodel;\r
+\r
+import org.apache.poi.ddf.EscherContainerRecord;\r
+import org.apache.poi.ddf.EscherRecord;\r
+import org.apache.poi.hssf.record.ObjRecord;\r
+\r
+/**\r
+ * @author Evgeniy Berlog\r
+ * date: 05.06.12\r
+ */\r
+public class HSSFUnknownShape extends HSSFShape {\r
+\r
+    public HSSFUnknownShape(EscherRecord spContainer, ObjRecord objRecord) {\r
+        super((EscherContainerRecord) spContainer, objRecord);\r
+    }\r
+}\r
diff --git a/src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java b/src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java
new file mode 100644 (file)
index 0000000..2818687
--- /dev/null
@@ -0,0 +1,29 @@
+package org.apache.poi.hssf.usermodel.drawing;\r
+\r
+import org.apache.poi.hssf.usermodel.HSSFRectangle;\r
+\r
+/**\r
+ * @author Evgeniy Berlog\r
+ * date: 08.06.12\r
+ */\r
+public enum HSSFShapeType {\r
+    NOT_PRIMITIVE(0x0, null),\r
+    RECTANGLE(0x1, HSSFRectangle.class),\r
+    ROUND_RECTANGLE(0x2, null);\r
+\r
+    private Short type;\r
+    private Class shape;\r
+\r
+    HSSFShapeType(Integer type, Class shape) {\r
+        this.type = type.shortValue();\r
+        this.shape = shape;\r
+    }\r
+\r
+    public Short getType() {\r
+        return type;\r
+    }\r
+\r
+    public Class getShape() {\r
+        return shape;\r
+    }\r
+}\r
index a22ce4a0cc07c112ecf3480f99e3294f6f82468f..0608c0eb1845754dfa389acce9a48ff5effcb367 100644 (file)
 package org.apache.poi.hssf.model;\r
 \r
 import junit.framework.TestCase;\r
+import org.apache.poi.ddf.EscherContainerRecord;\r
 import org.apache.poi.ddf.EscherDggRecord;\r
+import org.apache.poi.ddf.EscherRecord;\r
 import org.apache.poi.hssf.HSSFTestDataSamples;\r
 import org.apache.poi.hssf.record.*;\r
 import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;\r
-import org.apache.poi.hssf.usermodel.HSSFSheet;\r
-import org.apache.poi.hssf.usermodel.HSSFTestHelper;\r
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;\r
+import org.apache.poi.hssf.usermodel.*;\r
 import org.apache.poi.util.HexRead;\r
 \r
 import java.io.*;\r
@@ -35,18 +35,84 @@ import java.util.List;
  * @author Evgeniy Berlog\r
  */\r
 public class TestDrawingAggregate extends TestCase {\r
-    private static byte[] toByteArray(List<RecordBase> records){\r
-            ByteArrayOutputStream out = new ByteArrayOutputStream();\r
-            for(RecordBase rb : records) {\r
-                    Record r = (Record)rb;\r
-                    try {\r
-                            out.write(r.serialize());\r
-                        } catch (IOException e){\r
-                            throw new RuntimeException(e);\r
-                        }\r
-                }\r
-            return out.toByteArray();\r
+\r
+    private int spgrCount = 0;\r
+    private int spCount = 0;\r
+    private int shapeCount = 0;\r
+    private int shGroupCount = 0;\r
+\r
+    /*\r
+     * EscherAggregate must have for each SpgrContainer HSSFShapeGroup and for each SpContainer HSSFShape\r
+     */\r
+    private void checkEscherAndShapesCount(EscherAggregate agg, HSSFSheet sheet) {\r
+        /*\r
+        HSSFPatriarch patriarch = HSSFTestHelper.createTestPatriarch(sheet, agg);\r
+        agg.setPatriarch(patriarch);\r
+        EscherAggregate.createShapeTree(EscherAggregate.getMainSpgrContainer(agg), agg.getPatriarch(), agg);\r
+        EscherContainerRecord mainContainer = EscherAggregate.getMainSpgrContainer(agg);\r
+        calculateShapesCount(agg.getPatriarch());\r
+        calculateEscherContainersCount(mainContainer);\r
+\r
+        assertEquals(spgrCount, shGroupCount);\r
+        assertEquals(spCount - spgrCount - 1, shapeCount);\r
+        */\r
+    }\r
+\r
+    private void calculateEscherContainersCount(EscherContainerRecord spgr) {\r
+        for (EscherRecord record : spgr.getChildRecords()) {\r
+            if (EscherContainerRecord.SP_CONTAINER == record.getRecordId()) {\r
+                spCount++;\r
+                continue;\r
+            }\r
+            if (EscherContainerRecord.SPGR_CONTAINER == record.getRecordId()) {\r
+                spgrCount++;\r
+                calculateEscherContainersCount((EscherContainerRecord) record);\r
+            }\r
+        }\r
+    }\r
+\r
+    private void calculateShapesCount(HSSFShapeContainer group) {\r
+        for (HSSFShape shape : (List<HSSFShape>) group.getChildren()) {\r
+            if (shape instanceof HSSFShapeGroup) {\r
+                shGroupCount++;\r
+                calculateShapesCount((HSSFShapeGroup) shape);\r
+            } else {\r
+                shapeCount++;\r
+            }\r
+        }\r
+    }\r
+\r
+\r
+    private static byte[] toByteArray(List<RecordBase> records) {\r
+        ByteArrayOutputStream out = new ByteArrayOutputStream();\r
+        for (RecordBase rb : records) {\r
+            Record r = (Record) rb;\r
+            try {\r
+                out.write(r.serialize());\r
+            } catch (IOException e) {\r
+                throw new RuntimeException(e);\r
+            }\r
         }\r
+        return out.toByteArray();\r
+    }\r
+\r
+    public void testSolverContainerMustBeSavedDuringSerialization(){\r
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("SolverContainerAfterSPGR.xls");\r
+        HSSFSheet sh = wb.getSheetAt(0);\r
+        InternalSheet ish = HSSFTestHelper.getSheetForTest(sh);\r
+        sh.getDrawingPatriarch();\r
+        EscherAggregate agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);\r
+        assertEquals(agg.getEscherRecords().get(0).getChildRecords().size(), 3);\r
+        assertEquals(agg.getEscherRecords().get(0).getChild(2).getRecordId(), EscherContainerRecord.SOLVER_CONTAINER);\r
+        wb = HSSFTestDataSamples.writeOutAndReadBack(wb);\r
+        sh = wb.getSheetAt(0);\r
+        sh.getDrawingPatriarch();\r
+        ish = HSSFTestHelper.getSheetForTest(sh);\r
+        agg = (EscherAggregate) ish.findFirstRecordBySid(EscherAggregate.sid);\r
+        assertEquals(agg.getEscherRecords().get(0).getChildRecords().size(), 3);\r
+        assertEquals(agg.getEscherRecords().get(0).getChild(2).getRecordId(), EscherContainerRecord.SOLVER_CONTAINER);\r
+\r
+    }\r
 \r
     /**\r
      * test reading drawing aggregate from a test file from Bugzilla 45129\r
@@ -107,6 +173,7 @@ public class TestDrawingAggregate extends TestCase {
         byte[] dgBytesAfterSave = agg.serialize();\r
         assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);\r
         assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));\r
+        checkEscherAndShapesCount(agg, sh);\r
     }\r
 \r
     /**\r
@@ -174,7 +241,7 @@ public class TestDrawingAggregate extends TestCase {
         assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);\r
         assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));\r
 \r
-\r
+        checkEscherAndShapesCount(agg, sh);\r
     }\r
 \r
 \r
@@ -185,21 +252,20 @@ public class TestDrawingAggregate extends TestCase {
         List<RecordBase> records = isheet.getRecords();\r
 \r
         HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb);\r
-        InternalSheet isheet2 = HSSFTestHelper.getSheetForTest( wb2.getSheetAt(0));\r
+        InternalSheet isheet2 = HSSFTestHelper.getSheetForTest(wb2.getSheetAt(0));\r
         List<RecordBase> records2 = isheet2.getRecords();\r
 \r
         assertEquals(records.size(), records2.size());\r
-        for(int i = 0; i < records.size(); i++) {\r
+        for (int i = 0; i < records.size(); i++) {\r
             RecordBase r1 = records.get(i);\r
             RecordBase r2 = records2.get(i);\r
             assertTrue(r1.getClass() == r2.getClass());\r
             assertEquals(r1.getRecordSize(), r2.getRecordSize());\r
-            if(r1 instanceof Record ){\r
-                assertEquals(((Record)r1).getSid(), ((Record)r2).getSid());\r
+            if (r1 instanceof Record) {\r
+                assertEquals(((Record) r1).getSid(), ((Record) r2).getSid());\r
                 assertTrue(Arrays.equals(((Record) r1).serialize(), ((Record) r2).serialize()));\r
             }\r
         }\r
-\r
     }\r
 \r
     public void testSerializeDrawingWithComments() throws IOException {\r
@@ -257,6 +323,7 @@ public class TestDrawingAggregate extends TestCase {
         byte[] dgBytesAfterSave = agg.serialize();\r
         assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);\r
         assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));\r
+        checkEscherAndShapesCount(agg, sh);\r
     }\r
 \r
 \r
@@ -314,7 +381,8 @@ public class TestDrawingAggregate extends TestCase {
 \r
         byte[] dgBytesAfterSave = agg.serialize();\r
         assertEquals("different size of drawing data before and after save", dgBytes.length, dgBytesAfterSave.length);\r
-        assertTrue("drawing data brefpore and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));\r
+        assertTrue("drawing data before and after save is different", Arrays.equals(dgBytes, dgBytesAfterSave));\r
+        checkEscherAndShapesCount(agg, sh);\r
     }\r
 \r
     public void testUnhandledContinue() {\r
index 7c5a88bd4539fff946d92301127ca82935152085..0b79eae50eb450b6f79953715a64861d2824085c 100644 (file)
@@ -18,6 +18,7 @@
 package org.apache.poi.hssf.usermodel;
 import org.apache.poi.hssf.model.InternalSheet;
 import org.apache.poi.hssf.model.InternalWorkbook;
+import org.apache.poi.hssf.record.EscherAggregate;
 
 /**
  * Helper class for HSSF tests that aren't within the
@@ -34,4 +35,8 @@ public class HSSFTestHelper {
        public static InternalSheet getSheetForTest(HSSFSheet sheet) {
                return sheet.getSheet();
        }
+
+    public static HSSFPatriarch createTestPatriarch(HSSFSheet sheet, EscherAggregate agg){
+        return new HSSFPatriarch(sheet, agg);
+    }
 }
diff --git a/test-data/spreadsheet/SolverContainerAfterSPGR.xls b/test-data/spreadsheet/SolverContainerAfterSPGR.xls
new file mode 100755 (executable)
index 0000000..57a1b17
Binary files /dev/null and b/test-data/spreadsheet/SolverContainerAfterSPGR.xls differ