]> source.dussan.org Git - poi.git/commitdiff
Added such improvements:
authorEvgeniy Berlog <berlog@apache.org>
Mon, 18 Jun 2012 20:59:32 +0000 (20:59 +0000)
committerEvgeniy Berlog <berlog@apache.org>
Mon, 18 Jun 2012 20:59:32 +0000 (20:59 +0000)
1. Each shape contains EscherContainerRecord(SpContainer). Shapes get and set all properties into EscherOptRecord.
2. HSSFShapeGroup takes coordinates from EscherSpgrRecord.
3. Added tests for creating new HSSFSimpleShape from scratch and reading from existing file
4. Improved work with anchors.

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/gsoc2012@1351484 13f79535-47bb-0310-9956-ffa450edef68

17 files changed:
src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java
src/java/org/apache/poi/ddf/EscherRGBProperty.java
src/java/org/apache/poi/ddf/EscherSimpleProperty.java
src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.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/HSSFComment.java
src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java
src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java [deleted file]
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java
src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java
src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java
src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java
src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java [new file with mode: 0644]
src/testcases/org/apache/poi/hssf/model/TestHSSFAnchor.java [new file with mode: 0644]
test-data/spreadsheet/drawings.xls [new file with mode: 0644]

index fbca0fb87db7074151f662316f85661d43c58ce4..ffc9170c4313e6af143b979af0ca80969fe75ff6 100644 (file)
@@ -1,4 +1,3 @@
-
 /* ====================================================================
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
@@ -38,6 +37,14 @@ public class EscherClientAnchorRecord
     public static final short RECORD_ID = (short) 0xF010;
     public static final String RECORD_DESCRIPTION = "MsofbtClientAnchor";
 
+    /**
+     * bit[0] -  fMove (1 bit): A bit that specifies whether the shape will be kept intact when the cells are moved.
+     * bit[1] - fSize (1 bit): A bit that specifies whether the shape will be kept intact when the cells are resized. If fMove is 1, the value MUST be 1.
+     * bit[2-4] - reserved, MUST be 0 and MUST be ignored
+     * bit[5-15]- Undefined and MUST be ignored.
+     *
+     * it can take values: 0, 2, 3
+     */
     private short field_1_flag;
     private short field_2_col1;
     private short field_3_dx1;
index 5d23addfb5773a6beccba8600d91579f18637b47..e28b97b5006c9cfb9d0f7af231b8fc307035f31c 100644 (file)
@@ -38,6 +38,10 @@ public class EscherRGBProperty
         return propertyValue;
     }
 
+    public void setRgbColor(int color){
+        this.propertyValue = color;
+    }
+
     public byte getRed()
     {
         return (byte) ( propertyValue & 0xFF );
index 78fb6420342a633329ffcd309235d798536b0dcd..efc392dcfacd6e2782821e22d91d6eaa5693ebaa 100644 (file)
@@ -80,6 +80,10 @@ public class EscherSimpleProperty extends EscherProperty
         return propertyValue;
     }
 
+    public void setPropertyValue(int propertyValue) {
+        this.propertyValue = propertyValue;
+    }
+
     /**
      * Returns true if one escher property is equal to another.
      */
index 6a87806100832cf3c9726a84a06a17c6f84ec734..2fe36130cf2c24fa22d49a7d5ef0b6e548481cb4 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;
+
 /**
  * An anchor is what specifics the position of a shape within a client object
  * or within another containing shape.
  *
  * @author Glen Stampoultzis (glens at apache.org)
  */
-public abstract class HSSFAnchor
-{
-    int dx1;
-    int dy1;
-    int dx2;
-    int dy2;
-
-    public HSSFAnchor()
-    {
+public abstract class HSSFAnchor {
+
+    public HSSFAnchor() {
+        createEscherAnchor();
+    }
+
+    public HSSFAnchor(int dx1, int dy1, int dx2, int dy2) {
+        createEscherAnchor();
+        setDx1(dx1);
+        setDy1(dy1);
+        setDx2(dx2);
+        setDy2(dy2);
     }
 
-    public HSSFAnchor( int dx1, int dy1, int dx2, int dy2 )
-    {
-        this.dx1 = dx1;
-        this.dy1 = dy1;
-        this.dx2 = dx2;
-        this.dy2 = dy2;
+    public static HSSFAnchor createAnchorFromEscher(EscherContainerRecord container){
+        if (null != container.getChildById(EscherChildAnchorRecord.RECORD_ID)){
+            return new HSSFChildAnchor((EscherChildAnchorRecord) container.getChildById(EscherChildAnchorRecord.RECORD_ID));
+        } else {
+            if (null != container.getChildById(EscherClientAnchorRecord.RECORD_ID)){
+                return new HSSFClientAnchor((EscherClientAnchorRecord) container.getChildById(EscherClientAnchorRecord.RECORD_ID));
+            }
+            return null;
+//            throw new IllegalArgumentException("continer must have anchor record");
+        }
     }
 
-    public int getDx1(){ return dx1; }
-    public void setDx1( int dx1 ){ this.dx1 = dx1; }
-    public int getDy1(){ return dy1; }
-    public void setDy1( int dy1 ){ this.dy1 = dy1; }
-    public int getDy2(){ return dy2; }
-    public void setDy2( int dy2 ){ this.dy2 = dy2; }
-    public int getDx2(){ return dx2; }
-    public void setDx2( int dx2 ){ this.dx2 = dx2; }
+    public abstract int getDx1();
+
+    public abstract void setDx1(int dx1);
+
+    public abstract int getDy1();
+
+    public abstract void setDy1(int dy1);
+
+    public abstract int getDy2();
+
+    public abstract void setDy2(int dy2);
+
+    public abstract int getDx2();
+
+    public abstract void setDx2(int dx2);
 
     public abstract boolean isHorizontallyFlipped();
+
     public abstract boolean isVerticallyFlipped();
+
+    public abstract EscherRecord getEscherAnchor();
+
+    protected abstract void createEscherAnchor();
 }
index ccd0e620cfc04526dc9ef6bd0d4c53a90aa5db3b..38c4f5f0e2aafaa366b9ff965931eda82053d099 100644 (file)
@@ -19,39 +19,100 @@ package org.apache.poi.hssf.usermodel;
 
 
 import org.apache.poi.ddf.EscherChildAnchorRecord;
+import org.apache.poi.ddf.EscherRecord;
 
 public final class HSSFChildAnchor extends HSSFAnchor {
 
-    private EscherChildAnchorRecord escherChildAnchorRecord;
+    private EscherChildAnchorRecord _escherChildAnchor;
 
     public HSSFChildAnchor(EscherChildAnchorRecord escherChildAnchorRecord) {
-        this.escherChildAnchorRecord = escherChildAnchorRecord;
+        this._escherChildAnchor = escherChildAnchorRecord;
     }
 
-    public HSSFChildAnchor()
-    {
+    public HSSFChildAnchor() {
+        _escherChildAnchor = new EscherChildAnchorRecord();
     }
 
-    public HSSFChildAnchor( int dx1, int dy1, int dx2, int dy2 )
-    {
-        super( dx1, dy1, dx2, dy2 );
+    public HSSFChildAnchor(int dx1, int dy1, int dx2, int dy2) {
+        super(dx1, dy1, dx2, dy2);
     }
 
-    public void setAnchor(int dx1, int dy1, int dx2, int dy2)
-    {
-        this.dx1 = dx1;
-        this.dy1 = dy1;
-        this.dx2 = dx2;
-        this.dy2 = dy2;
+    @Override
+    public int getDx1() {
+        return _escherChildAnchor.getDx1();
     }
 
-    public boolean isHorizontallyFlipped()
-    {
-        return dx1 > dx2;
+    @Override
+    public void setDx1(int dx1) {
+        _escherChildAnchor.setDx1(dx1);
     }
 
-    public boolean isVerticallyFlipped()
-    {
-        return dy1 > dy2;
+    @Override
+    public int getDy1() {
+        return _escherChildAnchor.getDy1();
+    }
+
+    @Override
+    public void setDy1(int dy1) {
+        _escherChildAnchor.setDy1(dy1);
+    }
+
+    @Override
+    public int getDy2() {
+        return _escherChildAnchor.getDy2();
+    }
+
+    @Override
+    public void setDy2(int dy2) {
+        _escherChildAnchor.setDy2(dy2);
+    }
+
+    @Override
+    public int getDx2() {
+        return _escherChildAnchor.getDx2();
+    }
+
+    @Override
+    public void setDx2(int dx2) {
+        _escherChildAnchor.setDx2(dx2);
+    }
+
+    public void setAnchor(int dx1, int dy1, int dx2, int dy2) {
+        setDx1(dx1);
+        setDy1(dy1);
+        setDx2(dx2);
+        setDy2(dy2);
+    }
+
+    public boolean isHorizontallyFlipped() {
+        return getDx1() > getDx2();
+    }
+
+    public boolean isVerticallyFlipped() {
+        return getDy1() > getDy2();
+    }
+
+    @Override
+    public EscherRecord getEscherAnchor() {
+        return _escherChildAnchor;
+    }
+
+    @Override
+    protected void createEscherAnchor() {
+        _escherChildAnchor = new EscherChildAnchorRecord();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null)
+            return false;
+        if (obj == this)
+            return true;
+        if (obj.getClass() != getClass())
+            return false;
+        HSSFChildAnchor anchor = (HSSFChildAnchor) obj;
+
+        return anchor.getDx1() == getDx1() && anchor.getDx2() == getDx2() && anchor.getDy1() == getDy1()
+                && anchor.getDy2() == getDy2();
     }
 }
index a040144c2709cec947f4bc6f3de0abec0eda4d41..49e20a42f106b9c612fada8bac22b24c84902017 100644 (file)
@@ -18,9 +18,9 @@
 package org.apache.poi.hssf.usermodel;
 
 import org.apache.poi.ddf.EscherClientAnchorRecord;
+import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.ss.usermodel.ClientAnchor;
 
-
 /**
  * A client anchor is attached to an excel worksheet.  It anchors against a
  * top-left and buttom-right cell.
@@ -28,42 +28,34 @@ import org.apache.poi.ss.usermodel.ClientAnchor;
  * @author Glen Stampoultzis (glens at apache.org)
  */
 public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
-    short col1;
-    int row1;
-    short col2;
-    int row2;
-    int anchorType;
 
-    private EscherClientAnchorRecord escherClientAnchorRecord;
+    private EscherClientAnchorRecord _escherClientAnchor;
 
     public HSSFClientAnchor(EscherClientAnchorRecord escherClientAnchorRecord) {
-        this.escherClientAnchorRecord = escherClientAnchorRecord;
-        //TODO set properties or read properties from EscherRecord ?
+        this._escherClientAnchor = escherClientAnchorRecord;
     }
 
     /**
      * Creates a new client anchor and defaults all the anchor positions to 0.
      */
-    public HSSFClientAnchor()
-    {
+    public HSSFClientAnchor() {
     }
 
     /**
      * Creates a new client anchor and sets the top-left and bottom-right
      * coordinates of the anchor.
      *
-     * @param dx1   the x coordinate within the first cell.
-     * @param dy1   the y coordinate within the first cell.
-     * @param dx2   the x coordinate within the second cell.
-     * @param dy2   the y coordinate within the second cell.
-     * @param col1  the column (0 based) of the first cell.
-     * @param row1  the row (0 based) of the first cell.
-     * @param col2  the column (0 based) of the second cell.
-     * @param row2  the row (0 based) of the second cell.
+     * @param dx1  the x coordinate within the first cell.
+     * @param dy1  the y coordinate within the first cell.
+     * @param dx2  the x coordinate within the second cell.
+     * @param dy2  the y coordinate within the second cell.
+     * @param col1 the column (0 based) of the first cell.
+     * @param row1 the row (0 based) of the first cell.
+     * @param col2 the column (0 based) of the second cell.
+     * @param row2 the row (0 based) of the second cell.
      */
-    public HSSFClientAnchor( int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2 )
-    {
-        super( dx1, dy1, dx2, dy2 );
+    public HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2) {
+        super(dx1, dy1, dx2, dy2);
 
         checkRange(dx1, 0, 1023, "dx1");
         checkRange(dx2, 0, 1023, "dx2");
@@ -74,35 +66,30 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
         checkRange(row1, 0, 255 * 256, "row1");
         checkRange(row2, 0, 255 * 256, "row2");
 
-        this.col1 = col1;
-        this.row1 = row1;
-        this.col2 = col2;
-        this.row2 = row2;
+        setCol1(col1);
+        setCol2(col2);
+        setRow1(row1);
+        setRow2(row2);
     }
 
     /**
      * Calculates the height of a client anchor in points.
      *
-     * @param sheet     the sheet the anchor will be attached to
-     * @return          the shape height.
+     * @param sheet the sheet the anchor will be attached to
+     * @return the shape height.
      */
-    public float getAnchorHeightInPoints(HSSFSheet sheet )
-    {
+    public float getAnchorHeightInPoints(HSSFSheet sheet) {
         int y1 = getDy1();
         int y2 = getDy2();
-        int row1 = Math.min( getRow1(), getRow2() );
-        int row2 = Math.max( getRow1(), getRow2() );
+        int row1 = Math.min(getRow1(), getRow2());
+        int row2 = Math.max(getRow1(), getRow2());
 
         float points = 0;
-        if (row1 == row2)
-        {
+        if (row1 == row2) {
             points = ((y2 - y1) / 256.0f) * getRowHeightInPoints(sheet, row2);
-        }
-        else
-        {
+        } else {
             points += ((256.0f - y1) / 256.0f) * getRowHeightInPoints(sheet, row1);
-            for (int i = row1 + 1; i < row2; i++)
-            {
+            for (int i = row1 + 1; i < row2; i++) {
                 points += getRowHeightInPoints(sheet, i);
             }
             points += (y2 / 256.0f) * getRowHeightInPoints(sheet, row2);
@@ -111,8 +98,7 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
         return points;
     }
 
-    private float getRowHeightInPoints(HSSFSheet sheet, int rowNum)
-    {
+    private float getRowHeightInPoints(HSSFSheet sheet, int rowNum) {
         HSSFRow row = sheet.getRow(rowNum);
         if (row == null) {
             return sheet.getDefaultRowHeightInPoints();
@@ -120,55 +106,48 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
         return row.getHeightInPoints();
     }
 
-    public short getCol1()
-    {
-        return col1;
+    public short getCol1() {
+        return _escherClientAnchor.getCol1();
     }
 
-    public void setCol1( short col1 )
-    {
+    public void setCol1(short col1) {
         checkRange(col1, 0, 255, "col1");
-        this.col1 = col1;
+        _escherClientAnchor.setCol1(col1);
     }
-    public void setCol1( int col1 ){
-        setCol1((short)col1);
+
+    public void setCol1(int col1) {
+        setCol1((short) col1);
     }
 
-    public short getCol2()
-    {
-        return col2;
+    public short getCol2() {
+        return _escherClientAnchor.getCol2();
     }
 
-    public void setCol2( short col2 )
-    {
+    public void setCol2(short col2) {
         checkRange(col2, 0, 255, "col2");
-        this.col2 = col2;
+        _escherClientAnchor.setCol2(col2);
     }
 
-    public void setCol2( int col2 ){
-        setCol2((short)col2);
+    public void setCol2(int col2) {
+        setCol2((short) col2);
     }
 
-    public int getRow1()
-    {
-        return row1;
+    public int getRow1() {
+        return _escherClientAnchor.getRow1();
     }
 
-    public void setRow1( int row1 )
-    {
+    public void setRow1(int row1) {
         checkRange(row1, 0, 256 * 256, "row1");
-        this.row1 = row1;
+        _escherClientAnchor.setRow1(Integer.valueOf(row1).shortValue());
     }
 
-    public int getRow2()
-    {
-        return row2;
+    public int getRow2() {
+        return _escherClientAnchor.getRow2();
     }
 
-    public void setRow2( int row2 )
-    {
+    public void setRow2(int row2) {
         checkRange(row2, 0, 256 * 256, "row2");
-        this.row2 = row2;
+        _escherClientAnchor.setRow2(Integer.valueOf(row2).shortValue());
     }
 
     /**
@@ -179,79 +158,139 @@ public final class HSSFClientAnchor extends HSSFAnchor implements ClientAnchor {
      * @param y1   the y coordinate within the first cell.
      * @param x2   the x coordinate within the second cell.
      * @param y2   the y coordinate within the second cell.
-     * @param col1  the column (0 based) of the first cell.
-     * @param row1  the row (0 based) of the first cell.
-     * @param col2  the column (0 based) of the second cell.
-     * @param row2  the row (0 based) of the second cell.
+     * @param col1 the column (0 based) of the first cell.
+     * @param row1 the row (0 based) of the first cell.
+     * @param col2 the column (0 based) of the second cell.
+     * @param row2 the row (0 based) of the second cell.
      */
-    public void setAnchor( short col1, int row1, int x1, int y1, short col2, int row2, int x2, int y2 )
-    {
-        checkRange(dx1, 0, 1023, "dx1");
-        checkRange(dx2, 0, 1023, "dx2");
-        checkRange(dy1, 0, 255, "dy1");
-        checkRange(dy2, 0, 255, "dy2");
-        checkRange(col1, 0, 255, "col1");
-        checkRange(col2, 0, 255, "col2");
-        checkRange(row1, 0, 255 * 256, "row1");
-        checkRange(row2, 0, 255 * 256, "row2");
-
-        this.col1 = col1;
-        this.row1 = row1;
-        this.dx1 = x1;
-        this.dy1 = y1;
-        this.col2 = col2;
-        this.row2 = row2;
-        this.dx2 = x2;
-        this.dy2 = y2;
+    public void setAnchor(short col1, int row1, int x1, int y1, short col2, int row2, int x2, int y2) {
+        checkRange(getDx1(), 0, 1023, "dx1");
+        checkRange(getDx2(), 0, 1023, "dx2");
+        checkRange(getDy1(), 0, 255, "dy1");
+        checkRange(getDy2(), 0, 255, "dy2");
+        checkRange(getCol1(), 0, 255, "col1");
+        checkRange(getCol2(), 0, 255, "col2");
+        checkRange(getRow1(), 0, 255 * 256, "row1");
+        checkRange(getRow2(), 0, 255 * 256, "row2");
+
+        setCol1(col1);
+        setRow1(row1);
+        setDx1(x1);
+        setDy1(y1);
+        setCol2(col2);
+        setRow2(row2);
+        setDx2(x2);
+        setDy2(y2);
     }
 
     /**
-     * @return  true if the anchor goes from right to left.
+     * @return true if the anchor goes from right to left.
      */
-    public boolean isHorizontallyFlipped()
-    {
-        if (col1 == col2) {
-            return dx1 > dx2;
+    public boolean isHorizontallyFlipped() {
+        if (getCol1() == getCol2()) {
+            return getDx1() > getDx2();
         }
-        return col1 > col2;
+        return getCol1() > getCol2();
     }
 
     /**
-     * @return  true if the anchor goes from bottom to top.
+     * @return true if the anchor goes from bottom to top.
      */
-    public boolean isVerticallyFlipped()
-    {
-        if (row1 == row2) {
-            return dy1 > dy2;
+    public boolean isVerticallyFlipped() {
+        if (getRow1() == getRow2()) {
+            return getDy1() > getDy2();
         }
-        return row1 > row2;
+        return getRow1() > getRow2();
+    }
+
+    @Override
+    public EscherRecord getEscherAnchor() {
+        return _escherClientAnchor;
+    }
+
+    @Override
+    protected void createEscherAnchor() {
+        _escherClientAnchor = new EscherClientAnchorRecord();
     }
 
     /**
      * Gets the anchor type
-     * <p>
+     * <p/>
      * 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
      */
-    public int getAnchorType()
-    {
-        return anchorType;
+    public int getAnchorType() {
+        return _escherClientAnchor.getFlag();
     }
 
     /**
      * Sets the anchor type
-     * <p>
+     * <p/>
      * 0 = Move and size with Cells, 2 = Move but don't size with cells, 3 = Don't move or size with cells.
      */
-    public void setAnchorType( int anchorType )
-    {
-        this.anchorType = anchorType;
+    public void setAnchorType(int anchorType) {
+//        if (0 != anchorType && 2 != anchorType && 3 != anchorType){
+//            throw new IllegalArgumentException("Anchor type of shape can take only such values: 0, 2, 3");
+//        }
+        _escherClientAnchor.setFlag(Integer.valueOf(anchorType).shortValue());
     }
 
-    private void checkRange( int value, int minRange, int maxRange, String varName )
-    {
+    private void checkRange(int value, int minRange, int maxRange, String varName) {
         if (value < minRange || value > maxRange)
             throw new IllegalArgumentException(varName + " must be between " + minRange + " and " + maxRange);
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null)
+            return false;
+        if (obj == this)
+            return true;
+        if (obj.getClass() != getClass())
+            return false;
+        HSSFClientAnchor anchor = (HSSFClientAnchor) obj;
+
+        return anchor.getCol1() == getCol1() && anchor.getCol2() == getCol2() && anchor.getDx1() == getDx1()
+                && anchor.getDx2() == getDx2() && anchor.getDy1() == getDy1() && anchor.getDy2() == getDy2()
+                && anchor.getRow1() == getRow1() && anchor.getRow2() == getRow2() && anchor.getAnchorType() == getAnchorType();
+    }
 
+    @Override
+    public int getDx1() {
+        return _escherClientAnchor.getDx1();
+    }
+
+    @Override
+    public void setDx1(int dx1) {
+        _escherClientAnchor.setDx1(Integer.valueOf(dx1).shortValue());
+    }
+
+    @Override
+    public int getDy1() {
+        return _escherClientAnchor.getDy1();
+    }
+
+    @Override
+    public void setDy1(int dy1) {
+        _escherClientAnchor.setDy1(Integer.valueOf(dy1).shortValue());
+    }
+
+    @Override
+    public int getDy2() {
+        return _escherClientAnchor.getDy2();
+    }
+
+    @Override
+    public void setDy2(int dy2) {
+        _escherClientAnchor.setDy2(Integer.valueOf(dy2).shortValue());
+    }
+
+    @Override
+    public int getDx2() {
+        return _escherClientAnchor.getDx2();
+    }
+
+    @Override
+    public void setDx2(int dx2) {
+        _escherClientAnchor.setDx2(Integer.valueOf(dx2).shortValue());
+    }
 }
index 225e6da0e98e863987ddc213dc10bd224d01f34b..2216971e68d437a38792ace97fb5c81282c04a32 100644 (file)
@@ -57,7 +57,7 @@ public class HSSFComment extends HSSFTextbox implements Comment {
         setShapeType(OBJECT_TYPE_COMMENT);
 
         //default color for comments
-        _fillColor = 0x08000050;
+        setFillColor(0x08000050);
 
         //by default comments are hidden
         _visible = false;
index d4a7205c73099460d814cd3493cb8a84b0e63e66..5aeb40b188ea5d9cfdba3a0ff4dd092c2ccd692f 100644 (file)
@@ -145,8 +145,8 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
         float w = 0;
 
         //space in the leftmost cell
-        w += getColumnWidthInPixels(anchor.col1)*(1 - (float)anchor.dx1/1024);
-        short col2 = (short)(anchor.col1 + 1);
+        w += getColumnWidthInPixels(anchor.getCol1())*(1 - (float)anchor.getDx1()/1024);
+        short col2 = (short)(anchor.getCol1() + 1);
         int dx2 = 0;
 
         while(w < scaledWidth){
@@ -160,12 +160,12 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
             double delta = w - scaledWidth;
             dx2 = (int)((cw-delta)/cw*1024);
         }
-        anchor.col2 = col2;
-        anchor.dx2 = dx2;
+        anchor.setCol2(col2);
+        anchor.setDx2(dx2);
 
         float h = 0;
-        h += (1 - (float)anchor.dy1/256)* getRowHeightInPixels(anchor.row1);
-        int row2 = anchor.row1 + 1;
+        h += (1 - (float)anchor.getDy1()/256)* getRowHeightInPixels(anchor.getRow1());
+        int row2 = anchor.getRow1() + 1;
         int dy2 = 0;
 
         while(h < scaledHeight){
@@ -177,8 +177,8 @@ public final class HSSFPicture extends HSSFSimpleShape implements Picture {
             double delta = h - scaledHeight;
             dy2 = (int)((ch-delta)/ch*256);
         }
-        anchor.row2 = row2;
-        anchor.dy2 = dy2;
+        anchor.setRow2(row2);
+        anchor.setDy2(dy2);
 
         return anchor;
     }
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java
deleted file mode 100644 (file)
index 0a0468c..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-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 7ffdfdb9baec19c6cf5d4e5817498fa1072b9b66..c9bf922cb7f04eb015fb536f9c4ef3eaa88b52bb 100644 (file)
@@ -17,7 +17,7 @@
 
 package org.apache.poi.hssf.usermodel;
 
-import org.apache.poi.ddf.EscherContainerRecord;
+import org.apache.poi.ddf.*;
 import org.apache.poi.hssf.record.ObjRecord;
 
 /**
@@ -28,6 +28,8 @@ import org.apache.poi.hssf.record.ObjRecord;
 public abstract class HSSFShape {
     public static final int LINEWIDTH_ONE_PT = 12700;
     public static final int LINEWIDTH_DEFAULT = 9525;
+    public static final int LINESTYLE__COLOR_DEFAULT = 0x08000040;
+    public static final int FILL__FILLCOLOR_DEFAULT = 0x08000009;
 
     public static final int LINESTYLE_SOLID = 0;              // Solid (continuous) pen
     public static final int LINESTYLE_DASHSYS = 1;            // PS_DASH system   dash style
@@ -45,50 +47,53 @@ public abstract class HSSFShape {
     // TODO - make all these fields private
     HSSFShape parent;
     HSSFAnchor anchor;
-    HSSFPatriarch _patriarch;  
-    private int _lineStyleColor = 0x08000040;
-    int _fillColor = 0x08000009;
-    private int _lineWidth = LINEWIDTH_DEFAULT;    // 12700 = 1pt
-    private int _lineStyle = LINESTYLE_SOLID;
-    private boolean _noFill = false;
+    HSSFPatriarch _patriarch;
 
-    private EscherContainerRecord spContainer;
-    private ObjRecord objRecord;
+    protected EscherContainerRecord _escherContainer;
+    protected ObjRecord _objRecord;
+    protected final EscherOptRecord _optRecord;
 
-    public HSSFShape(EscherContainerRecord spContainer, ObjRecord objRecord){
-        this.spContainer = spContainer;
-        this.objRecord = objRecord;
+    public HSSFShape(EscherContainerRecord spContainer, ObjRecord objRecord) {
+        this._escherContainer = spContainer;
+        this._objRecord = objRecord;
+        this._optRecord = spContainer.getChildById(EscherOptRecord.RECORD_ID);
+        this.anchor = HSSFAnchor.createAnchorFromEscher(spContainer);
     }
+
     /**
      * Create a new shape with the specified parent and anchor.
      */
-    public HSSFShape( HSSFShape parent, HSSFAnchor anchor )
-    {
+    public HSSFShape(HSSFShape parent, HSSFAnchor anchor) {
         this.parent = parent;
         this.anchor = anchor;
+        this._escherContainer = new EscherContainerRecord();
+        _optRecord = new EscherOptRecord();
+        _optRecord.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEDASHING, LINESTYLE_SOLID));
+        _optRecord.addEscherProperty(new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEWIDTH, LINEWIDTH_DEFAULT));
+        _optRecord.addEscherProperty(new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, FILL__FILLCOLOR_DEFAULT));
+        _optRecord.addEscherProperty(new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, LINESTYLE__COLOR_DEFAULT));
+        _optRecord.addEscherProperty(new EscherBoolProperty(EscherProperties.FILL__NOFILLHITTEST, 0x0));
     }
 
-    public EscherContainerRecord getSpContainer() {
-        return spContainer;
+    public EscherContainerRecord getEscherContainer() {
+        return _escherContainer;
     }
 
     public ObjRecord getObjRecord() {
-        return objRecord;
+        return _objRecord;
     }
 
     /**
      * Gets the parent shape.
      */
-    public HSSFShape getParent()
-    {
+    public HSSFShape getParent() {
         return parent;
     }
 
     /**
-     * @return  the anchor that is used by this shape.
+     * @return the anchor that is used by this shape.
      */
-    public HSSFAnchor getAnchor()
-    {
+    public HSSFAnchor getAnchor() {
         return anchor;
     }
 
@@ -96,26 +101,29 @@ public abstract class HSSFShape {
      * Sets a particular anchor.  A top-level shape must have an anchor of
      * HSSFClientAnchor.  A child anchor must have an anchor of HSSFChildAnchor
      *
-     * @param anchor    the anchor to use.
-     * @throws IllegalArgumentException     when the wrong anchor is used for
-     *                                      this particular shape.
-     *
+     * @param anchor the anchor to use.
+     * @throws IllegalArgumentException when the wrong anchor is used for
+     *                                  this particular shape.
      * @see HSSFChildAnchor
      * @see HSSFClientAnchor
      */
-    public void setAnchor( HSSFAnchor anchor )
-    {
-        if ( parent == null )
-        {
-            if ( anchor instanceof HSSFChildAnchor )
-                throw new IllegalArgumentException( "Must use client anchors for shapes directly attached to sheet." );
+    public void setAnchor(HSSFAnchor anchor) {
+        if (parent == null) {
+            if (anchor instanceof HSSFChildAnchor)
+                throw new IllegalArgumentException("Must use client anchors for shapes directly attached to sheet.");
+            EscherClientAnchorRecord anch = _escherContainer.getChildById(EscherClientAnchorRecord.RECORD_ID);
+            if (null != anch) {
+                _escherContainer.removeChildRecord(anch);
+            }
+        } else {
+            if (anchor instanceof HSSFClientAnchor)
+                throw new IllegalArgumentException("Must use child anchors for shapes attached to groups.");
+            EscherChildAnchorRecord anch = _escherContainer.getChildById(EscherChildAnchorRecord.RECORD_ID);
+            if (null != anch) {
+                _escherContainer.removeChildRecord(anch);
+            }
         }
-        else
-        {
-            if ( anchor instanceof HSSFClientAnchor )
-                throw new IllegalArgumentException( "Must use child anchors for shapes attached to groups." );
-        }
-
+        _escherContainer.addChildRecord(anchor.getEscherAnchor());
         this.anchor = anchor;
     }
 
@@ -123,92 +131,141 @@ public abstract class HSSFShape {
      * The color applied to the lines of this shape.
      */
     public int getLineStyleColor() {
-        return _lineStyleColor;
+        EscherRGBProperty rgbProperty = _optRecord.lookup(EscherProperties.LINESTYLE__COLOR);
+        return rgbProperty == null ? LINESTYLE__COLOR_DEFAULT : rgbProperty.getRgbColor();
     }
 
     /**
      * The color applied to the lines of this shape.
      */
     public void setLineStyleColor(int lineStyleColor) {
-        _lineStyleColor = lineStyleColor;
+        EscherRGBProperty rgbProperty = _optRecord.lookup(EscherProperties.LINESTYLE__COLOR);
+        if (null == rgbProperty) {
+            rgbProperty = new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, lineStyleColor);
+            _optRecord.addEscherProperty(rgbProperty);
+        } else {
+            rgbProperty.setRgbColor(lineStyleColor);
+        }
     }
 
     /**
      * The color applied to the lines of this shape.
      */
     public void setLineStyleColor(int red, int green, int blue) {
-        this._lineStyleColor = ((blue) << 16) | ((green) << 8) | red;
+        int lineStyleColor = ((blue) << 16) | ((green) << 8) | red;
+        EscherRGBProperty rgbProperty = _optRecord.lookup(EscherProperties.LINESTYLE__COLOR);
+        if (null == rgbProperty) {
+            rgbProperty = new EscherRGBProperty(EscherProperties.LINESTYLE__COLOR, lineStyleColor);
+            _optRecord.addEscherProperty(rgbProperty);
+        } else {
+            rgbProperty.setRgbColor(lineStyleColor);
+        }
     }
 
     /**
      * The color used to fill this shape.
      */
-    public int getFillColor()
-    {
-        return _fillColor;
+    public int getFillColor() {
+        EscherRGBProperty rgbProperty = _optRecord.lookup(EscherProperties.FILL__FILLCOLOR);
+        return rgbProperty == null ? FILL__FILLCOLOR_DEFAULT : rgbProperty.getRgbColor();
     }
 
     /**
      * The color used to fill this shape.
      */
     public void setFillColor(int fillColor) {
-        _fillColor = fillColor;
+        EscherRGBProperty rgbProperty = _optRecord.lookup(EscherProperties.FILL__FILLCOLOR);
+        if (null == rgbProperty) {
+            rgbProperty = new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, fillColor);
+            _optRecord.addEscherProperty(rgbProperty);
+        } else {
+            rgbProperty.setRgbColor(fillColor);
+        }
     }
 
     /**
      * The color used to fill this shape.
      */
-    public void setFillColor( int red, int green, int blue )
-    {
-        this._fillColor = ((blue) << 16) | ((green) << 8) | red;
+    public void setFillColor(int red, int green, int blue) {
+        int fillColor = ((blue) << 16) | ((green) << 8) | red;
+        EscherRGBProperty rgbProperty = _optRecord.lookup(EscherProperties.FILL__FILLCOLOR);
+        if (null == rgbProperty) {
+            rgbProperty = new EscherRGBProperty(EscherProperties.FILL__FILLCOLOR, fillColor);
+            _optRecord.addEscherProperty(rgbProperty);
+        } else {
+            rgbProperty.setRgbColor(fillColor);
+        }
     }
 
     /**
-     * @return  returns with width of the line in EMUs.  12700 = 1 pt.
+     * @return returns with width of the line in EMUs.  12700 = 1 pt.
      */
     public int getLineWidth() {
-        return _lineWidth;
+        EscherSimpleProperty property = _optRecord.lookup(EscherProperties.LINESTYLE__LINEWIDTH);
+        return property.getPropertyValue();
     }
 
     /**
      * Sets the width of the line.  12700 = 1 pt.
      *
      * @param lineWidth width in EMU's.  12700EMU's = 1 pt
-     *
      * @see HSSFShape#LINEWIDTH_ONE_PT
      */
     public void setLineWidth(int lineWidth) {
-        _lineWidth = lineWidth;
+        EscherSimpleProperty property = _optRecord.lookup(EscherProperties.LINESTYLE__LINEWIDTH);
+        if (null == property) {
+            property = new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEWIDTH, lineWidth);
+            _optRecord.addEscherProperty(property);
+        } else {
+            property.setPropertyValue(lineWidth);
+        }
     }
 
     /**
      * @return One of the constants in LINESTYLE_*
      */
     public int getLineStyle() {
-        return _lineStyle;
+        EscherSimpleProperty property = _optRecord.lookup(EscherProperties.LINESTYLE__LINEDASHING);
+        if (null == property){
+            return -1;
+        }
+        return property.getPropertyValue();
     }
 
     /**
      * Sets the line style.
      *
-     * @param lineStyle     One of the constants in LINESTYLE_*
+     * @param lineStyle One of the constants in LINESTYLE_*
      */
     public void setLineStyle(int lineStyle) {
-        _lineStyle = lineStyle;
+        EscherSimpleProperty property = _optRecord.lookup(EscherProperties.LINESTYLE__LINEDASHING);
+        if (null == property) {
+            property = new EscherSimpleProperty(EscherProperties.LINESTYLE__LINEDASHING, lineStyle);
+            _optRecord.addEscherProperty(property);
+        } else {
+            property.setPropertyValue(lineStyle);
+        }
     }
 
     /**
      * @return <code>true</code> if this shape is not filled with a color.
      */
     public boolean isNoFill() {
-        return _noFill;
+        EscherBoolProperty property = _optRecord.lookup(EscherProperties.FILL__NOFILLHITTEST);
+        return property.isTrue();
     }
 
     /**
      * Sets whether this shape is filled or transparent.
      */
     public void setNoFill(boolean noFill) {
-        _noFill = noFill;
+        EscherBoolProperty property = _optRecord.lookup(EscherProperties.FILL__NOFILLHITTEST);
+        if (null == property) {
+            property = new EscherBoolProperty(EscherProperties.FILL__NOFILLHITTEST, noFill ? 1 : 0);
+            _optRecord.addEscherProperty(property);
+        } else {
+            property.setPropertyValue(noFill ? 1 : 0);
+        }
     }
 
     /**
index 4a10a8d07ac5e16444df76072b683bde852222bc..68f410d173d6530abc0a1c473a0d6f3c90d18222 100644 (file)
@@ -39,25 +39,25 @@ import java.util.List;
 import java.util.Map;\r
 \r
 /**\r
- * @author evgeniy\r
+ * @author Evgeniy Berlog\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 Map<Short, HSSFShapeType> shapeTypeToClass = new HashMap<Short, HSSFShapeType>(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
+            shapeTypeToClass.put(type.getType(), type);\r
         }\r
     }\r
 \r
     private static class ReflectionConstructorShapeCreator {\r
 \r
-        private final Map<Short, Class> shapeTypeToClass;\r
+        private final Map<Short, HSSFShapeType> shapeTypeToClass;\r
 \r
-        private ReflectionConstructorShapeCreator(Map<Short, Class> shapeTypeToClass) {\r
+        private ReflectionConstructorShapeCreator(Map<Short, HSSFShapeType> shapeTypeToClass) {\r
             this.shapeTypeToClass = shapeTypeToClass;\r
         }\r
 \r
@@ -65,7 +65,7 @@ public class HSSFShapeFactory {
             if (!shapeTypeToClass.containsKey(type)){\r
                 return new HSSFUnknownShape(spContainer, objRecord);\r
             }\r
-            Class clazz = shapeTypeToClass.get(type);\r
+            Class clazz = shapeTypeToClass.get(type).getShape();\r
             if (null == clazz){\r
                 //System.out.println("No class attached to shape type: "+type);\r
                 return new HSSFUnknownShape(spContainer, objRecord);\r
@@ -81,26 +81,6 @@ public class HSSFShapeFactory {
         }\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
@@ -111,10 +91,6 @@ public class HSSFShapeFactory {
                 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
index 7cab3e493d528080d322f6b60d32102d287b0bcd..b3209467aefb0ec41d4051a1cdc28c69907ea0e5 100644 (file)
@@ -41,32 +41,23 @@ public class HSSFShapeGroup
         implements HSSFShapeContainer
 {
     List<HSSFShape> shapes = new ArrayList<HSSFShape>();
-    int x1 = 0;
-    int y1  = 0 ;
-    int x2 = 1023;
-    int y2 = 255;
+    private EscherSpgrRecord _spgrRecord;
 
     public HSSFShapeGroup(EscherContainerRecord spgrContainer, ObjRecord objRecord) {
         super(spgrContainer, objRecord);
 
         // read internal and external coordinates from spgrContainer
         EscherContainerRecord spContainer = spgrContainer.getChildContainers().get(0);
+        _spgrRecord = (EscherSpgrRecord) spContainer.getChild(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);
+                    anchor = new HSSFClientAnchor((EscherClientAnchorRecord)ch);
                     break;
                 case EscherChildAnchorRecord.RECORD_ID:
-                    this.anchor = EscherAggregate.toChildAnchor((EscherChildAnchorRecord)ch);
-                    // TODO anchor = new HSSFChildAnchor((EscherClientAnchorRecord)ch);
+                    anchor = new HSSFChildAnchor((EscherChildAnchorRecord)ch);
                     break;
             }
         }
@@ -76,6 +67,11 @@ public class HSSFShapeGroup
     public HSSFShapeGroup( HSSFShape parent, HSSFAnchor anchor )
     {
         super( parent, anchor );
+        _spgrRecord = new EscherSpgrRecord();
+        _spgrRecord.setRectX1(0);
+        _spgrRecord.setRectX2(1023);
+        _spgrRecord.setRectY1(0);
+        _spgrRecord.setRectY2(255);
     }
 
     /**
@@ -171,10 +167,10 @@ public class HSSFShapeGroup
      */
     public void setCoordinates( int x1, int y1, int x2, int y2 )
     {
-        this.x1 = x1;
-        this.y1 = y1;
-        this.x2 = x2;
-        this.y2 = y2;
+        _spgrRecord.setRectX1(x1);
+        _spgrRecord.setRectX2(x2);
+        _spgrRecord.setRectY1(y1);
+        _spgrRecord.setRectY2(y2);
     }
 
     /**
@@ -182,7 +178,7 @@ public class HSSFShapeGroup
      */
     public int getX1()
     {
-        return x1;
+        return _spgrRecord.getRectX1();
     }
 
     /**
@@ -190,7 +186,7 @@ public class HSSFShapeGroup
      */
     public int getY1()
     {
-        return y1;
+        return _spgrRecord.getRectY1();
     }
 
     /**
@@ -198,7 +194,7 @@ public class HSSFShapeGroup
      */
     public int getX2()
     {
-        return x2;
+        return _spgrRecord.getRectX2();
     }
 
     /**
@@ -206,7 +202,7 @@ public class HSSFShapeGroup
      */
     public int getY2()
     {
-        return y2;
+        return _spgrRecord.getRectY2();
     }
 
     /**
index ee8522929d51475c6bb8d2453db80d23c1775749..6e0df0fd540b7c280beb5d100fc8890d892936fc 100644 (file)
 
 package org.apache.poi.hssf.usermodel;
 
+import org.apache.poi.ddf.*;
+import org.apache.poi.hssf.record.CommonObjectDataSubRecord;
+import org.apache.poi.hssf.record.ObjRecord;
+
 /**
  * Represents a simple shape such as a line, rectangle or oval.
  *
@@ -52,7 +56,13 @@ public class HSSFSimpleShape
 
     int shapeType = OBJECT_TYPE_LINE;
 
-    public HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor )
+    public HSSFSimpleShape(EscherContainerRecord spContainer, ObjRecord objRecord) {
+        super(spContainer, objRecord);
+        CommonObjectDataSubRecord cod = (CommonObjectDataSubRecord) objRecord.getSubRecords().get(0);
+        setShapeType(cod.getObjectType());
+    }
+
+    public HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor)
     {
         super( parent, anchor );
     }
index 281868792108b85754fb3f6790e1ef4ab7257150..29741c90f8b8f40f93748e0c62e8dac4582400d5 100644 (file)
@@ -1,22 +1,24 @@
 package org.apache.poi.hssf.usermodel.drawing;\r
 \r
-import org.apache.poi.hssf.usermodel.HSSFRectangle;\r
+import org.apache.poi.hssf.usermodel.HSSFSimpleShape;\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
+    NOT_PRIMITIVE((short)0x0, null, (short)0),\r
+    RECTANGLE((short)0x1, HSSFSimpleShape.class, HSSFSimpleShape.OBJECT_TYPE_RECTANGLE),\r
+    ROUND_RECTANGLE((short)0x2, null, null);\r
 \r
     private Short type;\r
     private Class shape;\r
+    private Short objectId;\r
 \r
-    HSSFShapeType(Integer type, Class shape) {\r
-        this.type = type.shortValue();\r
+    private HSSFShapeType(Short type, Class shape, Short objectId) {\r
+        this.type = type;\r
         this.shape = shape;\r
+        this.objectId = objectId;\r
     }\r
 \r
     public Short getType() {\r
diff --git a/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java b/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java
new file mode 100644 (file)
index 0000000..f276cba
--- /dev/null
@@ -0,0 +1,160 @@
+package org.apache.poi.hssf.model;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.ddf.*;\r
+import org.apache.poi.hssf.HSSFTestDataSamples;\r
+import org.apache.poi.hssf.usermodel.*;\r
+import org.apache.poi.util.HexDump;\r
+\r
+import java.io.IOException;\r
+\r
+import static junit.framework.Assert.assertEquals;\r
+\r
+/**\r
+ * @author Evgeniy Berlog\r
+ * date: 12.06.12\r
+ */\r
+public class TestDrawingShapes extends TestCase{\r
+\r
+    /**\r
+     * HSSFShape tree bust be built correctly\r
+     * Check file with such records structure:\r
+     * -patriarch\r
+     * --shape\r
+     * --group\r
+     * ---group\r
+     * ----shape\r
+     * ----shape\r
+     * ---shape\r
+     * ---group\r
+     * ----shape\r
+     * ----shape\r
+     */\r
+    public void testDrawingGroups(){\r
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls");\r
+        HSSFSheet sheet = wb.getSheet("groups");\r
+        HSSFPatriarch patriarch = sheet.getDrawingPatriarch();\r
+        assertEquals(patriarch.getChildren().size(), 2);\r
+        HSSFShapeGroup group = (HSSFShapeGroup) patriarch.getChildren().get(1);\r
+        assertEquals(3, group.getChildren().size());\r
+        HSSFShapeGroup group1 = (HSSFShapeGroup) group.getChildren().get(0);\r
+        assertEquals(2, group1.getChildren().size());\r
+        group1 = (HSSFShapeGroup) group.getChildren().get(2);\r
+        assertEquals(2, group1.getChildren().size());\r
+    }\r
+\r
+    public void testHSSFShapeCompatibility() {\r
+        HSSFShape shape = new HSSFSimpleShape(null, new  HSSFClientAnchor());\r
+        assertEquals(0x08000040, shape.getLineStyleColor());\r
+        assertEquals(0x08000009, shape.getFillColor());\r
+        assertEquals(HSSFShape.LINEWIDTH_DEFAULT, shape.getLineWidth());\r
+        assertEquals(HSSFShape.LINESTYLE_SOLID, shape.getLineStyle());\r
+        assertFalse(shape.isNoFill());\r
+\r
+        AbstractShape sp = AbstractShape.createShape(shape, 1);\r
+        EscherContainerRecord spContainer = sp.getSpContainer();\r
+        EscherOptRecord opt =\r
+                spContainer.getChildById(EscherOptRecord.RECORD_ID);\r
+\r
+        assertEquals(7, opt.getEscherProperties().size());\r
+        assertEquals(true,\r
+                ((EscherBoolProperty)opt.lookup(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE)).isTrue());\r
+        assertEquals(0x00000004,\r
+                ((EscherSimpleProperty)opt.lookup(EscherProperties.GEOMETRY__SHAPEPATH)).getPropertyValue());\r
+        assertEquals(0x08000009,\r
+                ((EscherSimpleProperty)opt.lookup(EscherProperties.FILL__FILLCOLOR)).getPropertyValue());\r
+        assertEquals(true,\r
+                ((EscherBoolProperty)opt.lookup(EscherProperties.FILL__NOFILLHITTEST)).isTrue());\r
+        assertEquals(0x08000040,\r
+                ((EscherSimpleProperty)opt.lookup(EscherProperties.LINESTYLE__COLOR)).getPropertyValue());\r
+        assertEquals(true,\r
+                ((EscherBoolProperty)opt.lookup(EscherProperties.LINESTYLE__NOLINEDRAWDASH)).isTrue());\r
+        assertEquals(true,\r
+                ((EscherBoolProperty)opt.lookup(EscherProperties.GROUPSHAPE__PRINT)).isTrue());\r
+    }\r
+    /**\r
+     * create a rectangle, save the workbook, read back and verify that all shape properties are there\r
+     */\r
+    public void testReadWriteRectangle() throws IOException {\r
+\r
+        HSSFWorkbook wb = new HSSFWorkbook();\r
+        HSSFSheet sheet = wb.createSheet();\r
+\r
+        HSSFPatriarch drawing = sheet.createDrawingPatriarch();\r
+        HSSFClientAnchor anchor = new HSSFClientAnchor(10, 10, 200, 200, (short)2, 2, (short)15, 15);\r
+        anchor.setAnchorType(2);\r
+        assertEquals(anchor.getAnchorType(), 2);\r
+\r
+        HSSFSimpleShape rectangle = drawing.createSimpleShape(anchor);\r
+        rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);\r
+        rectangle.setLineWidth(10000);\r
+        rectangle.setFillColor(777);\r
+        assertEquals(rectangle.getFillColor(), 777);\r
+        assertEquals(10000, rectangle.getLineWidth());\r
+        rectangle.setLineStyle(10);\r
+        assertEquals(10, rectangle.getLineStyle());\r
+        rectangle.setLineStyleColor(1111);\r
+        rectangle.setNoFill(true);\r
+        assertEquals(rectangle.getLineStyleColor(), 1111);\r
+        assertEquals(rectangle.isNoFill(), true);\r
+\r
+        wb = HSSFTestDataSamples.writeOutAndReadBack(wb);\r
+        sheet = wb.getSheetAt(0);\r
+        drawing = sheet.getDrawingPatriarch();\r
+        assertEquals(1, drawing.getChildren().size());\r
+\r
+        HSSFSimpleShape rectangle2 =\r
+                (HSSFSimpleShape)drawing.getChildren().get(0);\r
+        assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE,\r
+                rectangle2.getShapeType());\r
+        assertEquals(10000, rectangle2.getLineWidth());\r
+        assertEquals(10, rectangle2.getLineStyle());\r
+        assertEquals(anchor, rectangle2.getAnchor());\r
+        assertEquals(rectangle2.getLineStyleColor(), 1111);\r
+        assertEquals(rectangle2.getFillColor(), 777);\r
+        assertEquals(rectangle2.isNoFill(), true);\r
+\r
+        rectangle2.setFillColor(3333);\r
+        rectangle2.setLineStyle(9);\r
+        rectangle2.setLineStyleColor(4444);\r
+        rectangle2.setNoFill(false);\r
+        rectangle2.setLineWidth(77);\r
+        rectangle2.getAnchor().setDx1(2);\r
+        rectangle2.getAnchor().setDx2(3);\r
+        rectangle2.getAnchor().setDy1(4);\r
+        rectangle2.getAnchor().setDy2(5);\r
+\r
+        wb = HSSFTestDataSamples.writeOutAndReadBack(wb);\r
+        sheet = wb.getSheetAt(0);\r
+        drawing = sheet.getDrawingPatriarch();\r
+        assertEquals(1, drawing.getChildren().size());\r
+        rectangle2 = (HSSFSimpleShape)drawing.getChildren().get(0);\r
+        assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, rectangle2.getShapeType());\r
+        assertEquals(77, rectangle2.getLineWidth());\r
+        assertEquals(9, rectangle2.getLineStyle());\r
+        assertEquals(rectangle2.getLineStyleColor(), 4444);\r
+        assertEquals(rectangle2.getFillColor(), 3333);\r
+        assertEquals(rectangle2.getAnchor().getDx1(), 2);\r
+        assertEquals(rectangle2.getAnchor().getDx2(), 3);\r
+        assertEquals(rectangle2.getAnchor().getDy1(), 4);\r
+        assertEquals(rectangle2.getAnchor().getDy2(), 5);\r
+        assertEquals(rectangle2.isNoFill(), false);\r
+    }\r
+\r
+\r
+    /* assert shape properties when reading shapes from a existing workbook */\r
+    public void testReadExistingRectangle() {\r
+        HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls");\r
+        HSSFSheet sheet = wb.getSheet("rectangles");\r
+        HSSFPatriarch drawing = sheet.getDrawingPatriarch();\r
+        assertEquals(1, drawing.getChildren().size());\r
+\r
+        for(HSSFShape shape : drawing.getChildren()){\r
+            assertEquals(shape.isNoFill(), true);\r
+            assertEquals(shape.getLineStyle(), HSSFShape.LINESTYLE_DASHDOTGEL);\r
+            assertEquals(shape.getLineStyleColor(), 0x616161);\r
+            assertEquals(HexDump.toHex(shape.getFillColor()), shape.getFillColor(), 0x2CE03D);\r
+            assertEquals(shape.getLineWidth(), HSSFShape.LINEWIDTH_ONE_PT*2);\r
+        }\r
+    }\r
+}\r
diff --git a/src/testcases/org/apache/poi/hssf/model/TestHSSFAnchor.java b/src/testcases/org/apache/poi/hssf/model/TestHSSFAnchor.java
new file mode 100644 (file)
index 0000000..ef90f01
--- /dev/null
@@ -0,0 +1,209 @@
+package org.apache.poi.hssf.model;\r
+\r
+import junit.framework.TestCase;\r
+import org.apache.poi.ddf.EscherChildAnchorRecord;\r
+import org.apache.poi.ddf.EscherClientAnchorRecord;\r
+import org.apache.poi.ddf.EscherContainerRecord;\r
+import org.apache.poi.hssf.usermodel.*;\r
+\r
+/**\r
+ * @author Evgeniy Berlog\r
+ * @date 12.06.12\r
+ */\r
+public class TestHSSFAnchor extends TestCase {\r
+\r
+    public void testCreateClientAnchorFromContainer(){\r
+        EscherContainerRecord container = new EscherContainerRecord();\r
+        EscherClientAnchorRecord escher = new EscherClientAnchorRecord();\r
+        escher.setFlag((short) 3);\r
+        escher.setCol1((short)11);\r
+        escher.setCol2((short)12);\r
+        escher.setRow1((short)13);\r
+        escher.setRow2((short) 14);\r
+        escher.setDx1((short) 15);\r
+        escher.setDx2((short) 16);\r
+        escher.setDy1((short) 17);\r
+        escher.setDy2((short) 18);\r
+        container.addChildRecord(escher);\r
+\r
+        HSSFClientAnchor anchor = (HSSFClientAnchor) HSSFAnchor.createAnchorFromEscher(container);\r
+        assertEquals(anchor.getCol1(), 11);\r
+        assertEquals(escher.getCol1(), 11);\r
+        assertEquals(anchor.getCol2(), 12);\r
+        assertEquals(escher.getCol2(), 12);\r
+        assertEquals(anchor.getRow1(), 13);\r
+        assertEquals(escher.getRow1(), 13);\r
+        assertEquals(anchor.getRow2(), 14);\r
+        assertEquals(escher.getRow2(), 14);\r
+        assertEquals(anchor.getDx1(), 15);\r
+        assertEquals(escher.getDx1(), 15);\r
+        assertEquals(anchor.getDx2(), 16);\r
+        assertEquals(escher.getDx2(), 16);\r
+        assertEquals(anchor.getDy1(), 17);\r
+        assertEquals(escher.getDy1(), 17);\r
+        assertEquals(anchor.getDy2(), 18);\r
+        assertEquals(escher.getDy2(), 18);\r
+    }\r
+\r
+    public void testCreateChildAnchorFromContainer(){\r
+        EscherContainerRecord container = new EscherContainerRecord();\r
+        EscherChildAnchorRecord escher = new EscherChildAnchorRecord();\r
+        escher.setDx1((short) 15);\r
+        escher.setDx2((short) 16);\r
+        escher.setDy1((short) 17);\r
+        escher.setDy2((short) 18);\r
+        container.addChildRecord(escher);\r
+\r
+        HSSFChildAnchor anchor = (HSSFChildAnchor) HSSFAnchor.createAnchorFromEscher(container);\r
+        assertEquals(anchor.getDx1(), 15);\r
+        assertEquals(escher.getDx1(), 15);\r
+        assertEquals(anchor.getDx2(), 16);\r
+        assertEquals(escher.getDx2(), 16);\r
+        assertEquals(anchor.getDy1(), 17);\r
+        assertEquals(escher.getDy1(), 17);\r
+        assertEquals(anchor.getDy2(), 18);\r
+        assertEquals(escher.getDy2(), 18);\r
+    }\r
+\r
+    public void testShapeEscherMustHaveAnchorRecord(){\r
+        HSSFWorkbook wb = new HSSFWorkbook();\r
+        HSSFSheet sheet = wb.createSheet();\r
+\r
+        HSSFPatriarch drawing = sheet.createDrawingPatriarch();\r
+        HSSFClientAnchor anchor = new HSSFClientAnchor(10, 10, 200, 200, (short)2, 2, (short)15, 15);\r
+        anchor.setAnchorType(2);\r
+\r
+        HSSFSimpleShape rectangle = drawing.createSimpleShape(anchor);\r
+        rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);\r
+\r
+        rectangle.setAnchor(anchor);\r
+\r
+        assertNotNull(anchor.getEscherAnchor());\r
+        assertNotNull(rectangle.getEscherContainer());\r
+        assertTrue(anchor.getEscherAnchor().equals(rectangle.getEscherContainer().getChildById(EscherClientAnchorRecord.RECORD_ID)));\r
+    }\r
+\r
+    public void testClientAnchorFromEscher(){\r
+        EscherClientAnchorRecord escher = new EscherClientAnchorRecord();\r
+        escher.setCol1((short)11);\r
+        escher.setCol2((short)12);\r
+        escher.setRow1((short)13);\r
+        escher.setRow2((short) 14);\r
+        escher.setDx1((short) 15);\r
+        escher.setDx2((short) 16);\r
+        escher.setDy1((short) 17);\r
+        escher.setDy2((short) 18);\r
+\r
+        HSSFClientAnchor anchor = new HSSFClientAnchor(escher);\r
+        assertEquals(anchor.getCol1(), 11);\r
+        assertEquals(escher.getCol1(), 11);\r
+        assertEquals(anchor.getCol2(), 12);\r
+        assertEquals(escher.getCol2(), 12);\r
+        assertEquals(anchor.getRow1(), 13);\r
+        assertEquals(escher.getRow1(), 13);\r
+        assertEquals(anchor.getRow2(), 14);\r
+        assertEquals(escher.getRow2(), 14);\r
+        assertEquals(anchor.getDx1(), 15);\r
+        assertEquals(escher.getDx1(), 15);\r
+        assertEquals(anchor.getDx2(), 16);\r
+        assertEquals(escher.getDx2(), 16);\r
+        assertEquals(anchor.getDy1(), 17);\r
+        assertEquals(escher.getDy1(), 17);\r
+        assertEquals(anchor.getDy2(), 18);\r
+        assertEquals(escher.getDy2(), 18);\r
+    }\r
+\r
+    public void testClientAnchorFromScratch(){\r
+        HSSFClientAnchor anchor = new HSSFClientAnchor();\r
+        EscherClientAnchorRecord escher = (EscherClientAnchorRecord) anchor.getEscherAnchor();\r
+        anchor.setAnchor((short)11, 12, 13, 14, (short)15, 16, 17, 18);\r
+\r
+        assertEquals(anchor.getCol1(), 11);\r
+        assertEquals(escher.getCol1(), 11);\r
+        assertEquals(anchor.getCol2(), 15);\r
+        assertEquals(escher.getCol2(), 15);\r
+        assertEquals(anchor.getRow1(), 12);\r
+        assertEquals(escher.getRow1(), 12);\r
+        assertEquals(anchor.getRow2(), 16);\r
+        assertEquals(escher.getRow2(), 16);\r
+        assertEquals(anchor.getDx1(), 13);\r
+        assertEquals(escher.getDx1(), 13);\r
+        assertEquals(anchor.getDx2(), 17);\r
+        assertEquals(escher.getDx2(), 17);\r
+        assertEquals(anchor.getDy1(), 14);\r
+        assertEquals(escher.getDy1(), 14);\r
+        assertEquals(anchor.getDy2(), 18);\r
+        assertEquals(escher.getDy2(), 18);\r
+\r
+        anchor.setCol1(111);\r
+        assertEquals(anchor.getCol1(), 111);\r
+        assertEquals(escher.getCol1(), 111);\r
+        anchor.setCol2(112);\r
+        assertEquals(anchor.getCol2(), 112);\r
+        assertEquals(escher.getCol2(), 112);\r
+        anchor.setRow1(113);\r
+        assertEquals(anchor.getRow1(), 113);\r
+        assertEquals(escher.getRow1(), 113);\r
+        anchor.setRow2(114);\r
+        assertEquals(anchor.getRow2(), 114);\r
+        assertEquals(escher.getRow2(), 114);\r
+        anchor.setDx1(115);\r
+        assertEquals(anchor.getDx1(), 115);\r
+        assertEquals(escher.getDx1(), 115);\r
+        anchor.setDx2(116);\r
+        assertEquals(anchor.getDx2(), 116);\r
+        assertEquals(escher.getDx2(), 116);\r
+        anchor.setDy1(117);\r
+        assertEquals(anchor.getDy1(), 117);\r
+        assertEquals(escher.getDy1(), 117);\r
+        anchor.setDy2(118);\r
+        assertEquals(anchor.getDy2(), 118);\r
+        assertEquals(escher.getDy2(), 118);\r
+    }\r
+\r
+    public void testChildAnchorFromEscher(){\r
+        EscherChildAnchorRecord escher = new EscherChildAnchorRecord();\r
+        escher.setDx1((short) 15);\r
+        escher.setDx2((short) 16);\r
+        escher.setDy1((short) 17);\r
+        escher.setDy2((short) 18);\r
+\r
+        HSSFChildAnchor anchor = new HSSFChildAnchor(escher);\r
+        assertEquals(anchor.getDx1(), 15);\r
+        assertEquals(escher.getDx1(), 15);\r
+        assertEquals(anchor.getDx2(), 16);\r
+        assertEquals(escher.getDx2(), 16);\r
+        assertEquals(anchor.getDy1(), 17);\r
+        assertEquals(escher.getDy1(), 17);\r
+        assertEquals(anchor.getDy2(), 18);\r
+        assertEquals(escher.getDy2(), 18);\r
+    }\r
+\r
+    public void testChildAnchorFromScratch(){\r
+        HSSFChildAnchor anchor = new HSSFChildAnchor();\r
+        EscherChildAnchorRecord escher = (EscherChildAnchorRecord) anchor.getEscherAnchor();\r
+        anchor.setAnchor(11, 12, 13, 14);\r
+\r
+        assertEquals(anchor.getDx1(), 11);\r
+        assertEquals(escher.getDx1(), 11);\r
+        assertEquals(anchor.getDx2(), 13);\r
+        assertEquals(escher.getDx2(), 13);\r
+        assertEquals(anchor.getDy1(), 12);\r
+        assertEquals(escher.getDy1(), 12);\r
+        assertEquals(anchor.getDy2(), 14);\r
+        assertEquals(escher.getDy2(), 14);\r
+\r
+        anchor.setDx1(115);\r
+        assertEquals(anchor.getDx1(), 115);\r
+        assertEquals(escher.getDx1(), 115);\r
+        anchor.setDx2(116);\r
+        assertEquals(anchor.getDx2(), 116);\r
+        assertEquals(escher.getDx2(), 116);\r
+        anchor.setDy1(117);\r
+        assertEquals(anchor.getDy1(), 117);\r
+        assertEquals(escher.getDy1(), 117);\r
+        anchor.setDy2(118);\r
+        assertEquals(anchor.getDy2(), 118);\r
+        assertEquals(escher.getDy2(), 118);\r
+    }\r
+}\r
diff --git a/test-data/spreadsheet/drawings.xls b/test-data/spreadsheet/drawings.xls
new file mode 100644 (file)
index 0000000..ccbcc8c
Binary files /dev/null and b/test-data/spreadsheet/drawings.xls differ