From: Evgeniy Berlog Date: Mon, 18 Jun 2012 20:59:32 +0000 (+0000) Subject: Added such improvements: X-Git-Tag: 3.10-beta1~161^2~24 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=0e8a727b3580b518d3db0a73cf0faf3ed7a5a2d1;p=poi.git Added such improvements: 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 --- diff --git a/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java b/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java index fbca0fb87d..ffc9170c43 100644 --- a/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java +++ b/src/java/org/apache/poi/ddf/EscherClientAnchorRecord.java @@ -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; diff --git a/src/java/org/apache/poi/ddf/EscherRGBProperty.java b/src/java/org/apache/poi/ddf/EscherRGBProperty.java index 5d23addfb5..e28b97b500 100644 --- a/src/java/org/apache/poi/ddf/EscherRGBProperty.java +++ b/src/java/org/apache/poi/ddf/EscherRGBProperty.java @@ -38,6 +38,10 @@ public class EscherRGBProperty return propertyValue; } + public void setRgbColor(int color){ + this.propertyValue = color; + } + public byte getRed() { return (byte) ( propertyValue & 0xFF ); diff --git a/src/java/org/apache/poi/ddf/EscherSimpleProperty.java b/src/java/org/apache/poi/ddf/EscherSimpleProperty.java index 78fb642034..efc392dcfa 100644 --- a/src/java/org/apache/poi/ddf/EscherSimpleProperty.java +++ b/src/java/org/apache/poi/ddf/EscherSimpleProperty.java @@ -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. */ diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java index 6a87806100..2fe36130cf 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java @@ -18,40 +18,64 @@ 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(); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java index ccd0e620cf..38c4f5f0e2 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java @@ -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(); } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java index a040144c27..49e20a42f1 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java @@ -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 - *

+ *

* 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 - *

+ *

* 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()); + } } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java b/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java index 225e6da0e9..2216971e68 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFComment.java @@ -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; diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java index d4a7205c73..5aeb40b188 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFPicture.java @@ -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 index 0a0468c144..0000000000 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFRectangle.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.apache.poi.hssf.usermodel; - -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.hssf.record.ObjRecord; - -/** - * @author Evgeniy Berlog - * @date 08.06.12 - */ -public class HSSFRectangle extends HSSFShape{ - - public HSSFRectangle(EscherContainerRecord spContainer, ObjRecord objRecord) { - super(spContainer, objRecord); - } -} diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java index 7ffdfdb9ba..c9bf922cb7 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java @@ -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 true 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); + } } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java index 4a10a8d07a..68f410d173 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeFactory.java @@ -39,25 +39,25 @@ import java.util.List; import java.util.Map; /** - * @author evgeniy + * @author Evgeniy Berlog * date: 05.06.12 */ public class HSSFShapeFactory { - private static final Map shapeTypeToClass = new HashMap(HSSFShapeType.values().length); + private static final Map shapeTypeToClass = new HashMap(HSSFShapeType.values().length); private static final ReflectionConstructorShapeCreator shapeCreator = new ReflectionConstructorShapeCreator(shapeTypeToClass); static { for (HSSFShapeType type: HSSFShapeType.values()){ - shapeTypeToClass.put(type.getType(), type.getShape()); + shapeTypeToClass.put(type.getType(), type); } } private static class ReflectionConstructorShapeCreator { - private final Map shapeTypeToClass; + private final Map shapeTypeToClass; - private ReflectionConstructorShapeCreator(Map shapeTypeToClass) { + private ReflectionConstructorShapeCreator(Map shapeTypeToClass) { this.shapeTypeToClass = shapeTypeToClass; } @@ -65,7 +65,7 @@ public class HSSFShapeFactory { if (!shapeTypeToClass.containsKey(type)){ return new HSSFUnknownShape(spContainer, objRecord); } - Class clazz = shapeTypeToClass.get(type); + Class clazz = shapeTypeToClass.get(type).getShape(); if (null == clazz){ //System.out.println("No class attached to shape type: "+type); return new HSSFUnknownShape(spContainer, objRecord); @@ -81,26 +81,6 @@ public class HSSFShapeFactory { } } - public static HSSFShape createShape(EscherRecord container, ObjRecord objRecord){ - if (0 == container.getChildRecords().size()){ - throw new IllegalArgumentException("Couldn't create shape from empty escher container"); - } - if (container.getChild(0) instanceof EscherSpgrRecord){ - return new HSSFShapeGroup((EscherContainerRecord) container, objRecord); - } - - //TODO implement cases for all shapes - return new HSSFUnknownShape(container, objRecord); - } - - public static HSSFShapeGroup createShapeGroup(){ - return null; - } - - public static HSSFShapeGroup createSimpleShape(EscherRecord container, ObjRecord objRecord){ - return null; - } - public static void createShapeTree(EscherContainerRecord container, EscherAggregate agg, HSSFShapeContainer out){ if(container.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){ HSSFShapeGroup group = new HSSFShapeGroup(container, @@ -111,10 +91,6 @@ public class HSSFShapeFactory { EscherContainerRecord spContainer = children.get(i); if(i == 0){ EscherSpgrRecord spgr = (EscherSpgrRecord)spContainer.getChildById(EscherSpgrRecord.RECORD_ID); - group.setCoordinates( - spgr.getRectX1(), spgr.getRectY1(), - spgr.getRectX2(), spgr.getRectY2() - ); } else { createShapeTree(spContainer, agg, group); } diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java index 7cab3e493d..b3209467ae 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java @@ -41,32 +41,23 @@ public class HSSFShapeGroup implements HSSFShapeContainer { List shapes = new ArrayList(); - 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(); } /** diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java index ee8522929d..6e0df0fd54 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java @@ -17,6 +17,10 @@ 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 ); } diff --git a/src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java b/src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java index 2818687921..29741c90f8 100644 --- a/src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java +++ b/src/java/org/apache/poi/hssf/usermodel/drawing/HSSFShapeType.java @@ -1,22 +1,24 @@ package org.apache.poi.hssf.usermodel.drawing; -import org.apache.poi.hssf.usermodel.HSSFRectangle; +import org.apache.poi.hssf.usermodel.HSSFSimpleShape; /** * @author Evgeniy Berlog * date: 08.06.12 */ public enum HSSFShapeType { - NOT_PRIMITIVE(0x0, null), - RECTANGLE(0x1, HSSFRectangle.class), - ROUND_RECTANGLE(0x2, null); + NOT_PRIMITIVE((short)0x0, null, (short)0), + RECTANGLE((short)0x1, HSSFSimpleShape.class, HSSFSimpleShape.OBJECT_TYPE_RECTANGLE), + ROUND_RECTANGLE((short)0x2, null, null); private Short type; private Class shape; + private Short objectId; - HSSFShapeType(Integer type, Class shape) { - this.type = type.shortValue(); + private HSSFShapeType(Short type, Class shape, Short objectId) { + this.type = type; this.shape = shape; + this.objectId = objectId; } public Short getType() { 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 index 0000000000..f276cba391 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/model/TestDrawingShapes.java @@ -0,0 +1,160 @@ +package org.apache.poi.hssf.model; + +import junit.framework.TestCase; +import org.apache.poi.ddf.*; +import org.apache.poi.hssf.HSSFTestDataSamples; +import org.apache.poi.hssf.usermodel.*; +import org.apache.poi.util.HexDump; + +import java.io.IOException; + +import static junit.framework.Assert.assertEquals; + +/** + * @author Evgeniy Berlog + * date: 12.06.12 + */ +public class TestDrawingShapes extends TestCase{ + + /** + * HSSFShape tree bust be built correctly + * Check file with such records structure: + * -patriarch + * --shape + * --group + * ---group + * ----shape + * ----shape + * ---shape + * ---group + * ----shape + * ----shape + */ + public void testDrawingGroups(){ + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); + HSSFSheet sheet = wb.getSheet("groups"); + HSSFPatriarch patriarch = sheet.getDrawingPatriarch(); + assertEquals(patriarch.getChildren().size(), 2); + HSSFShapeGroup group = (HSSFShapeGroup) patriarch.getChildren().get(1); + assertEquals(3, group.getChildren().size()); + HSSFShapeGroup group1 = (HSSFShapeGroup) group.getChildren().get(0); + assertEquals(2, group1.getChildren().size()); + group1 = (HSSFShapeGroup) group.getChildren().get(2); + assertEquals(2, group1.getChildren().size()); + } + + public void testHSSFShapeCompatibility() { + HSSFShape shape = new HSSFSimpleShape(null, new HSSFClientAnchor()); + assertEquals(0x08000040, shape.getLineStyleColor()); + assertEquals(0x08000009, shape.getFillColor()); + assertEquals(HSSFShape.LINEWIDTH_DEFAULT, shape.getLineWidth()); + assertEquals(HSSFShape.LINESTYLE_SOLID, shape.getLineStyle()); + assertFalse(shape.isNoFill()); + + AbstractShape sp = AbstractShape.createShape(shape, 1); + EscherContainerRecord spContainer = sp.getSpContainer(); + EscherOptRecord opt = + spContainer.getChildById(EscherOptRecord.RECORD_ID); + + assertEquals(7, opt.getEscherProperties().size()); + assertEquals(true, + ((EscherBoolProperty)opt.lookup(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE)).isTrue()); + assertEquals(0x00000004, + ((EscherSimpleProperty)opt.lookup(EscherProperties.GEOMETRY__SHAPEPATH)).getPropertyValue()); + assertEquals(0x08000009, + ((EscherSimpleProperty)opt.lookup(EscherProperties.FILL__FILLCOLOR)).getPropertyValue()); + assertEquals(true, + ((EscherBoolProperty)opt.lookup(EscherProperties.FILL__NOFILLHITTEST)).isTrue()); + assertEquals(0x08000040, + ((EscherSimpleProperty)opt.lookup(EscherProperties.LINESTYLE__COLOR)).getPropertyValue()); + assertEquals(true, + ((EscherBoolProperty)opt.lookup(EscherProperties.LINESTYLE__NOLINEDRAWDASH)).isTrue()); + assertEquals(true, + ((EscherBoolProperty)opt.lookup(EscherProperties.GROUPSHAPE__PRINT)).isTrue()); + } + /** + * create a rectangle, save the workbook, read back and verify that all shape properties are there + */ + public void testReadWriteRectangle() throws IOException { + + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + HSSFPatriarch drawing = sheet.createDrawingPatriarch(); + HSSFClientAnchor anchor = new HSSFClientAnchor(10, 10, 200, 200, (short)2, 2, (short)15, 15); + anchor.setAnchorType(2); + assertEquals(anchor.getAnchorType(), 2); + + HSSFSimpleShape rectangle = drawing.createSimpleShape(anchor); + rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + rectangle.setLineWidth(10000); + rectangle.setFillColor(777); + assertEquals(rectangle.getFillColor(), 777); + assertEquals(10000, rectangle.getLineWidth()); + rectangle.setLineStyle(10); + assertEquals(10, rectangle.getLineStyle()); + rectangle.setLineStyleColor(1111); + rectangle.setNoFill(true); + assertEquals(rectangle.getLineStyleColor(), 1111); + assertEquals(rectangle.isNoFill(), true); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + + HSSFSimpleShape rectangle2 = + (HSSFSimpleShape)drawing.getChildren().get(0); + assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, + rectangle2.getShapeType()); + assertEquals(10000, rectangle2.getLineWidth()); + assertEquals(10, rectangle2.getLineStyle()); + assertEquals(anchor, rectangle2.getAnchor()); + assertEquals(rectangle2.getLineStyleColor(), 1111); + assertEquals(rectangle2.getFillColor(), 777); + assertEquals(rectangle2.isNoFill(), true); + + rectangle2.setFillColor(3333); + rectangle2.setLineStyle(9); + rectangle2.setLineStyleColor(4444); + rectangle2.setNoFill(false); + rectangle2.setLineWidth(77); + rectangle2.getAnchor().setDx1(2); + rectangle2.getAnchor().setDx2(3); + rectangle2.getAnchor().setDy1(4); + rectangle2.getAnchor().setDy2(5); + + wb = HSSFTestDataSamples.writeOutAndReadBack(wb); + sheet = wb.getSheetAt(0); + drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + rectangle2 = (HSSFSimpleShape)drawing.getChildren().get(0); + assertEquals(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE, rectangle2.getShapeType()); + assertEquals(77, rectangle2.getLineWidth()); + assertEquals(9, rectangle2.getLineStyle()); + assertEquals(rectangle2.getLineStyleColor(), 4444); + assertEquals(rectangle2.getFillColor(), 3333); + assertEquals(rectangle2.getAnchor().getDx1(), 2); + assertEquals(rectangle2.getAnchor().getDx2(), 3); + assertEquals(rectangle2.getAnchor().getDy1(), 4); + assertEquals(rectangle2.getAnchor().getDy2(), 5); + assertEquals(rectangle2.isNoFill(), false); + } + + + /* assert shape properties when reading shapes from a existing workbook */ + public void testReadExistingRectangle() { + HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("drawings.xls"); + HSSFSheet sheet = wb.getSheet("rectangles"); + HSSFPatriarch drawing = sheet.getDrawingPatriarch(); + assertEquals(1, drawing.getChildren().size()); + + for(HSSFShape shape : drawing.getChildren()){ + assertEquals(shape.isNoFill(), true); + assertEquals(shape.getLineStyle(), HSSFShape.LINESTYLE_DASHDOTGEL); + assertEquals(shape.getLineStyleColor(), 0x616161); + assertEquals(HexDump.toHex(shape.getFillColor()), shape.getFillColor(), 0x2CE03D); + assertEquals(shape.getLineWidth(), HSSFShape.LINEWIDTH_ONE_PT*2); + } + } +} 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 index 0000000000..ef90f01f40 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/model/TestHSSFAnchor.java @@ -0,0 +1,209 @@ +package org.apache.poi.hssf.model; + +import junit.framework.TestCase; +import org.apache.poi.ddf.EscherChildAnchorRecord; +import org.apache.poi.ddf.EscherClientAnchorRecord; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.hssf.usermodel.*; + +/** + * @author Evgeniy Berlog + * @date 12.06.12 + */ +public class TestHSSFAnchor extends TestCase { + + public void testCreateClientAnchorFromContainer(){ + EscherContainerRecord container = new EscherContainerRecord(); + EscherClientAnchorRecord escher = new EscherClientAnchorRecord(); + escher.setFlag((short) 3); + escher.setCol1((short)11); + escher.setCol2((short)12); + escher.setRow1((short)13); + escher.setRow2((short) 14); + escher.setDx1((short) 15); + escher.setDx2((short) 16); + escher.setDy1((short) 17); + escher.setDy2((short) 18); + container.addChildRecord(escher); + + HSSFClientAnchor anchor = (HSSFClientAnchor) HSSFAnchor.createAnchorFromEscher(container); + assertEquals(anchor.getCol1(), 11); + assertEquals(escher.getCol1(), 11); + assertEquals(anchor.getCol2(), 12); + assertEquals(escher.getCol2(), 12); + assertEquals(anchor.getRow1(), 13); + assertEquals(escher.getRow1(), 13); + assertEquals(anchor.getRow2(), 14); + assertEquals(escher.getRow2(), 14); + assertEquals(anchor.getDx1(), 15); + assertEquals(escher.getDx1(), 15); + assertEquals(anchor.getDx2(), 16); + assertEquals(escher.getDx2(), 16); + assertEquals(anchor.getDy1(), 17); + assertEquals(escher.getDy1(), 17); + assertEquals(anchor.getDy2(), 18); + assertEquals(escher.getDy2(), 18); + } + + public void testCreateChildAnchorFromContainer(){ + EscherContainerRecord container = new EscherContainerRecord(); + EscherChildAnchorRecord escher = new EscherChildAnchorRecord(); + escher.setDx1((short) 15); + escher.setDx2((short) 16); + escher.setDy1((short) 17); + escher.setDy2((short) 18); + container.addChildRecord(escher); + + HSSFChildAnchor anchor = (HSSFChildAnchor) HSSFAnchor.createAnchorFromEscher(container); + assertEquals(anchor.getDx1(), 15); + assertEquals(escher.getDx1(), 15); + assertEquals(anchor.getDx2(), 16); + assertEquals(escher.getDx2(), 16); + assertEquals(anchor.getDy1(), 17); + assertEquals(escher.getDy1(), 17); + assertEquals(anchor.getDy2(), 18); + assertEquals(escher.getDy2(), 18); + } + + public void testShapeEscherMustHaveAnchorRecord(){ + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFSheet sheet = wb.createSheet(); + + HSSFPatriarch drawing = sheet.createDrawingPatriarch(); + HSSFClientAnchor anchor = new HSSFClientAnchor(10, 10, 200, 200, (short)2, 2, (short)15, 15); + anchor.setAnchorType(2); + + HSSFSimpleShape rectangle = drawing.createSimpleShape(anchor); + rectangle.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE); + + rectangle.setAnchor(anchor); + + assertNotNull(anchor.getEscherAnchor()); + assertNotNull(rectangle.getEscherContainer()); + assertTrue(anchor.getEscherAnchor().equals(rectangle.getEscherContainer().getChildById(EscherClientAnchorRecord.RECORD_ID))); + } + + public void testClientAnchorFromEscher(){ + EscherClientAnchorRecord escher = new EscherClientAnchorRecord(); + escher.setCol1((short)11); + escher.setCol2((short)12); + escher.setRow1((short)13); + escher.setRow2((short) 14); + escher.setDx1((short) 15); + escher.setDx2((short) 16); + escher.setDy1((short) 17); + escher.setDy2((short) 18); + + HSSFClientAnchor anchor = new HSSFClientAnchor(escher); + assertEquals(anchor.getCol1(), 11); + assertEquals(escher.getCol1(), 11); + assertEquals(anchor.getCol2(), 12); + assertEquals(escher.getCol2(), 12); + assertEquals(anchor.getRow1(), 13); + assertEquals(escher.getRow1(), 13); + assertEquals(anchor.getRow2(), 14); + assertEquals(escher.getRow2(), 14); + assertEquals(anchor.getDx1(), 15); + assertEquals(escher.getDx1(), 15); + assertEquals(anchor.getDx2(), 16); + assertEquals(escher.getDx2(), 16); + assertEquals(anchor.getDy1(), 17); + assertEquals(escher.getDy1(), 17); + assertEquals(anchor.getDy2(), 18); + assertEquals(escher.getDy2(), 18); + } + + public void testClientAnchorFromScratch(){ + HSSFClientAnchor anchor = new HSSFClientAnchor(); + EscherClientAnchorRecord escher = (EscherClientAnchorRecord) anchor.getEscherAnchor(); + anchor.setAnchor((short)11, 12, 13, 14, (short)15, 16, 17, 18); + + assertEquals(anchor.getCol1(), 11); + assertEquals(escher.getCol1(), 11); + assertEquals(anchor.getCol2(), 15); + assertEquals(escher.getCol2(), 15); + assertEquals(anchor.getRow1(), 12); + assertEquals(escher.getRow1(), 12); + assertEquals(anchor.getRow2(), 16); + assertEquals(escher.getRow2(), 16); + assertEquals(anchor.getDx1(), 13); + assertEquals(escher.getDx1(), 13); + assertEquals(anchor.getDx2(), 17); + assertEquals(escher.getDx2(), 17); + assertEquals(anchor.getDy1(), 14); + assertEquals(escher.getDy1(), 14); + assertEquals(anchor.getDy2(), 18); + assertEquals(escher.getDy2(), 18); + + anchor.setCol1(111); + assertEquals(anchor.getCol1(), 111); + assertEquals(escher.getCol1(), 111); + anchor.setCol2(112); + assertEquals(anchor.getCol2(), 112); + assertEquals(escher.getCol2(), 112); + anchor.setRow1(113); + assertEquals(anchor.getRow1(), 113); + assertEquals(escher.getRow1(), 113); + anchor.setRow2(114); + assertEquals(anchor.getRow2(), 114); + assertEquals(escher.getRow2(), 114); + anchor.setDx1(115); + assertEquals(anchor.getDx1(), 115); + assertEquals(escher.getDx1(), 115); + anchor.setDx2(116); + assertEquals(anchor.getDx2(), 116); + assertEquals(escher.getDx2(), 116); + anchor.setDy1(117); + assertEquals(anchor.getDy1(), 117); + assertEquals(escher.getDy1(), 117); + anchor.setDy2(118); + assertEquals(anchor.getDy2(), 118); + assertEquals(escher.getDy2(), 118); + } + + public void testChildAnchorFromEscher(){ + EscherChildAnchorRecord escher = new EscherChildAnchorRecord(); + escher.setDx1((short) 15); + escher.setDx2((short) 16); + escher.setDy1((short) 17); + escher.setDy2((short) 18); + + HSSFChildAnchor anchor = new HSSFChildAnchor(escher); + assertEquals(anchor.getDx1(), 15); + assertEquals(escher.getDx1(), 15); + assertEquals(anchor.getDx2(), 16); + assertEquals(escher.getDx2(), 16); + assertEquals(anchor.getDy1(), 17); + assertEquals(escher.getDy1(), 17); + assertEquals(anchor.getDy2(), 18); + assertEquals(escher.getDy2(), 18); + } + + public void testChildAnchorFromScratch(){ + HSSFChildAnchor anchor = new HSSFChildAnchor(); + EscherChildAnchorRecord escher = (EscherChildAnchorRecord) anchor.getEscherAnchor(); + anchor.setAnchor(11, 12, 13, 14); + + assertEquals(anchor.getDx1(), 11); + assertEquals(escher.getDx1(), 11); + assertEquals(anchor.getDx2(), 13); + assertEquals(escher.getDx2(), 13); + assertEquals(anchor.getDy1(), 12); + assertEquals(escher.getDy1(), 12); + assertEquals(anchor.getDy2(), 14); + assertEquals(escher.getDy2(), 14); + + anchor.setDx1(115); + assertEquals(anchor.getDx1(), 115); + assertEquals(escher.getDx1(), 115); + anchor.setDx2(116); + assertEquals(anchor.getDx2(), 116); + assertEquals(escher.getDx2(), 116); + anchor.setDy1(117); + assertEquals(anchor.getDy1(), 117); + assertEquals(escher.getDy1(), 117); + anchor.setDy2(118); + assertEquals(anchor.getDy2(), 118); + assertEquals(escher.getDy2(), 118); + } +} diff --git a/test-data/spreadsheet/drawings.xls b/test-data/spreadsheet/drawings.xls new file mode 100644 index 0000000000..ccbcc8cb4a Binary files /dev/null and b/test-data/spreadsheet/drawings.xls differ