From 7458fdc277abf235c1933ede00a9aa6b0e8866ac Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Sat, 21 Nov 2015 15:54:01 +0000 Subject: [PATCH] In preparation for table rendering, added table row heights and column widths to common sl. To have better results in rendering switch anchor from java.awt.Rectangle to Rectangle2D. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1715540 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hslf/examples/ApacheconEU08.java | 5 +- .../apache/poi/hslf/examples/TableDemo.java | 3 +- .../apache/poi/sl/draw/DrawBackground.java | 7 +- .../apache/poi/sl/draw/DrawPictureShape.java | 19 ++-- .../apache/poi/sl/draw/DrawTextParagraph.java | 5 +- .../apache/poi/sl/usermodel/GroupShape.java | 6 +- .../poi/sl/usermodel/PlaceableShape.java | 6 +- .../org/apache/poi/sl/usermodel/Shape.java | 4 +- .../apache/poi/sl/usermodel/TableShape.java | 16 +++ src/java/org/apache/poi/util/Units.java | 6 +- .../poi/xslf/usermodel/XSLFBackground.java | 6 +- .../poi/xslf/usermodel/XSLFDrawing.java | 20 ++-- .../poi/xslf/usermodel/XSLFFreeformShape.java | 3 +- .../poi/xslf/usermodel/XSLFGraphicFrame.java | 20 ++-- .../poi/xslf/usermodel/XSLFGroupShape.java | 32 +++--- .../apache/poi/xslf/usermodel/XSLFShadow.java | 6 +- .../poi/xslf/usermodel/XSLFSimpleShape.java | 16 +-- .../apache/poi/xslf/usermodel/XSLFTable.java | 6 ++ .../poi/xslf/usermodel/XSLFTextShape.java | 6 +- .../org/apache/poi/sl/TestTable.java | 64 ++++++++++++ .../poi/sl/draw/TestDrawPictureShape.java | 31 ++++-- .../usermodel/TestXSLFConnectorShape.java | 17 ++-- .../xslf/usermodel/TestXSLFFreeformShape.java | 6 +- .../xslf/usermodel/TestXSLFGroupShape.java | 6 +- .../xslf/usermodel/TestXSLFTextParagraph.java | 12 +-- .../poi/hslf/usermodel/HSLFFreeformShape.java | 3 +- .../poi/hslf/usermodel/HSLFGroupShape.java | 74 +++++++------- .../poi/hslf/usermodel/HSLFPictureShape.java | 6 +- .../apache/poi/hslf/usermodel/HSLFShape.java | 20 ++-- .../apache/poi/hslf/usermodel/HSLFSheet.java | 14 +-- .../apache/poi/hslf/usermodel/HSLFTable.java | 91 ++++++++++++------ .../poi/hslf/usermodel/HSLFTableCell.java | 42 ++++---- .../poi/hslf/usermodel/HSLFTextShape.java | 11 ++- .../apache/poi/hslf/model/TestMovieShape.java | 4 +- .../poi/hslf/model/TestOleEmbedding.java | 42 +++++--- .../org/apache/poi/hslf/model/TestShapes.java | 56 ++++++----- .../org/apache/poi/hslf/model/TestTable.java | 43 +++++---- .../apache/poi/hslf/usermodel/TestTable.java | 8 +- .../sl/draw/geom/TestPresetGeometries.java | 4 +- test-data/slideshow/table_test.ppt | Bin 0 -> 122368 bytes test-data/slideshow/table_test.pptx | Bin 0 -> 28935 bytes 41 files changed, 459 insertions(+), 287 deletions(-) create mode 100644 src/ooxml/testcases/org/apache/poi/sl/TestTable.java create mode 100644 test-data/slideshow/table_test.ppt create mode 100644 test-data/slideshow/table_test.pptx diff --git a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java index 8101c71f6..32a6c7d1c 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java +++ b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java @@ -22,6 +22,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.io.FileOutputStream; import java.io.IOException; import java.util.List; @@ -183,8 +184,8 @@ public final class ApacheconEU08 { table1.setRowHeight(1, 80); Dimension dim = ppt.getPageSize(); - Rectangle oldAnchor = table1.getAnchor(); - table1.setAnchor(new Rectangle((dim.width-450)/2, 100, oldAnchor.width, oldAnchor.height)); + Rectangle2D oldAnchor = table1.getAnchor(); + table1.setAnchor(new Rectangle2D.Double((dim.width-450)/2, 100, oldAnchor.getWidth(), oldAnchor.getHeight())); TextBox box1 = slide.createTextBox(); box1.setHorizontalCentered(true); diff --git a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java index c8a139590..817541ee8 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java @@ -78,7 +78,7 @@ public final class TableDemo { table1.setColumnWidth(1, 150); int pgWidth = ppt.getPageSize().width; - table1.moveTo((pgWidth - table1.getAnchor().width)/2, 100); + table1.moveTo((pgWidth - table1.getAnchor().getWidth())/2., 100.); //test data for the second taable String[][] txt2 = { @@ -125,5 +125,6 @@ public final class TableDemo { ppt.write(out); out.close(); + ppt.close(); } } diff --git a/src/java/org/apache/poi/sl/draw/DrawBackground.java b/src/java/org/apache/poi/sl/draw/DrawBackground.java index a06c2da23..b09bc9858 100644 --- a/src/java/org/apache/poi/sl/draw/DrawBackground.java +++ b/src/java/org/apache/poi/sl/draw/DrawBackground.java @@ -20,7 +20,6 @@ package org.apache.poi.sl.draw; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Paint; -import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import org.apache.poi.sl.usermodel.Background; @@ -36,12 +35,12 @@ public class DrawBackground extends DrawShape { @SuppressWarnings("rawtypes") public void draw(Graphics2D graphics) { Dimension pg = shape.getSheet().getSlideShow().getPageSize(); - final Rectangle anchor = new Rectangle(0, 0, (int)pg.getWidth(), (int)pg.getHeight()); + final Rectangle2D anchor = new Rectangle2D.Double(0, 0, pg.getWidth(), pg.getHeight()); PlaceableShape ps = new PlaceableShape(){ public ShapeContainer getParent() { return null; } - public Rectangle getAnchor() { return anchor; } - public void setAnchor(Rectangle newAnchor) {} + public Rectangle2D getAnchor() { return anchor; } + public void setAnchor(Rectangle2D newAnchor) {} public double getRotation() { return 0; } public void setRotation(double theta) {} public void setFlipHorizontal(boolean flip) {} diff --git a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java index 534d246ad..5976dbeae 100644 --- a/src/java/org/apache/poi/sl/draw/DrawPictureShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawPictureShape.java @@ -20,7 +20,6 @@ package org.apache.poi.sl.draw; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Insets; -import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.io.IOException; @@ -70,12 +69,12 @@ public class DrawPictureShape extends DrawSimpleShape { PictureShape ps = getShape(); Dimension dim = ps.getPictureData().getImageDimension(); - Rectangle origRect = ps.getAnchor(); - int x = (int)origRect.getX(); - int y = (int)origRect.getY(); - int w = (int)dim.getWidth(); - int h = (int)dim.getHeight(); - ps.setAnchor(new Rectangle(x, y, w, h)); + Rectangle2D origRect = ps.getAnchor(); + double x = origRect.getX(); + double y = origRect.getY(); + double w = dim.getWidth(); + double h = dim.getHeight(); + ps.setAnchor(new Rectangle2D.Double(x, y, w, h)); } @@ -85,7 +84,7 @@ public class DrawPictureShape extends DrawSimpleShape { * * @param target The target rectangle */ - public void resize(Rectangle target) { + public void resize(Rectangle2D target) { resize(target, RectAlign.CENTER); } @@ -100,7 +99,7 @@ public class DrawPictureShape extends DrawSimpleShape { * The alignment within the target rectangle when resizing. * A null value corresponds to RectAlign.CENTER */ - public void resize(Rectangle target, RectAlign align) { + public void resize(Rectangle2D target, RectAlign align) { PictureShape ps = getShape(); Dimension dim = ps.getPictureData().getImageDimension(); if (dim.width <= 0 || dim.height <= 0) { @@ -170,6 +169,6 @@ public class DrawPictureShape extends DrawSimpleShape { break; } - ps.setAnchor(new Rectangle((int)x, (int)y, (int)w, (int)h)); + ps.setAnchor(new Rectangle2D.Double(x, y, w, h)); } } diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java index 0bd364b9e..65233fe0b 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -19,7 +19,6 @@ package org.apache.poi.sl.draw; import java.awt.Graphics2D; import java.awt.Paint; -import java.awt.Rectangle; import java.awt.font.FontRenderContext; import java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute; @@ -427,8 +426,8 @@ public class DrawTextParagraph implements Drawable { private PlaceableShape getParagraphShape() { PlaceableShape ps = new PlaceableShape(){ public ShapeContainer getParent() { return null; } - public Rectangle getAnchor() { return paragraph.getParentShape().getAnchor(); } - public void setAnchor(Rectangle anchor) {} + public Rectangle2D getAnchor() { return paragraph.getParentShape().getAnchor(); } + public void setAnchor(Rectangle2D anchor) {} public double getRotation() { return 0; } public void setRotation(double theta) {} public void setFlipHorizontal(boolean flip) {} diff --git a/src/java/org/apache/poi/sl/usermodel/GroupShape.java b/src/java/org/apache/poi/sl/usermodel/GroupShape.java index 87396b587..a7545a4d4 100644 --- a/src/java/org/apache/poi/sl/usermodel/GroupShape.java +++ b/src/java/org/apache/poi/sl/usermodel/GroupShape.java @@ -17,7 +17,7 @@ package org.apache.poi.sl.usermodel; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; public interface GroupShape< S extends Shape, @@ -30,7 +30,7 @@ public interface GroupShape< * * @return the coordinate space of this group */ - Rectangle getInteriorAnchor(); + Rectangle2D getInteriorAnchor(); /** * Sets the coordinate space of this group. All children are constrained @@ -38,5 +38,5 @@ public interface GroupShape< * * @param anchor the coordinate space of this group */ - void setInteriorAnchor(Rectangle anchor); + void setInteriorAnchor(Rectangle2D anchor); } diff --git a/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java b/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java index bcba7401c..191bad65f 100644 --- a/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java +++ b/src/java/org/apache/poi/sl/usermodel/PlaceableShape.java @@ -17,7 +17,7 @@ package org.apache.poi.sl.usermodel; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; public interface PlaceableShape< S extends Shape, @@ -29,13 +29,13 @@ public interface PlaceableShape< * @return the position of this shape within the drawing canvas. * The coordinates are expressed in points */ - Rectangle getAnchor(); + Rectangle2D getAnchor(); /** * @param anchor the position of this shape within the drawing canvas. * The coordinates are expressed in points */ - void setAnchor(Rectangle anchor); + void setAnchor(Rectangle2D anchor); /** * Rotation angle in degrees diff --git a/src/java/org/apache/poi/sl/usermodel/Shape.java b/src/java/org/apache/poi/sl/usermodel/Shape.java index a05e3bf45..36f8379c5 100644 --- a/src/java/org/apache/poi/sl/usermodel/Shape.java +++ b/src/java/org/apache/poi/sl/usermodel/Shape.java @@ -17,7 +17,7 @@ package org.apache.poi.sl.usermodel; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; public interface Shape< S extends Shape, @@ -37,5 +37,5 @@ public interface Shape< * * @return the anchor of this shape */ - Rectangle getAnchor(); + Rectangle2D getAnchor(); } diff --git a/src/java/org/apache/poi/sl/usermodel/TableShape.java b/src/java/org/apache/poi/sl/usermodel/TableShape.java index 561448446..5070cf405 100644 --- a/src/java/org/apache/poi/sl/usermodel/TableShape.java +++ b/src/java/org/apache/poi/sl/usermodel/TableShape.java @@ -27,6 +27,14 @@ public interface TableShape< TableCell getCell(int row, int col); + /** + * Gets the width (in points) of the n-th column + * + * @param idx the column index (0-based) + * @return the width (in points) + */ + double getColumnWidth(int idx); + /** * Sets the width (in points) of the n-th column * @@ -35,6 +43,14 @@ public interface TableShape< */ void setColumnWidth(int idx, double width); + /** + * Gets the row height + * + * @param row the row index (0-based) + * @return the height (in points) + */ + double getRowHeight(int row); + /** * Sets the row height. * diff --git a/src/java/org/apache/poi/util/Units.java b/src/java/org/apache/poi/util/Units.java index c871fc0a3..55b6d40f0 100644 --- a/src/java/org/apache/poi/util/Units.java +++ b/src/java/org/apache/poi/util/Units.java @@ -51,7 +51,7 @@ public class Units { * @return emus */ public static int toEMU(double points){ - return (int)Math.round(EMU_PER_POINT*points); + return (int)Math.rint(EMU_PER_POINT*points); } /** @@ -103,13 +103,13 @@ public class Units { public static int pointsToMaster(double points) { points *= MASTER_DPI; points /= POINT_DPI; - return (int)points; + return (int)Math.rint(points); } public static int pointsToPixel(double points) { points *= PIXEL_DPI; points /= POINT_DPI; - return (int)points; + return (int)Math.rint(points); } public static double pixelToPoints(int pixel) { diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java index 817d2edcc..6dbdf2d4f 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFBackground.java @@ -19,7 +19,7 @@ package org.apache.poi.xslf.usermodel; import java.awt.Color; import java.awt.Dimension; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.usermodel.Background; @@ -43,9 +43,9 @@ public class XSLFBackground extends XSLFSimpleShape } @Override - public Rectangle getAnchor(){ + public Rectangle2D getAnchor(){ Dimension pg = getSheet().getSlideShow().getPageSize(); - return new Rectangle(0, 0, (int)pg.getWidth(), (int)pg.getHeight()); + return new Rectangle2D.Double(0, 0, pg.getWidth(), pg.getHeight()); } @Override diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java index f312145b9..ccf0c7b30 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFDrawing.java @@ -16,6 +16,9 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; +import java.awt.Color; +import java.awt.geom.Rectangle2D; + import org.apache.poi.util.Beta; import org.apache.xmlbeans.XmlObject; import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; @@ -25,9 +28,6 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; -import java.awt.Color; -import java.awt.Rectangle; - /** * @author Yegor Kozlov @@ -57,7 +57,7 @@ public class XSLFDrawing { CTShape sp = _spTree.addNewSp(); sp.set(XSLFAutoShape.prototype(_shapeId++)); XSLFAutoShape shape = new XSLFAutoShape(sp, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); return shape; } @@ -65,7 +65,7 @@ public class XSLFDrawing { CTShape sp = _spTree.addNewSp(); sp.set(XSLFFreeformShape.prototype(_shapeId++)); XSLFFreeformShape shape = new XSLFFreeformShape(sp, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); return shape; } @@ -73,7 +73,7 @@ public class XSLFDrawing { CTShape sp = _spTree.addNewSp(); sp.set(XSLFTextBox.prototype(_shapeId++)); XSLFTextBox shape = new XSLFTextBox(sp, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); return shape; } @@ -81,7 +81,7 @@ public class XSLFDrawing { CTConnector sp = _spTree.addNewCxnSp(); sp.set(XSLFConnectorShape.prototype(_shapeId++)); XSLFConnectorShape shape = new XSLFConnectorShape(sp, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); shape.setLineColor(Color.black); shape.setLineWidth(0.75); return shape; @@ -91,7 +91,7 @@ public class XSLFDrawing { CTGroupShape obj = _spTree.addNewGrpSp(); obj.set(XSLFGroupShape.prototype(_shapeId++)); XSLFGroupShape shape = new XSLFGroupShape(obj, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); return shape; } @@ -99,7 +99,7 @@ public class XSLFDrawing { CTPicture obj = _spTree.addNewPic(); obj.set(XSLFPictureShape.prototype(_shapeId++, rel)); XSLFPictureShape shape = new XSLFPictureShape(obj, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); return shape; } @@ -107,7 +107,7 @@ public class XSLFDrawing { CTGraphicalObjectFrame obj = _spTree.addNewGraphicFrame(); obj.set(XSLFTable.prototype(_shapeId++)); XSLFTable shape = new XSLFTable(obj, _sheet); - shape.setAnchor(new Rectangle()); + shape.setAnchor(new Rectangle2D.Double()); return shape; } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java index 4f14fc1a8..1f2352393 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFFreeformShape.java @@ -19,7 +19,6 @@ package org.apache.poi.xslf.usermodel; -import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; @@ -61,7 +60,7 @@ public class XSLFFreeformShape extends XSLFAutoShape public int setPath(GeneralPath path) { CTPath2D ctPath = CTPath2D.Factory.newInstance(); - Rectangle bounds = path.getBounds(); + Rectangle2D bounds = path.getBounds2D(); int x0 = Units.toEMU(bounds.getX()); int y0 = Units.toEMU(bounds.getY()); PathIterator it = path.getPathIterator(new AffineTransform()); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java index 930acd402..8e4977e7d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGraphicFrame.java @@ -19,7 +19,7 @@ package org.apache.poi.xslf.usermodel; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import javax.xml.namespace.QName; @@ -28,6 +28,7 @@ import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.sl.draw.DrawNotImplemented; +import org.apache.poi.sl.usermodel.PlaceableShape; import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.util.Beta; import org.apache.poi.util.Units; @@ -44,7 +45,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFra */ @Beta @DrawNotImplemented -public class XSLFGraphicFrame extends XSLFShape { +public class XSLFGraphicFrame extends XSLFShape implements PlaceableShape { /*package*/ XSLFGraphicFrame(CTGraphicalObjectFrame shape, XSLFSheet sheet){ super(shape,sheet); } @@ -54,18 +55,19 @@ public class XSLFGraphicFrame extends XSLFShape { } @Override - public Rectangle getAnchor(){ + public Rectangle2D getAnchor(){ CTTransform2D xfrm = ((CTGraphicalObjectFrame)getXmlObject()).getXfrm(); CTPoint2D off = xfrm.getOff(); - int x = (int)Units.toPoints(off.getX()); - int y = (int)Units.toPoints(off.getY()); + double x = Units.toPoints(off.getX()); + double y = Units.toPoints(off.getY()); CTPositiveSize2D ext = xfrm.getExt(); - int cx = (int)Units.toPoints(ext.getCx()); - int cy = (int)Units.toPoints(ext.getCy()); - return new Rectangle(x, y, cx, cy); + double cx = Units.toPoints(ext.getCx()); + double cy = Units.toPoints(ext.getCy()); + return new Rectangle2D.Double(x, y, cx, cy); } - public void setAnchor(Rectangle anchor){ + @Override + public void setAnchor(Rectangle2D anchor){ CTTransform2D xfrm = ((CTGraphicalObjectFrame)getXmlObject()).getXfrm(); CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff(); long x = Units.toEMU(anchor.getX()); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java index 5f66e9fca..b3aba60dd 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java @@ -19,7 +19,7 @@ package org.apache.poi.xslf.usermodel; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -79,19 +79,19 @@ implements XSLFShapeContainer, GroupShape { } @Override - public Rectangle getAnchor(){ + public Rectangle2D getAnchor(){ CTGroupTransform2D xfrm = getXfrm(); CTPoint2D off = xfrm.getOff(); - int x = (int)Units.toPoints(off.getX()); - int y = (int)Units.toPoints(off.getY()); + double x = Units.toPoints(off.getX()); + double y = Units.toPoints(off.getY()); CTPositiveSize2D ext = xfrm.getExt(); - int cx = (int)Units.toPoints(ext.getCx()); - int cy = (int)Units.toPoints(ext.getCy()); - return new Rectangle(x,y,cx,cy); + double cx = Units.toPoints(ext.getCx()); + double cy = Units.toPoints(ext.getCy()); + return new Rectangle2D.Double(x,y,cx,cy); } @Override - public void setAnchor(Rectangle anchor){ + public void setAnchor(Rectangle2D anchor){ CTGroupTransform2D xfrm = getSafeXfrm(); CTPoint2D off = xfrm.isSetOff() ? xfrm.getOff() : xfrm.addNewOff(); long x = Units.toEMU(anchor.getX()); @@ -111,15 +111,16 @@ implements XSLFShapeContainer, GroupShape { * used for calculations of grouping, scaling, and rotation * behavior of shapes placed within a group. */ - public Rectangle getInteriorAnchor(){ + @Override + public Rectangle2D getInteriorAnchor(){ CTGroupTransform2D xfrm = getXfrm(); CTPoint2D off = xfrm.getChOff(); - int x = (int)Units.toPoints(off.getX()); - int y = (int)Units.toPoints(off.getY()); + double x = Units.toPoints(off.getX()); + double y = Units.toPoints(off.getY()); CTPositiveSize2D ext = xfrm.getChExt(); - int cx = (int)Units.toPoints(ext.getCx()); - int cy = (int)Units.toPoints(ext.getCy()); - return new Rectangle(x, y, cx, cy); + double cx = Units.toPoints(ext.getCx()); + double cy = Units.toPoints(ext.getCy()); + return new Rectangle2D.Double(x, y, cx, cy); } /** @@ -128,7 +129,8 @@ implements XSLFShapeContainer, GroupShape { * used for calculations of grouping, scaling, and rotation * behavior of shapes placed within a group. */ - public void setInteriorAnchor(Rectangle anchor) { + @Override + public void setInteriorAnchor(Rectangle2D anchor) { CTGroupTransform2D xfrm = getSafeXfrm(); CTPoint2D off = xfrm.isSetChOff() ? xfrm.getChOff() : xfrm.addNewChOff(); long x = Units.toEMU(anchor.getX()); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java index f5d41c293..4adeba302 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShadow.java @@ -18,7 +18,7 @@ package org.apache.poi.xslf.usermodel; import java.awt.Color; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import org.apache.poi.sl.draw.DrawPaint; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; @@ -48,11 +48,11 @@ public class XSLFShadow extends XSLFShape implements ShadowRectangle2D that is the bounds of this shape. */ - public Rectangle resizeToFitText(){ - Rectangle anchor = getAnchor(); + public Rectangle2D resizeToFitText(){ + Rectangle2D anchor = getAnchor(); if(anchor.getWidth() == 0.) throw new POIXMLException( "Anchor of the shape was not set."); double height = getTextHeight(); diff --git a/src/ooxml/testcases/org/apache/poi/sl/TestTable.java b/src/ooxml/testcases/org/apache/poi/sl/TestTable.java new file mode 100644 index 000000000..d9a3717be --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/sl/TestTable.java @@ -0,0 +1,64 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + */ + +package org.apache.poi.sl; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.sl.usermodel.SlideShow; +import org.apache.poi.sl.usermodel.SlideShowFactory; +import org.apache.poi.sl.usermodel.TableShape; +import org.junit.Test; + +public class TestTable { + private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); + + @Test + public void testColWidthRowHeight() throws IOException { + // Test of table dimensions of same slideshow saved as ppt/x + // to check if both return similar (points) value + SlideShow ppt = SlideShowFactory.create(_slTests.getFile("table_test.ppt")); + TableShape ts = (TableShape)ppt.getSlides().get(0).getShapes().get(0); + int cols = ts.getNumberOfColumns(); + int rows = ts.getNumberOfRows(); + + SlideShow pptx = SlideShowFactory.create(_slTests.getFile("table_test.pptx")); + TableShape tsx = (TableShape)pptx.getSlides().get(0).getShapes().get(0); + int colsx = tsx.getNumberOfColumns(); + int rowsx = tsx.getNumberOfRows(); + + assertEquals(cols, colsx); + assertEquals(rows, rowsx); + + for (int i=0; i master -> points + static double rbf(double val, PictureShape picShape) { + if (picShape.getClass().getName().contains("HSLF")) { + return Units.masterToPoints(Units.pointsToMaster(val)); + } else { + return val; + } + } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFConnectorShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFConnectorShape.java index beed20719..fb86c1926 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFConnectorShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFConnectorShape.java @@ -20,13 +20,18 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.awt.Color; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape; import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize; -import org.apache.poi.sl.usermodel.*; +import org.apache.poi.sl.usermodel.ShapeType; import org.junit.Test; -import org.openxmlformats.schemas.drawingml.x2006.main.*; +import org.openxmlformats.schemas.drawingml.x2006.main.CTConnection; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualConnectorProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndLength; +import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndType; +import org.openxmlformats.schemas.drawingml.x2006.main.STLineEndWidth; +import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; import org.openxmlformats.schemas.presentationml.x2006.main.CTConnector; /** @@ -122,17 +127,17 @@ public class TestXSLFConnectorShape { XSLFAutoShape rect1 = slide.createAutoShape(); rect1.setShapeType(ShapeType.RECT); - rect1.setAnchor(new Rectangle(100, 100, 100, 100)); + rect1.setAnchor(new Rectangle2D.Double(100, 100, 100, 100)); rect1.setFillColor(Color.blue); XSLFAutoShape rect2 = slide.createAutoShape(); rect2.setShapeType(ShapeType.RECT); - rect2.setAnchor(new Rectangle(300, 300, 100, 100)); + rect2.setAnchor(new Rectangle2D.Double(300, 300, 100, 100)); rect2.setFillColor(Color.red); XSLFConnectorShape connector1 = slide.createConnector(); - connector1.setAnchor(new Rectangle(200, 150, 100, 200)); + connector1.setAnchor(new Rectangle2D.Double(200, 150, 100, 200)); CTConnector ctConnector = (CTConnector)connector1.getXmlObject(); ctConnector.getSpPr().getPrstGeom().setPrst(STShapeType.BENT_CONNECTOR_3); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java index 92eb9a798..720c5f6e0 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFFreeformShape.java @@ -16,11 +16,11 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; -import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; import org.junit.Test; @@ -35,7 +35,7 @@ public class TestXSLFFreeformShape { XSLFSlide slide = ppt.createSlide(); XSLFFreeformShape shape1 = slide.createFreeform(); // comples path consisting of a rectangle and an ellipse inside it - GeneralPath path1 = new GeneralPath(new Rectangle(150, 150, 300, 300)); + GeneralPath path1 = new GeneralPath(new Rectangle2D.Double(150, 150, 300, 300)); path1.append(new Ellipse2D.Double(200, 200, 100, 50), false); shape1.setPath(path1); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFGroupShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFGroupShape.java index f5d180121..ff06d5107 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFGroupShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFGroupShape.java @@ -21,7 +21,7 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.awt.Dimension; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import org.junit.Test; @@ -40,11 +40,11 @@ public class TestXSLFGroupShape { XSLFGroupShape group = slide.createGroup(); assertEquals(1, slide.getShapes().size()); - Rectangle interior = new Rectangle(-10, -10, 20, 20); + Rectangle2D interior = new Rectangle2D.Double(-10, -10, 20, 20); group.setInteriorAnchor(interior); assertEquals(interior, group.getInteriorAnchor()); - Rectangle anchor = new Rectangle(0, 0, 792, 612); + Rectangle2D anchor = new Rectangle2D.Double(0, 0, 792, 612); group.setAnchor(anchor); assertEquals(anchor, group.getAnchor()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java index a57771080..7824616a7 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java @@ -24,7 +24,7 @@ import static org.junit.Assert.assertTrue; import java.awt.Color; import java.awt.Graphics2D; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; @@ -74,7 +74,7 @@ public class TestXSLFTextParagraph { "of text within a shape. Properties here apply to all text " + "residing within the corresponding paragraph."); - Rectangle anchor = new Rectangle(50, 50, 300, 200); + Rectangle2D anchor = new Rectangle2D.Double(50, 50, 300, 200); sh.setAnchor(anchor); DrawTextParagraphProxy dtp = new DrawTextParagraphProxy(p); @@ -172,7 +172,7 @@ public class TestXSLFTextParagraph { "of text within a shape. Properties here apply to all text " + "residing within the corresponding paragraph."); - sh.setAnchor(new Rectangle(50, 50, 300, 200)); + sh.setAnchor(new Rectangle2D.Double(50, 50, 300, 200)); DrawTextParagraphProxy dtp = new DrawTextParagraphProxy(p); BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); @@ -184,13 +184,13 @@ public class TestXSLFTextParagraph { assertEquals(4, lines.size()); // decrease the shape width from 300 pt to 100 pt - sh.setAnchor(new Rectangle(50, 50, 100, 200)); + sh.setAnchor(new Rectangle2D.Double(50, 50, 100, 200)); dtp.breakText(graphics); lines = dtp.getLines(); assertEquals(12, lines.size()); // decrease the shape width from 300 pt to 100 pt - sh.setAnchor(new Rectangle(50, 50, 600, 200)); + sh.setAnchor(new Rectangle2D.Double(50, 50, 600, 200)); dtp.breakText(graphics); lines = dtp.getLines(); assertEquals(2, lines.size()); @@ -224,7 +224,7 @@ public class TestXSLFTextParagraph { assertEquals("POI", lines.get(1).getString()); XSLFAutoShape sh2 = slide.createAutoShape(); - sh2.setAnchor(new Rectangle(50, 50, 300, 200)); + sh2.setAnchor(new Rectangle2D.Double(50, 50, 300, 200)); XSLFTextParagraph p2 = sh2.addNewTextParagraph(); XSLFTextRun r2 = p2.addNewTextRun(); r2.setFontFamily("serif"); // this should always be available diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java index 0c21c7e8b..dde778ffc 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java @@ -17,7 +17,6 @@ package org.apache.poi.hslf.usermodel; -import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; @@ -90,7 +89,7 @@ public final class HSLFFreeformShape extends HSLFAutoShape implements FreeformSh @Override public int setPath(GeneralPath path) { - Rectangle bounds = path.getBounds(); + Rectangle2D bounds = path.getBounds2D(); PathIterator it = path.getPathIterator(new AffineTransform()); List segInfo = new ArrayList(); diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java index bbfe93f97..bae325a0f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.usermodel; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -73,7 +73,7 @@ implements HSLFShapeContainer, GroupShape { } @Override - public void setAnchor(Rectangle anchor) { + public void setAnchor(Rectangle2D anchor) { EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); boolean isInitialized = !(clientAnchor.getDx1() == 0 && clientAnchor.getRow1() == 0); @@ -85,7 +85,7 @@ implements HSLFShapeContainer, GroupShape { } @Override - public void setInteriorAnchor(Rectangle anchor){ + public void setInteriorAnchor(Rectangle2D anchor){ EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); int x1 = Units.pointsToMaster(anchor.getX()); @@ -100,16 +100,16 @@ implements HSLFShapeContainer, GroupShape { } @Override - public Rectangle getInteriorAnchor(){ + public Rectangle2D getInteriorAnchor(){ EscherSpgrRecord rec = getEscherChild(EscherSpgrRecord.RECORD_ID); - int x1 = (int)Units.masterToPoints(rec.getRectX1()); - int y1 = (int)Units.masterToPoints(rec.getRectY1()); - int x2 = (int)Units.masterToPoints(rec.getRectX2()); - int y2 = (int)Units.masterToPoints(rec.getRectY2()); - return new Rectangle(x1,y1,x2-x1,y2-y1); + double x1 = Units.masterToPoints(rec.getRectX1()); + double y1 = Units.masterToPoints(rec.getRectY1()); + double x2 = Units.masterToPoints(rec.getRectX2()); + double y2 = Units.masterToPoints(rec.getRectY2()); + return new Rectangle2D.Double(x1,y1,x2-x1,y2-y1); } - protected void setExteriorAnchor(Rectangle anchor) { + protected void setExteriorAnchor(Rectangle2D anchor) { EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); //hack. internal variable EscherClientAnchorRecord.shortRecord can be @@ -121,10 +121,10 @@ implements HSLFShapeContainer, GroupShape { clientAnchor.fillFields(header, 0, null); // All coordinates need to be converted to Master units (576 dpi) - clientAnchor.setFlag((short)Units.pointsToMaster(anchor.y)); - clientAnchor.setCol1((short)Units.pointsToMaster(anchor.x)); - clientAnchor.setDx1((short)Units.pointsToMaster(anchor.width + anchor.x)); - clientAnchor.setRow1((short)Units.pointsToMaster(anchor.height + anchor.y)); + clientAnchor.setFlag((short)Units.pointsToMaster(anchor.getY())); + clientAnchor.setCol1((short)Units.pointsToMaster(anchor.getX())); + clientAnchor.setDx1((short)Units.pointsToMaster(anchor.getWidth() + anchor.getX())); + clientAnchor.setRow1((short)Units.pointsToMaster(anchor.getHeight() + anchor.getY())); // TODO: does this make sense? setInteriorAnchor(anchor); @@ -177,20 +177,20 @@ implements HSLFShapeContainer, GroupShape { /** * Moves and scales this ShapeGroup to the specified anchor. */ - protected void moveAndScale(Rectangle anchorDest){ - Rectangle anchorSrc = getAnchor(); - double scaleX = (anchorSrc.width == 0) ? 0 : anchorDest.width / (double)anchorSrc.width; - double scaleY = (anchorSrc.height == 0) ? 0 : anchorDest.height / (double)anchorSrc.height; + protected void moveAndScale(Rectangle2D anchorDest){ + Rectangle2D anchorSrc = getAnchor(); + double scaleX = (anchorSrc.getWidth() == 0) ? 0 : anchorDest.getWidth() / anchorSrc.getWidth(); + double scaleY = (anchorSrc.getHeight() == 0) ? 0 : anchorDest.getHeight() / anchorSrc.getHeight(); setExteriorAnchor(anchorDest); for (HSLFShape shape : getShapes()) { - Rectangle chanchor = shape.getAnchor(); - int x = (int)Math.rint(anchorDest.x+(chanchor.x-anchorSrc.x)*scaleX); - int y = (int)Math.rint(anchorDest.y+(chanchor.y-anchorSrc.y)*scaleY); - int width = (int)Math.rint(chanchor.width*scaleX); - int height = (int)Math.rint(chanchor.height*scaleY); - shape.setAnchor(new Rectangle(x, y, width, height)); + Rectangle2D chanchor = shape.getAnchor(); + double x = anchorDest.getX()+(chanchor.getX()-anchorSrc.getX())*scaleX; + double y = anchorDest.getY()+(chanchor.getY()-anchorSrc.getY())*scaleY; + double width = chanchor.getWidth()*scaleX; + double height = chanchor.getHeight()*scaleY; + shape.setAnchor(new Rectangle2D.Double(x, y, width, height)); } } @@ -200,7 +200,7 @@ implements HSLFShapeContainer, GroupShape { * * @return the anchor of this shape group */ - public Rectangle getAnchor(){ + public Rectangle2D getAnchor(){ EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); int x1,y1,x2,y2; if(clientAnchor == null){ @@ -216,11 +216,11 @@ implements HSLFShapeContainer, GroupShape { x2 = clientAnchor.getDx1(); y2 = clientAnchor.getRow1(); } - Rectangle anchor= new Rectangle( - (int)(x1 == -1 ? -1 : Units.masterToPoints(x1)), - (int)(y1 == -1 ? -1 : Units.masterToPoints(y1)), - (int)(x2 == -1 ? -1 : Units.masterToPoints(x2-x1)), - (int)(y2 == -1 ? -1 : Units.masterToPoints(y2-y1)) + Rectangle2D anchor= new Rectangle2D.Double( + (x1 == -1 ? -1 : Units.masterToPoints(x1)), + (y1 == -1 ? -1 : Units.masterToPoints(y1)), + (x2 == -1 ? -1 : Units.masterToPoints(x2-x1)), + (y2 == -1 ? -1 : Units.masterToPoints(y2-y1)) ); return anchor; @@ -295,7 +295,7 @@ implements HSLFShapeContainer, GroupShape { public HSLFTextBox createTextBox() { HSLFTextBox s = new HSLFTextBox(this); s.setHorizontalCentered(true); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } @@ -304,7 +304,7 @@ implements HSLFShapeContainer, GroupShape { public HSLFAutoShape createAutoShape() { HSLFAutoShape s = new HSLFAutoShape(ShapeType.RECT, this); s.setHorizontalCentered(true); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } @@ -313,7 +313,7 @@ implements HSLFShapeContainer, GroupShape { public HSLFFreeformShape createFreeform() { HSLFFreeformShape s = new HSLFFreeformShape(this); s.setHorizontalCentered(true); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } @@ -321,7 +321,7 @@ implements HSLFShapeContainer, GroupShape { @Override public HSLFConnectorShape createConnector() { HSLFConnectorShape s = new HSLFConnectorShape(this); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } @@ -329,7 +329,7 @@ implements HSLFShapeContainer, GroupShape { @Override public HSLFGroupShape createGroup() { HSLFGroupShape s = new HSLFGroupShape(this); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } @@ -340,7 +340,7 @@ implements HSLFShapeContainer, GroupShape { throw new IllegalArgumentException("pictureData needs to be of type HSLFPictureData"); } HSLFPictureShape s = new HSLFPictureShape((HSLFPictureData)pictureData, this); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } @@ -351,7 +351,7 @@ implements HSLFShapeContainer, GroupShape { throw new IllegalArgumentException("numRows and numCols must be greater than 0"); } HSLFTable s = new HSLFTable(numRows,numCols,this); - s.setAnchor(new Rectangle(0, 0, 100, 100)); + s.setAnchor(new Rectangle2D.Double(0, 0, 100, 100)); addShape(s); return s; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java index 713ecad70..81acffa25 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java @@ -18,7 +18,7 @@ package org.apache.poi.hslf.usermodel; import java.awt.Insets; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.util.List; import org.apache.poi.ddf.AbstractEscherOptRecord; @@ -113,6 +113,7 @@ public class HSLFPictureShape extends HSLFSimpleShape implements PictureShape { * * @return the anchor of this shape */ - public Rectangle getAnchor() { + public Rectangle2D getAnchor() { EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); int flags = spRecord.getFlags(); int x1,y1,x2,y2; @@ -156,11 +156,11 @@ public abstract class HSLFShape implements Shape { } // TODO: find out where this -1 value comes from at #57820 (link to ms docs?) - Rectangle anchor = new Rectangle( - (int)(x1 == -1 ? -1 : Units.masterToPoints(x1)), - (int)(y1 == -1 ? -1 : Units.masterToPoints(y1)), - (int)(x2 == -1 ? -1 : Units.masterToPoints(x2-x1)), - (int)(y2 == -1 ? -1 : Units.masterToPoints(y2-y1)) + Rectangle2D anchor = new Rectangle2D.Double( + (x1 == -1 ? -1 : Units.masterToPoints(x1)), + (y1 == -1 ? -1 : Units.masterToPoints(y1)), + (x2 == -1 ? -1 : Units.masterToPoints(x2-x1)), + (y2 == -1 ? -1 : Units.masterToPoints(y2-y1)) ); return anchor; @@ -172,7 +172,7 @@ public abstract class HSLFShape implements Shape { * * @param anchor new anchor */ - public void setAnchor(Rectangle anchor){ + public void setAnchor(Rectangle2D anchor){ int x = Units.pointsToMaster(anchor.getX()); int y = Units.pointsToMaster(anchor.getY()); int w = Units.pointsToMaster(anchor.getWidth() + anchor.getX()); @@ -201,10 +201,10 @@ public abstract class HSLFShape implements Shape { * @param x the x coordinate of the top left corner of the shape * @param y the y coordinate of the top left corner of the shape */ - public final void moveTo(float x, float y) { + public final void moveTo(double x, double y) { // This convenience method should be implemented via setAnchor in subclasses // see HSLFGroupShape.setAnchor() for a reference - Rectangle anchor = getAnchor(); + Rectangle2D anchor = getAnchor(); anchor.setRect(x, y, anchor.getWidth(), anchor.getHeight()); setAnchor(anchor); } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java index 1a46a5e17..35ab5f204 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java @@ -18,7 +18,7 @@ package org.apache.poi.hslf.usermodel; import java.awt.Graphics2D; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -402,7 +402,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet { if(numRows < 1) throw new IllegalArgumentException("The number of rows must be greater than 1"); if(numCols < 1) throw new IllegalArgumentException("The number of columns must be greater than 1"); - int x=0, y=0, tblWidth=0, tblHeight=0; + double x=0, y=0, tblWidth=0, tblHeight=0; cells = new HSLFTableCell[numRows][numCols]; for (int i = 0; i < cells.length; i++) { x = 0; for (int j = 0; j < cells[i].length; j++) { cells[i][j] = new HSLFTableCell(this); - Rectangle anchor = new Rectangle(x, y, HSLFTableCell.DEFAULT_WIDTH, HSLFTableCell.DEFAULT_HEIGHT); + Rectangle2D anchor = new Rectangle2D.Double(x, y, HSLFTableCell.DEFAULT_WIDTH, HSLFTableCell.DEFAULT_HEIGHT); cells[i][j].setAnchor(anchor); x += HSLFTableCell.DEFAULT_WIDTH; } @@ -90,7 +90,7 @@ implements HSLFShapeContainer, TableShape { } tblWidth = x; tblHeight = y; - setExteriorAnchor(new Rectangle(0, 0, tblWidth, tblHeight)); + setExteriorAnchor(new Rectangle2D.Double(0, 0, tblWidth, tblHeight)); EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0); AbstractEscherOptRecord opt = new EscherOptRecord(); @@ -159,13 +159,18 @@ implements HSLFShapeContainer, TableShape { private static class TableCellComparator implements Comparator { public int compare( HSLFShape o1, HSLFShape o2 ) { - Rectangle anchor1 = o1.getAnchor(); - Rectangle anchor2 = o2.getAnchor(); - int delta = anchor1.y - anchor2.y; - if (delta == 0) delta = anchor1.x - anchor2.x; + Rectangle2D anchor1 = o1.getAnchor(); + Rectangle2D anchor2 = o2.getAnchor(); + double delta = anchor1.getY() - anchor2.getY(); + if (delta == 0) { + delta = anchor1.getX() - anchor2.getX(); + } // descending size - if (delta == 0) delta = (anchor2.width*anchor2.height)-(anchor1.width*anchor1.height); - return delta; + if (delta == 0) { + delta = (anchor2.getWidth()*anchor2.getHeight())-(anchor1.getWidth()*anchor1.getHeight()); + } + + return (int)Math.signum(delta); } } @@ -176,7 +181,7 @@ implements HSLFShapeContainer, TableShape { htc.add((HSLFTableCell)h); } } - + if (htc.isEmpty()) { throw new IllegalStateException("HSLFTable without HSLFTableCells"); } @@ -186,12 +191,12 @@ implements HSLFShapeContainer, TableShape { List lst = new ArrayList(); List row = new ArrayList(); - int y0 = htc.get(0).getAnchor().y; + double y0 = htc.get(0).getAnchor().getY(); for (HSLFTableCell sh : htc) { - Rectangle anchor = sh.getAnchor(); - boolean isNextRow = (anchor.y > y0); + Rectangle2D anchor = sh.getAnchor(); + boolean isNextRow = (anchor.getY() > y0); if (isNextRow) { - y0 = anchor.y; + y0 = anchor.getY(); lst.add(row.toArray(new HSLFTableCell[row.size()])); row.clear(); } @@ -207,7 +212,7 @@ implements HSLFShapeContainer, TableShape { final double lx1, lx2, ly1, ly2; LineRect(HSLFLine l) { this.l = l; - Rectangle r = l.getAnchor(); + Rectangle2D r = l.getAnchor(); lx1 = r.getMinX(); lx2 = r.getMaxX(); ly1 = r.getMinY(); @@ -240,7 +245,7 @@ implements HSLFShapeContainer, TableShape { // TODO: this only works for non-rotated tables for (HSLFTableCell[] tca : cells) { for (HSLFTableCell tc : tca) { - final Rectangle cellAnchor = tc.getAnchor(); + final Rectangle2D cellAnchor = tc.getAnchor(); /** * x1/y1 --------+ @@ -321,29 +326,53 @@ implements HSLFShapeContainer, TableShape { } } + @Override + public double getRowHeight(int row) { + if (row < 0 || row >= cells.length) { + throw new IllegalArgumentException("Row index '"+row+"' is not within range [0-"+(cells.length-1)+"]"); + } + + return cells[row][0].getAnchor().getHeight(); + } + @Override public void setRowHeight(int row, double height) { + if (row < 0 || row >= cells.length) { + throw new IllegalArgumentException("Row index '"+row+"' is not within range [0-"+(cells.length-1)+"]"); + } + int pxHeight = Units.pointsToPixel(height); - int currentHeight = cells[row][0].getAnchor().height; - int dy = pxHeight - currentHeight; + double currentHeight = cells[row][0].getAnchor().getHeight(); + double dy = pxHeight - currentHeight; for (int i = row; i < cells.length; i++) { for (int j = 0; j < cells[i].length; j++) { - Rectangle anchor = cells[i][j].getAnchor(); + Rectangle2D anchor = cells[i][j].getAnchor(); if(i == row) { - anchor.height = pxHeight; + anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), pxHeight); } else { - anchor.y += dy; + anchor.setRect(anchor.getX(), anchor.getY()+dy, anchor.getWidth(), pxHeight); } cells[i][j].setAnchor(anchor); } } - Rectangle tblanchor = getAnchor(); - tblanchor.height += dy; + Rectangle2D tblanchor = getAnchor(); + tblanchor.setRect(tblanchor.getX(), tblanchor.getY(), tblanchor.getWidth(), tblanchor.getHeight() + dy); setExteriorAnchor(tblanchor); } + @Override + public double getColumnWidth(int col) { + if (col < 0 || col >= cells[0].length) { + throw new IllegalArgumentException("Column index '"+col+"' is not within range [0-"+(cells[0].length-1)+"]"); + } + + // TODO: check for merged cols + double width = cells[0][col].getAnchor().getWidth(); + return width; + } + @Override public void setColumnWidth(int col, final double width){ if (col < 0 || col >= cells[0].length) { @@ -352,20 +381,20 @@ implements HSLFShapeContainer, TableShape { double currentWidth = cells[0][col].getAnchor().getWidth(); double dx = width - currentWidth; for (HSLFTableCell cols[] : cells) { - Rectangle anchor = cols[col].getAnchor(); - anchor.width = (int)Math.rint(width); + Rectangle2D anchor = cols[col].getAnchor(); + anchor.setRect(anchor.getX(), anchor.getY(), width, anchor.getHeight()); cols[col].setAnchor(anchor); if (col < cols.length - 1) { for (int j = col+1; j < cols.length; j++) { anchor = cols[j].getAnchor(); - anchor.x += dx; + anchor.setRect(anchor.getX()+dx, anchor.getY(), anchor.getWidth(), anchor.getHeight()); cols[j].setAnchor(anchor); } } } - Rectangle tblanchor = getAnchor(); - tblanchor.width += dx; + Rectangle2D tblanchor = getAnchor(); + tblanchor.setRect(tblanchor.getX(), tblanchor.getY(), tblanchor.getWidth() + dx, tblanchor.getHeight()); setExteriorAnchor(tblanchor); } @@ -393,7 +422,7 @@ implements HSLFShapeContainer, TableShape { } @Override - protected void moveAndScale(Rectangle anchorDest){ + protected void moveAndScale(Rectangle2D anchorDest){ super.moveAndScale(anchorDest); updateRowHeightsProperty(); } @@ -403,7 +432,7 @@ implements HSLFShapeContainer, TableShape { EscherArrayProperty p = opt.lookup(EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES); byte[] val = new byte[4]; for (int rowIdx = 0; rowIdx < cells.length; rowIdx++) { - int rowHeight = Units.pointsToMaster(cells[rowIdx][0].getAnchor().height); + int rowHeight = Units.pointsToMaster(cells[rowIdx][0].getAnchor().getHeight()); LittleEndian.putInt(val, 0, rowHeight); p.setElement(rowIdx, val); } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java index 80341aa35..aee899483 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java @@ -18,7 +18,7 @@ package org.apache.poi.hslf.usermodel; import java.awt.Color; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import org.apache.poi.ddf.AbstractEscherOptRecord; import org.apache.poi.ddf.EscherContainerRecord; @@ -85,40 +85,40 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell { } catch (IOException e){ throw new HSLFException(e); } - if(getAnchor().equals(new Rectangle()) && !"".equals(getText())) resizeToFitText(); + boolean isInitialAnchor = getAnchor().equals(new Rectangle2D.Double()); + boolean isFilledTxt = !"".equals(getText()); + if (isInitialAnchor && isFilledTxt) { + resizeToFitText(); + } } for (HSLFTextParagraph htp : _paragraphs) { htp.setShapeId(getShapeId()); @@ -250,10 +253,10 @@ implements TextShape { * @return a Rectangle2D that is the bounds of this shape. */ public Rectangle2D resizeToFitText(){ - Rectangle anchor = getAnchor(); + Rectangle2D anchor = getAnchor(); if(anchor.getWidth() == 0.) { logger.log(POILogger.WARN, "Width of shape wasn't set. Defaulting to 200px"); - anchor.setSize(200, (int)anchor.getHeight()); + anchor.setRect(anchor.getX(), anchor.getY(), 200., anchor.getHeight()); setAnchor(anchor); } double height = getTextHeight(); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java index 7b6e762cf..7e96707d1 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java @@ -21,7 +21,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -50,7 +50,7 @@ public final class TestMovieShape { HSLFPictureData thumbnailData = ppt.addPicture(_slTests.readFile("tomcat.png"), PictureType.PNG); MovieShape shape = new MovieShape(movieIdx, thumbnailData); - shape.setAnchor(new Rectangle(300,225,120,90)); + shape.setAnchor(new Rectangle2D.Double(300,225,120,90)); slide.addShape(shape); assertEquals(path, shape.getPath()); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java index 5babd1bf8..e3c739001 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java @@ -20,10 +20,11 @@ package org.apache.poi.hslf.model; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.util.List; @@ -50,23 +51,36 @@ public final class TestOleEmbedding { * @throws Exception if an error occurs. */ @Test - public void testOleEmbedding2003() throws Exception { + public void testOleEmbedding2003() throws IOException { HSLFSlideShowImpl slideShow = new HSLFSlideShowImpl(_slTests.openResourceAsStream("ole2-embedding-2003.ppt")); // Placeholder EMFs for clients that don't support the OLE components. List pictures = slideShow.getPictureData(); assertEquals("Should be two pictures", 2, pictures.size()); - //assertDigestEquals("Wrong data for picture 1", "8d1fbadf4814f321bb1ccdd056e3c788", pictures[0].getData()); - //assertDigestEquals("Wrong data for picture 2", "987a698e83559cf3d38a0deeba1cc63b", pictures[1].getData()); + + long checkSums[] = { 0xD37A4204l, 0x26A62F68l, 0x82853169l, 0xE0E45D2Bl }; + int checkId = 0; + + // check for checksum to be uptodate + for (HSLFPictureData pd : pictures) { + long checkEMF = IOUtils.calculateChecksum(pd.getData()); + assertEquals(checkSums[checkId++], checkEMF); + } // Actual embedded objects. HSLFObjectData[] objects = slideShow.getEmbeddedObjects(); assertEquals("Should be two objects", 2, objects.length); - //assertDigestEquals("Wrong data for objecs 1", "0d1fcc61a83de5c4894dc0c88e9a019d", objects[0].getData()); - //assertDigestEquals("Wrong data for object 2", "b323604b2003a7299c77c2693b641495", objects[1].getData()); + for (HSLFObjectData od : objects) { + long checkEMF = IOUtils.calculateChecksum(od.getData()); + assertEquals(checkSums[checkId++], checkEMF); + } + + slideShow.close(); } + + @Test - public void testOLEShape() throws Exception { + public void testOLEShape() throws IOException { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("ole2-embedding-2003.ppt")); HSLFSlide slide = ppt.getSlides().get(0); @@ -97,12 +111,12 @@ public final class TestOleEmbedding { } assertEquals("Expected 2 OLE shapes", 2, cnt); + ppt.close(); } @Test - public void testEmbedding() throws Exception { - HSLFSlideShowImpl _hslfSlideShow = HSLFSlideShowImpl.create(); - HSLFSlideShow ppt = new HSLFSlideShow(_hslfSlideShow); + public void testEmbedding() throws IOException { + HSLFSlideShow ppt = new HSLFSlideShow(); File pict = POIDataSamples.getSlideShowInstance().getFile("clock.jpg"); HSLFPictureData pictData = ppt.addPicture(pict, PictureType.JPEG); @@ -117,7 +131,7 @@ public final class TestOleEmbedding { OLEShape oleShape1 = new OLEShape(pictData); oleShape1.setObjectID(oleObjectId1); slide1.addShape(oleShape1); - oleShape1.setAnchor(new Rectangle(100,100,100,100)); + oleShape1.setAnchor(new Rectangle2D.Double(100,100,100,100)); // add second slide with different order in object creation HSLFSlide slide2 = ppt.createSlide(); @@ -131,7 +145,7 @@ public final class TestOleEmbedding { oleShape2.setObjectID(oleObjectId2); slide2.addShape(oleShape2); - oleShape2.setAnchor(new Rectangle(100,100,100,100)); + oleShape2.setAnchor(new Rectangle2D.Double(100,100,100,100)); ByteArrayOutputStream bos = new ByteArrayOutputStream(); ppt.write(bos); @@ -148,6 +162,8 @@ public final class TestOleEmbedding { poiData1.close(); poiData2.close(); - + ppt.close(); } + + } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java index 3ce7a71b9..bf23bd403 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java @@ -26,7 +26,7 @@ import static org.junit.Assert.assertTrue; import java.awt.Color; import java.awt.Dimension; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -49,7 +49,6 @@ import org.apache.poi.hslf.usermodel.HSLFShape; import org.apache.poi.hslf.usermodel.HSLFSimpleShape; import org.apache.poi.hslf.usermodel.HSLFSlide; import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFTextBox; import org.apache.poi.hslf.usermodel.HSLFTextParagraph; import org.apache.poi.hslf.usermodel.HSLFTextRun; @@ -84,7 +83,7 @@ public final class TestShapes { } @Test - public void graphics() throws Exception { + public void graphics() throws IOException { HSLFSlide slide = ppt.createSlide(); HSLFLine line = new HSLFLine(); @@ -96,7 +95,7 @@ public final class TestShapes { slide.addShape(line); HSLFAutoShape ellipse = new HSLFAutoShape(ShapeType.ELLIPSE); - java.awt.Rectangle ellipseAnchor = new Rectangle(320, 154, 55, 111); + Rectangle2D ellipseAnchor = new Rectangle2D.Double(320, 154, 55, 111); ellipse.setAnchor(ellipseAnchor); ellipse.setLineWidth(2); ellipse.setLineDash(LineDash.SOLID); @@ -110,10 +109,10 @@ public final class TestShapes { //read ppt from byte array - ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertEquals(1, ppt.getSlides().size()); + HSLFSlideShow ppt2 = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); + assertEquals(1, ppt2.getSlides().size()); - slide = ppt.getSlides().get(0); + slide = ppt2.getSlides().get(0); List shape = slide.getShapes(); assertEquals(2, shape.size()); @@ -122,6 +121,8 @@ public final class TestShapes { assertTrue(shape.get(1) instanceof HSLFAutoShape); //group shape assertEquals(ellipseAnchor, shape.get(1).getAnchor()); //group shape + + ppt2.close(); } /** @@ -129,7 +130,7 @@ public final class TestShapes { * @throws Exception */ @Test - public void textBoxRead() throws Exception { + public void textBoxRead() throws IOException { ppt = new HSLFSlideShow(_slTests.openResourceAsStream("with_textbox.ppt")); HSLFSlide sl = ppt.getSlides().get(0); for (HSLFShape sh : sl.getShapes()) { @@ -161,7 +162,7 @@ public final class TestShapes { @SuppressWarnings("unused") @Test - public void testParagraphs() throws Exception { + public void testParagraphs() throws IOException { HSLFSlideShow ss = new HSLFSlideShow(); HSLFSlide slide = ss.createSlide(); HSLFTextBox shape = new HSLFTextBox(); @@ -175,7 +176,7 @@ public final class TestShapes { p2r2.setStrikethrough(true); // run 3 has same text properties as run 2 and will be merged when saving HSLFTextRun p2r3 = shape.appendText("para 2 run 3.", false); - shape.setAnchor(new Rectangle(100,100,100,10)); + shape.setAnchor(new Rectangle2D.Double(100,100,100,10)); slide.addShape(shape); shape.resizeToFitText(); @@ -207,7 +208,7 @@ public final class TestShapes { * and set some of the style attributes */ @Test - public void textBoxWriteBytes() throws Exception { + public void textBoxWriteBytes() throws IOException { ppt = new HSLFSlideShow(); HSLFSlide sl = ppt.createSlide(); HSLFTextRun rt; @@ -241,8 +242,8 @@ public final class TestShapes { ppt.write(out); out.close(); - ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - sl = ppt.getSlides().get(0); + HSLFSlideShow ppt2 = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); + sl = ppt2.getSlides().get(0); txtbox = (HSLFTextBox)sl.getShapes().get(0); rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); @@ -255,6 +256,8 @@ public final class TestShapes { assertFalse(rt.isUnderlined()); assertEquals("Arial", rt.getFontFamily()); assertTrue(sameColor(Color.red, rt.getFontColor())); + + ppt2.close(); } /** @@ -276,7 +279,7 @@ public final class TestShapes { * it must be the same as returned by Slide.getTextRuns(). */ @Test - public void textBoxSet() throws Exception { + public void textBoxSet() throws IOException { textBoxSet("with_textbox.ppt"); textBoxSet("basic_test_ppt_file.ppt"); textBoxSet("next_test_ppt_file.ppt"); @@ -285,7 +288,7 @@ public final class TestShapes { textBoxSet("incorrect_slide_order.ppt"); } - private void textBoxSet(String filename) throws Exception { + private void textBoxSet(String filename) throws IOException { HSLFSlideShow ss = new HSLFSlideShow(_slTests.openResourceAsStream(filename)); for (HSLFSlide sld : ss.getSlides()) { ArrayList lst1 = new ArrayList(); @@ -311,13 +314,14 @@ public final class TestShapes { assertTrue(lst1.containsAll(lst2)); assertTrue(lst2.containsAll(lst1)); } + ss.close(); } /** * Test adding shapes to ShapeGroup */ @Test - public void shapeGroup() throws Exception { + public void shapeGroup() throws IOException { HSLFSlideShow ss = new HSLFSlideShow(); HSLFSlide slide = ss.createSlide(); @@ -325,22 +329,23 @@ public final class TestShapes { HSLFGroupShape group = new HSLFGroupShape(); - group.setAnchor(new Rectangle(0, 0, (int)pgsize.getWidth(), (int)pgsize.getHeight())); + group.setAnchor(new Rectangle2D.Double(0, 0, pgsize.getWidth(), pgsize.getHeight())); slide.addShape(group); HSLFPictureData data = ss.addPicture(_slTests.readFile("clock.jpg"), PictureType.JPEG); HSLFPictureShape pict = new HSLFPictureShape(data, group); - pict.setAnchor(new Rectangle(0, 0, 200, 200)); + pict.setAnchor(new Rectangle2D.Double(0, 0, 200, 200)); group.addShape(pict); HSLFLine line = new HSLFLine(group); - line.setAnchor(new Rectangle(300, 300, 500, 0)); + line.setAnchor(new Rectangle2D.Double(300, 300, 500, 0)); group.addShape(line); //serialize and read again. ByteArrayOutputStream out = new ByteArrayOutputStream(); ss.write(out); out.close(); + ss.close(); ByteArrayInputStream is = new ByteArrayInputStream(out.toByteArray()); ss = new HSLFSlideShow(is); @@ -359,10 +364,12 @@ public final class TestShapes { assertTrue(grshape.get(1) instanceof HSLFLine); pict = (HSLFPictureShape)grshape.get(0); - assertEquals(new Rectangle(0, 0, 200, 200), pict.getAnchor()); + assertEquals(new Rectangle2D.Double(0, 0, 200, 200), pict.getAnchor()); line = (HSLFLine)grshape.get(1); - assertEquals(new Rectangle(300, 300, 500, 0), line.getAnchor()); + assertEquals(new Rectangle2D.Double(300, 300, 500, 0), line.getAnchor()); + + ss.close(); } /** @@ -387,10 +394,12 @@ public final class TestShapes { ByteArrayOutputStream out = new ByteArrayOutputStream(); ss.write(out); out.close(); + ss.close(); ss = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); sl = ss.getSlides().get(0); assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().size()); + ss.close(); } @Test @@ -409,7 +418,7 @@ public final class TestShapes { } @Test - public void shapeId() { + public void shapeId() throws IOException { HSLFSlideShow ss = new HSLFSlideShow(); HSLFSlide slide = ss.createSlide(); HSLFShape shape = null; @@ -456,6 +465,7 @@ public final class TestShapes { slide.addShape(shape); } assertEquals(numClusters + 1, dgg.getNumIdClusters()); + ss.close(); } @Test @@ -482,5 +492,7 @@ public final class TestShapes { assertEquals("Border width is 5 pt", sh4.getText()); assertEquals(Color.black, sh4.getLineColor()); assertEquals(5.0, sh4.getLineWidth(), 0); + + ss.close(); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java index 9b11555b1..3c7bc9c9a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java @@ -25,6 +25,7 @@ import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.List; import org.apache.poi.POIDataSamples; @@ -42,8 +43,6 @@ import org.junit.Test; /** * Test Table object. - * - * @author Yegor Kozlov */ public final class TestTable { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); @@ -52,7 +51,7 @@ public final class TestTable { * Test that ShapeFactory works properly and returns Table */ @Test - public void testShapeFactory() throws Exception { + public void testShapeFactory() throws IOException { HSLFSlideShow ppt = new HSLFSlideShow(); HSLFSlide slide = ppt.createSlide(); @@ -72,20 +71,22 @@ public final class TestTable { ByteArrayOutputStream out = new ByteArrayOutputStream(); ppt.write(out); out.close(); - + ppt.close(); + ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); slide = ppt.getSlides().get(0); assertTrue(slide.getShapes().get(0) instanceof HSLFTable); HSLFTable tbl3 = (HSLFTable)slide.getShapes().get(0); assertEquals(tbl.getNumberOfColumns(), tbl3.getNumberOfColumns()); assertEquals(tbl.getNumberOfRows(), tbl3.getNumberOfRows()); + ppt.close(); } /** * Error constructing Table when rownum=1 */ @Test - public void test45889(){ + public void test45889() throws IOException { HSLFSlideShow ppt = new HSLFSlideShow(); HSLFSlide slide = ppt.createSlide(); List shapes; @@ -101,24 +102,25 @@ public final class TestTable { assertEquals(tbl1.getNumberOfColumns(), tbl2.getNumberOfColumns()); assertEquals(tbl1.getNumberOfRows(), tbl2.getNumberOfRows()); + ppt.close(); } - @Test - public void testIllegalCOnstruction(){ + @Test(expected=IllegalArgumentException.class) + public void testIllegalRowCnstruction() throws IOException { HSLFSlideShow ppt = new HSLFSlideShow(); HSLFSlide slide = ppt.createSlide(); - try { - slide.createTable(0, 5); - fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1"); - } catch (IllegalArgumentException e){ + slide.createTable(0, 5); + fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1"); + ppt.close(); + } - } - try { - slide.createTable(5, 0); - fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1"); - } catch (IllegalArgumentException e){ - - } + @Test(expected=IllegalArgumentException.class) + public void testIllegalColConstruction() throws IOException { + HSLFSlideShow ppt = new HSLFSlideShow(); + HSLFSlide slide = ppt.createSlide(); + slide.createTable(5, 0); + fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1"); + ppt.close(); } /** @@ -126,7 +128,7 @@ public final class TestTable { * when the table is positioned with its top at -1 */ @Test - public void test57820() throws Exception { + public void test57820() throws IOException { SlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("bug57820-initTableNullRefrenceException.ppt")); List> slides = ppt.getSlides(); @@ -143,7 +145,8 @@ public final class TestTable { } assertNotNull(tbl); - assertEquals(-1, tbl.getAnchor().getY(), 0); + + ppt.close(); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java index 7a917fafd..a151db2ba 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java @@ -25,7 +25,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.awt.Color; -import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -58,10 +58,10 @@ public class TestTable { new DrawTableShape(table).setAllBorders(1.0, Color.black, StrokeStyle.LineDash.DASH_DOT); - table.setAnchor(new Rectangle(100, 100, 400, 400)); + table.setAnchor(new Rectangle2D.Double(100, 100, 400, 400)); - Rectangle rectExp = new Rectangle(420,367,80,133); - Rectangle rectAct = table.getCell(rows-1, cols-1).getAnchor(); + Rectangle2D rectExp = new Rectangle2D.Double(420,366.625,80,133.375); + Rectangle2D rectAct = table.getCell(rows-1, cols-1).getAnchor(); assertEquals(rectExp, rectAct); ppt.close(); } diff --git a/src/testcases/org/apache/poi/sl/draw/geom/TestPresetGeometries.java b/src/testcases/org/apache/poi/sl/draw/geom/TestPresetGeometries.java index 59dd694da..49338e0b6 100644 --- a/src/testcases/org/apache/poi/sl/draw/geom/TestPresetGeometries.java +++ b/src/testcases/org/apache/poi/sl/draw/geom/TestPresetGeometries.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.awt.Rectangle; import java.awt.geom.GeneralPath; +import java.awt.geom.Rectangle2D; import java.net.URL; import java.util.Enumeration; import java.util.Map; @@ -38,7 +38,7 @@ public class TestPresetGeometries { for(String name : shapes.keySet()) { CustomGeometry geom = shapes.get(name); - Context ctx = new Context(geom, new Rectangle(0, 0, 100, 100), new IAdjustableShape() { + Context ctx = new Context(geom, new Rectangle2D.Double(0, 0, 100, 100), new IAdjustableShape() { public Guide getAdjustValue(String presetName) { return null; } diff --git a/test-data/slideshow/table_test.ppt b/test-data/slideshow/table_test.ppt new file mode 100644 index 0000000000000000000000000000000000000000..d1c688a3ac6f7c221e724a832518ab6c836a5f59 GIT binary patch literal 122368 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 jr6vw)i4MB9Xn}gdfZ7Y{iZ04J{0s{XJRB&1O literal 0 HcmV?d00001 diff --git a/test-data/slideshow/table_test.pptx b/test-data/slideshow/table_test.pptx new file mode 100644 index 0000000000000000000000000000000000000000..451a6dce78b982a0e12cf51d35c49590ef3c0baa GIT binary patch literal 28935 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 literal 0 HcmV?d00001