From: Yegor Kozlov Date: Fri, 17 Oct 2008 15:14:00 +0000 (+0000) Subject: more progress on SpreadsheetML drawing layer;finished XSSFPicture, auto-sizing is... X-Git-Tag: ooxml_20081107~28 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f160dd1e7b90daf2e0daaced94cd087cea1e0f43;p=poi.git more progress on SpreadsheetML drawing layer;finished XSSFPicture, auto-sizing is supported; implemented initial support for shape groups. Common HSSF-XSSF drawing interfaces are still TODO. git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@705638 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPictures.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPictures.java new file mode 100755 index 0000000000..b4c018d9ac --- /dev/null +++ b/src/examples/src/org/apache/poi/xssf/usermodel/examples/WorkingWithPictures.java @@ -0,0 +1,60 @@ +/* ==================================================================== + 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.xssf.usermodel.examples; + +import org.apache.poi.xssf.usermodel.*; + +import java.io.IOException; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; + +/** + * Demonstrates how to insert pictures in a SpreadsheetML document + * + * @author Yegor Kozlov + */ +public class WorkingWithPictures { + public static void main(String[] args) throws IOException { + + //create a new workbook + XSSFWorkbook wb = new XSSFWorkbook(); + + //add a picture in this workbook. + InputStream is = new FileInputStream("lilies.jpg"); + int pictureIdx = wb.addPicture(is, XSSFWorkbook.PICTURE_TYPE_JPEG); + is.close(); + + //create sheet + XSSFSheet sheet = wb.createSheet(); + + //create drawing + XSSFDrawing drawing = sheet.createDrawingPatriarch(); + + //add a picture shape + XSSFPicture pict = drawing.createPicture(new XSSFClientAnchor(), pictureIdx); + + //auto-size picture + pict.resize(); + + //save workbook + FileOutputStream fileOut = new FileOutputStream("xssf-picture.xlsx"); + wb.write(fileOut); + fileOut.close(); + + } +} diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Row.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Row.java index bbed1cfdbb..99cd0320ea 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Row.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Row.java @@ -176,11 +176,6 @@ public interface Row extends Iterable { */ Iterator iterator(); - int compareTo(Object obj); - - boolean equals(Object obj); - - /** * Used to specify the different possible policies * if for the case of null and blank cells diff --git a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java index ce4f92ceb5..d5ad5bddad 100644 --- a/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java +++ b/src/ooxml/interfaces-jdk15/org/apache/poi/ss/usermodel/Sheet.java @@ -98,32 +98,6 @@ public interface Sheet extends Iterable { int getLastRowNum(); - - - /** - * @deprecated (Sep 2008) use {@link #setColumnHidden(int, boolean)} - */ - void setColumnHidden(short columnIndex, boolean hidden); - /** - * @deprecated (Sep 2008) use {@link #isColumnHidden(int)} - */ - boolean isColumnHidden(short columnIndex); - - /** - * @deprecated (Sep 2008) use {@link #setColumnWidth(int, int)} - */ - void setColumnWidth(short columnIndex, short width); - - /** - * @deprecated (Sep 2008) use {@link #getColumnWidth(int)} - */ - short getColumnWidth(short columnIndex); - - /** - * @deprecated (Sep 2008) use {@link #setDefaultColumnWidth(int)} - */ - void setDefaultColumnWidth(short width); - /** * Get the visibility state for a given column. * @param columnIndex - the column to get (0-based) diff --git a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java index e809a7729d..faf7e7c07e 100755 --- a/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java +++ b/src/ooxml/java/org/apache/poi/POIXMLDocumentPart.java @@ -110,7 +110,7 @@ public class POIXMLDocumentPart { /** * Save the content in the underlying package part. - * Default implemenation is empty meaning that the package part is left unmodified. + * Default implementation is empty meaning that the package part is left unmodified. * * Sub-classes should override and add logic to marshal the "model" into Ooxml4J. * @@ -122,6 +122,7 @@ public class POIXMLDocumentPart { * XmlObject bean = getXmlBean(); //the "model" which holds changes in memory * bean.save(out, DEFAULT_XML_OPTIONS); * out.close(); + * } * * */ diff --git a/src/ooxml/java/org/apache/poi/POIXMLFactory.java b/src/ooxml/java/org/apache/poi/POIXMLFactory.java index 4b922dd146..6341b20842 100755 --- a/src/ooxml/java/org/apache/poi/POIXMLFactory.java +++ b/src/ooxml/java/org/apache/poi/POIXMLFactory.java @@ -41,7 +41,7 @@ public abstract class POIXMLFactory { * Create a new POIXMLDocumentPart using the supplied descriptor. This method is used when adding new parts * to a document, for example, when adding a sheet to a workbook, slide to a presentation, etc. * - * @param descriptor described the object to create + * @param descriptor describes the object to create * @return A new instance of a POIXMLDocumentPart. */ public abstract POIXMLDocumentPart newDocumentPart(POIXMLRelation descriptor); diff --git a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java index 15c09c80a9..f59a8bc308 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/CommentsTable.java @@ -34,7 +34,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CommentsDocument; import org.openxml4j.opc.PackagePart; import org.openxml4j.opc.PackageRelationship; -public class CommentsTable extends POIXMLDocumentPart implements CommentsSource, XSSFModel { +public class CommentsTable extends POIXMLDocumentPart implements CommentsSource { private CTComments comments; public CommentsTable(InputStream is) throws IOException { diff --git a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java index e854d19d02..cbf2811676 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/SharedStringsTable.java @@ -60,7 +60,7 @@ import org.openxml4j.opc.PackageRelationship; * @author Nick Birch * @author Yegor Kozlov */ -public class SharedStringsTable extends POIXMLDocumentPart implements XSSFModel, SharedStringSource { +public class SharedStringsTable extends POIXMLDocumentPart implements SharedStringSource { /** * Array of individual string items in the Shared String table. diff --git a/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java b/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java index 568d56c157..1e7fdd888f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/StylesTable.java @@ -64,15 +64,15 @@ import org.openxml4j.opc.PackageRelationship; * * @author ugo */ -public class StylesTable extends POIXMLDocumentPart implements StylesSource, XSSFModel { +public class StylesTable extends POIXMLDocumentPart implements StylesSource { private final Hashtable numberFormats = new Hashtable(); private final List fonts = new ArrayList(); private final List fills = new ArrayList(); private final List borders = new ArrayList(); - private final List styleXfs = new LinkedList(); - private final List xfs = new LinkedList(); + private final List styleXfs = new ArrayList(); + private final List xfs = new ArrayList(); - private final List dxfs = new LinkedList(); + private final List dxfs = new ArrayList(); /** * The first style id available for use as a custom style diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFAnchor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFAnchor.java new file mode 100755 index 0000000000..89f4fb8869 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFAnchor.java @@ -0,0 +1,27 @@ +/* ==================================================================== + 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.xssf.usermodel; + +/** + * An anchor is what specifics the position of a shape within a client object + * or within another containing shape. + * + * @author Yegor Kozlov + */ +public abstract class XSSFAnchor { + +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChildAnchor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChildAnchor.java new file mode 100755 index 0000000000..d02ee82d02 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChildAnchor.java @@ -0,0 +1,81 @@ +/* ==================================================================== + 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.xssf.usermodel; + +import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D; + +/** + * @author Yegor Kozlov + */ +public class XSSFChildAnchor extends XSSFAnchor { + private CTTransform2D t2d; + + public XSSFChildAnchor(int x, int y, int cx, int cy) { + t2d = CTTransform2D.Factory.newInstance(); + CTPoint2D off = t2d.addNewOff(); + CTPositiveSize2D ext = t2d.addNewExt(); + + off.setX(x); + off.setY(y); + ext.setCx(Math.abs(cx - x)); + ext.setCy(Math.abs(cy - y)); + if(x > cx) t2d.setFlipH(true); + if(y > cy) t2d.setFlipV(true); + } + + public XSSFChildAnchor(CTTransform2D t2d) { + this.t2d = t2d; + } + + public CTTransform2D getCTTransform2D() { + return t2d; + } + + public int getDx1() { + return (int)t2d.getOff().getX(); + } + + public void setDx1(int dx1) { + t2d.getOff().setX(dx1); + } + + public int getDy1() { + return (int)t2d.getOff().getY(); + } + + public void setDy1(int dy1) { + t2d.getOff().setY(dy1); + } + + public int getDy2() { + return (int)(getDy1() + t2d.getExt().getCy()); + } + + public void setDy2(int dy2) { + t2d.getExt().setCy(dy2 - getDy1()); + } + + public int getDx2() { + return (int)(getDx1() + t2d.getExt().getCx()); + } + + public void setDx2(int dx2) { + t2d.getExt().setCx(dx2 - getDx1()); + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java index 0a6129e432..9e6bd26277 100755 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFClientAnchor.java @@ -20,11 +20,11 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; /** * A client anchor is attached to an excel worksheet. It anchors against - * top-left and buttom-right cells. + * top-left and bottom-right cells. * * @author Yegor Kozlov */ -public class XSSFClientAnchor { +public class XSSFClientAnchor extends XSSFAnchor { /** * Starting anchor point @@ -92,7 +92,7 @@ public class XSSFClientAnchor { return cell1.getCol(); } - public void setCol1(short col1) { + public void setCol1(int col1) { cell1.setCol(col1); } @@ -100,7 +100,7 @@ public class XSSFClientAnchor { return cell2.getCol(); } - public void setCol2(short col2) { + public void setCol2(int col2) { cell2.setCol(col2); } @@ -176,6 +176,10 @@ public class XSSFClientAnchor { return cell1; } + protected void setFrom(CTMarker from){ + cell1 = from; + } + /** * Return ending anchor point * @@ -184,4 +188,8 @@ public class XSSFClientAnchor { public CTMarker getTo(){ return cell2; } + + protected void setTo(CTMarker to){ + cell2 = to; + } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConnector.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConnector.java new file mode 100755 index 0000000000..2127263ea9 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFConnector.java @@ -0,0 +1,121 @@ +/* ==================================================================== + 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.xssf.usermodel; + +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*; +import org.openxmlformats.schemas.drawingml.x2006.main.*; + +/** + * A connection shape drawing element. A connection shape is a line, etc. + * that connects two other shapes in this drawing. + * + * @author Yegor Kozlov + */ +public class XSSFConnector extends XSSFShape { + + private static CTConnector prototype = null; + + private CTConnector ctShape; + + /** + * Construct a new XSSFConnector object. + * + * @param drawing the XSSFDrawing that owns this shape + * @param ctShape the shape bean that holds all the shape properties + */ + protected XSSFConnector(XSSFDrawing drawing, CTConnector ctShape) { + this.drawing = drawing; + this.ctShape = ctShape; + } + + /** + * Initialize default structure of a new auto-shape + * + */ + protected static CTConnector prototype() { + if(prototype == null) { + CTConnector shape = CTConnector.Factory.newInstance(); + CTConnectorNonVisual nv = shape.addNewNvCxnSpPr(); + CTNonVisualDrawingProps nvp = nv.addNewCNvPr(); + nvp.setId(1); + nvp.setName("Shape 1"); + nv.addNewCNvCxnSpPr(); + + CTShapeProperties sp = shape.addNewSpPr(); + CTTransform2D t2d = sp.addNewXfrm(); + CTPositiveSize2D p1 = t2d.addNewExt(); + p1.setCx(0); + p1.setCy(0); + CTPoint2D p2 = t2d.addNewOff(); + p2.setX(0); + p2.setY(0); + + CTPresetGeometry2D geom = sp.addNewPrstGeom(); + geom.setPrst(STShapeType.LINE); + geom.addNewAvLst(); + + CTShapeStyle style = shape.addNewStyle(); + CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr(); + scheme.setVal(STSchemeColorVal.ACCENT_1); + style.getLnRef().setIdx(1); + + CTStyleMatrixReference fillref = style.addNewFillRef(); + fillref.setIdx(0); + fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1); + + CTStyleMatrixReference effectRef = style.addNewEffectRef(); + effectRef.setIdx(0); + effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1); + + CTFontReference fontRef = style.addNewFontRef(); + fontRef.setIdx(STFontCollectionIndex.MINOR); + fontRef.addNewSchemeClr().setVal(STSchemeColorVal.TX_1); + + prototype = shape; + } + return prototype; + } + + public CTConnector getCTConnector(){ + return ctShape; + } + + /** + * Gets the shape type, one of the constants defined in {@link org.apache.poi.xssf.usermodel.ShapeTypes}. + * + * @return the shape type + * @see org.apache.poi.xssf.usermodel.ShapeTypes + */ + public int getShapeType() { + return ctShape.getSpPr().getPrstGeom().getPrst().intValue(); + } + + /** + * Sets the shape types. + * + * @param type the shape type, one of the constants defined in {@link org.apache.poi.xssf.usermodel.ShapeTypes}. + * @see org.apache.poi.xssf.usermodel.ShapeTypes + */ + public void setShapeType(int type) { + ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type)); + } + + protected CTShapeProperties getShapeProperties(){ + return ctShape.getSpPr(); + } + +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java index 1172612eb0..82f6ec0fcb 100755 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java @@ -19,10 +19,9 @@ package org.apache.poi.xssf.usermodel; import org.apache.poi.POIXMLDocumentPart; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; +import org.apache.xmlbeans.XmlObject; import org.openxml4j.opc.*; -import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing; -import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor; -import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.STEditAs; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; import javax.xml.namespace.QName; @@ -30,6 +29,8 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Map; import java.util.HashMap; +import java.util.List; +import java.util.LinkedList; /** * Represents a SpreadsheetML drawing @@ -105,6 +106,23 @@ public class XSSFDrawing extends POIXMLDocumentPart { out.close(); } + /** + * Constructs a textbox under the drawing. + * + * @param anchor the client anchor describes how this group is attached + * to the sheet. + * @return the newly created textbox. + */ + public XSSFTextBox createTextbox(XSSFClientAnchor anchor){ + CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor); + CTShape ctShape = ctAnchor.addNewSp(); + ctShape.set(XSSFSimpleShape.prototype()); + XSSFTextBox shape = new XSSFTextBox(this, ctShape); + shape.anchor = anchor; + return shape; + + } + /** * Creates a picture. * @@ -116,13 +134,32 @@ public class XSSFDrawing extends POIXMLDocumentPart { */ public XSSFPicture createPicture(XSSFClientAnchor anchor, int pictureIndex) { + PackageRelationship rel = addPictureReference(pictureIndex); + + CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor); + ctAnchor.setEditAs(STEditAs.ONE_CELL); + CTPicture ctShape = ctAnchor.addNewPic(); + ctShape.set(XSSFPicture.prototype()); + + XSSFPicture shape = new XSSFPicture(this, ctShape); + shape.anchor = anchor; + shape.setPictureReference(rel); + return shape; + } + + /** + * Add the indexed picture to this drawing relations + * + * @param pictureIndex the index of the picture in the workbook collection of pictures, + * {@link org.apache.poi.xssf.usermodel.XSSFWorkbook#getAllPictures()} . + */ + protected PackageRelationship addPictureReference(int pictureIndex){ XSSFWorkbook wb = (XSSFWorkbook)getParent().getParent(); XSSFPictureData data = wb.getAllPictures().get(pictureIndex); PackagePartName ppName = data.getPackagePart().getPartName(); PackageRelationship rel = packagePart.addRelationship(ppName, TargetMode.INTERNAL, XSSFRelation.IMAGES.getRelation()); addRelation(new XSSFPictureData(data.getPackagePart(), rel)); - CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor); - return new XSSFPicture(this, rel, ctAnchor); + return rel; } /** @@ -136,7 +173,49 @@ public class XSSFDrawing extends POIXMLDocumentPart { public XSSFSimpleShape createSimpleShape(XSSFClientAnchor anchor) { CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor); - return new XSSFSimpleShape(this, ctAnchor); + CTShape ctShape = ctAnchor.addNewSp(); + ctShape.set(XSSFSimpleShape.prototype()); + XSSFSimpleShape shape = new XSSFSimpleShape(this, ctShape); + shape.anchor = anchor; + return shape; + } + + /** + * Creates a simple shape. This includes such shapes as lines, rectangles, + * and ovals. + * + * @param anchor the client anchor describes how this group is attached + * to the sheet. + * @return the newly created shape. + */ + public XSSFConnector createConnector(XSSFClientAnchor anchor) + { + CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor); + CTConnector ctShape = ctAnchor.addNewCxnSp(); + ctShape.set(XSSFConnector.prototype()); + + XSSFConnector shape = new XSSFConnector(this, ctShape); + shape.anchor = anchor; + return shape; + } + + /** + * Creates a simple shape. This includes such shapes as lines, rectangles, + * and ovals. + * + * @param anchor the client anchor describes how this group is attached + * to the sheet. + * @return the newly created shape. + */ + public XSSFShapeGroup createGroup(XSSFClientAnchor anchor) + { + CTTwoCellAnchor ctAnchor = createTwoCellAnchor(anchor); + CTGroupShape ctGroup = ctAnchor.addNewGrpSp(); + ctGroup.set(XSSFShapeGroup.prototype()); + + XSSFShapeGroup shape = new XSSFShapeGroup(this, ctGroup); + shape.anchor = anchor; + return shape; } /** @@ -144,12 +223,13 @@ public class XSSFDrawing extends POIXMLDocumentPart { * * @return a new CTTwoCellAnchor */ - private CTTwoCellAnchor createTwoCellAnchor(XSSFClientAnchor anchor){ + private CTTwoCellAnchor createTwoCellAnchor(XSSFClientAnchor anchor) { CTTwoCellAnchor ctAnchor = drawing.addNewTwoCellAnchor(); - ctAnchor.setEditAs(STEditAs.ONE_CELL); ctAnchor.setFrom(anchor.getFrom()); ctAnchor.setTo(anchor.getTo()); ctAnchor.addNewClientData(); + anchor.setTo(ctAnchor.getTo()); + anchor.setFrom(ctAnchor.getFrom()); return ctAnchor; } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java index 93a7caa6e6..293aeaaee2 100755 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFPicture.java @@ -43,18 +43,15 @@ public class XSSFPicture extends XSSFShape { private static final POILogger logger = POILogFactory.getLogger(XSSFPicture.class); /** - * width of 1px in columns with default width + * A default instance of CTShape used for creating new shapes. */ - private static final float PX_DEFAULT = 0.125f; - /** - * width of 1px in columns with overridden width - */ - private static final float PX_MODIFIED = 0.143f; + private static CTPicture prototype = null; /** - * Height of 1px of a row + * Width of one character in pixels. Same for Calibry and Arial. */ - private static final int PX_ROW = 15; + private static final float CHARACTER_WIDTH = 7.0017f; + /** * This object specifies a picture object and all its properties @@ -65,56 +62,60 @@ public class XSSFPicture extends XSSFShape { * Construct a new XSSFPicture object. This constructor is called from * {@link XSSFDrawing#createPicture(XSSFClientAnchor, int)} * - * @param parent the XSSFDrawing that owns this picture - * @param rel the relationship to the picture data - * @param anchor the two cell anchor placeholder for this picture, - * this object encloses the CTPicture bean that holds all the picture properties + * @param drawing the XSSFDrawing that owns this picture + */ + protected XSSFPicture(XSSFDrawing drawing, CTPicture ctPicture){ + this.drawing = drawing; + this.ctPicture = ctPicture; + } + + /** + * Returns a prototype that is used to construct new shapes + * + * @return a prototype that is used to construct new shapes */ - protected XSSFPicture(XSSFDrawing parent, PackageRelationship rel, CTTwoCellAnchor anchor){ - super(parent, anchor); - //Create a new picture and attach it to the specified two-cell anchor - ctPicture = newPicture(rel); - anchor.setPic(ctPicture); + protected static CTPicture prototype(){ + if(prototype == null) { + CTPicture pic = CTPicture.Factory.newInstance(); + CTPictureNonVisual nvpr = pic.addNewNvPicPr(); + CTNonVisualDrawingProps nvProps = nvpr.addNewCNvPr(); + nvProps.setId(1); + nvProps.setName("Picture 1"); + nvProps.setDescr("Picture"); + CTNonVisualPictureProperties nvPicProps = nvpr.addNewCNvPicPr(); + nvPicProps.addNewPicLocks().setNoChangeAspect(true); + + CTBlipFillProperties blip = pic.addNewBlipFill(); + blip.addNewBlip().setEmbed(""); + blip.addNewStretch().addNewFillRect(); + + CTShapeProperties sppr = pic.addNewSpPr(); + CTTransform2D t2d = sppr.addNewXfrm(); + CTPositiveSize2D ext = t2d.addNewExt(); + //should be original picture width and height expressed in EMUs + ext.setCx(0); + ext.setCy(0); + + CTPoint2D off = t2d.addNewOff(); + off.setX(0); + off.setY(0); + + CTPresetGeometry2D prstGeom = sppr.addNewPrstGeom(); + prstGeom.setPrst(STShapeType.RECT); + prstGeom.addNewAvLst(); + + prototype = pic; + } + return prototype; } /** - * Create a new CTPicture bean and initialize its required attributes + * Link this shape with the picture data * - * @param rel the relationship to the picture data - * @return a new CTPicture bean + * @param rel relationship referring the picture data */ - private static CTPicture newPicture(PackageRelationship rel){ - CTPicture pic = CTPicture.Factory.newInstance(); - - CTPictureNonVisual nvpr = pic.addNewNvPicPr(); - CTNonVisualDrawingProps nvProps = nvpr.addNewCNvPr(); - //YK: TODO shape IDs must be unique across workbook - int shapeId = 1; - nvProps.setId(shapeId); - nvProps.setName("Picture " + shapeId); - nvProps.setDescr(rel.getTargetURI().toString()); - CTNonVisualPictureProperties nvPicProps = nvpr.addNewCNvPicPr(); - nvPicProps.addNewPicLocks().setNoChangeAspect(true); - - CTBlipFillProperties blip = pic.addNewBlipFill(); - blip.addNewBlip().setEmbed(rel.getId()); - blip.addNewStretch().addNewFillRect(); - - CTShapeProperties sppr = pic.addNewSpPr(); - CTTransform2D t2d = sppr.addNewXfrm(); - CTPositiveSize2D ext = t2d.addNewExt(); - //should be original picture width and height expressed in EMUs - ext.setCx(0); - ext.setCy(0); - - CTPoint2D off = t2d.addNewOff(); - off.setX(0); - off.setY(0); - - CTPresetGeometry2D prstGeom = sppr.addNewPrstGeom(); - prstGeom.setPrst(STShapeType.RECT); - prstGeom.addNewAvLst(); - return pic; + protected void setPictureReference(PackageRelationship rel){ + ctPicture.getBlipFill().getBlip().setEmbed(rel.getId()); } /** @@ -130,7 +131,7 @@ public class XSSFPicture extends XSSFShape { * Reset the image to the original size. */ public void resize(){ - XSSFClientAnchor anchor = getAnchor(); + XSSFClientAnchor anchor = (XSSFClientAnchor)getAnchor(); XSSFClientAnchor pref = getPreferredSize(); @@ -152,78 +153,76 @@ public class XSSFPicture extends XSSFShape { * @return XSSFClientAnchor with the preferred size for this image */ public XSSFClientAnchor getPreferredSize(){ - XSSFClientAnchor anchor = getAnchor(); + XSSFClientAnchor anchor = (XSSFClientAnchor)getAnchor(); XSSFPictureData data = getPictureData(); Dimension size = getImageDimension(data.getPackagePart(), data.getPictureType()); float w = 0; - - //space in the leftmost cell - w += anchor.getDx1()/EMU_PER_POINT; - short col2 = (short)(anchor.getCol1() + 1); + int col2 = anchor.getCol1(); int dx2 = 0; + if(anchor.getDx1() > 0){ + w += getColumnWidthInPixels(col2) - anchor.getDx1(); + col2++; + } - while(w < size.width){ - w += getColumnWidthInPixels(col2++); + for (;;) { + w += getColumnWidthInPixels(col2); + if(w > size.width) break; + col2++; } if(w > size.width) { - //calculate dx2, offset in the rightmost cell - col2--; - float cw = getColumnWidthInPixels(col2); + float cw = getColumnWidthInPixels(col2 + 1); float delta = w - size.width; - dx2 = (int)(EMU_PER_POINT*(cw-delta)); + dx2 = (int)(EMU_PER_PIXEL*(cw-delta)); } anchor.setCol2(col2); anchor.setDx2(dx2); float h = 0; - h += (1 - anchor.getDy1()/256)* getRowHeightInPixels(anchor.getRow1()); - int row2 = anchor.getRow1() + 1; + int row2 = anchor.getRow1(); int dy2 = 0; - while(h < size.height){ - h += getRowHeightInPixels(row2++); + if(anchor.getDy1() > 0){ + h += getRowHeightInPixels(row2) - anchor.getDy1(); + row2++; } + + for (;;) { + h += getRowHeightInPixels(row2); + if(h > size.height) break; + row2++; + } + if(h > size.height) { - row2--; - float ch = getRowHeightInPixels(row2); + float ch = getRowHeightInPixels(row2 + 1); float delta = h - size.height; - dy2 = (int)((ch-delta)/ch*256); + dy2 = (int)(EMU_PER_PIXEL*(ch-delta)); } anchor.setRow2(row2); anchor.setDy2(dy2); - return anchor; - } - - private float getColumnWidthInPixels(int column){ - XSSFSheet sheet = (XSSFSheet)getDrawing().getParent(); - int cw = sheet.getColumnWidth(column); - float px = getPixelWidth(column); + CTPositiveSize2D size2d = ctPicture.getSpPr().getXfrm().getExt(); + size2d.setCx(size.width*EMU_PER_PIXEL); + size2d.setCy(size.height*EMU_PER_PIXEL); - return cw/px; + return anchor; } - private float getRowHeightInPixels(int i){ + private float getColumnWidthInPixels(int columnIndex){ XSSFSheet sheet = (XSSFSheet)getDrawing().getParent(); + float numChars = (float)sheet.getColumnWidth(columnIndex)/256; - XSSFRow row = sheet.getRow(i); - float height; - if(row != null) height = row.getHeight(); - else height = sheet.getDefaultRowHeight(); - - return height/PX_ROW; + return numChars*CHARACTER_WIDTH; } - private float getPixelWidth(int column){ + private float getRowHeightInPixels(int rowIndex){ XSSFSheet sheet = (XSSFSheet)getDrawing().getParent(); - int def = sheet.getDefaultColumnWidth(); - int cw = sheet.getColumnWidth(column); - - return cw == def ? PX_DEFAULT : PX_MODIFIED; + XSSFRow row = sheet.getRow(rowIndex); + float height = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints(); + return height*PIXEL_DPI/POINT_DPI; } /** @@ -238,7 +237,7 @@ public class XSSFPicture extends XSSFShape { Dimension size = new Dimension(); switch (type){ - //we can calculate the preferred size only for JPEG and PNG + //we can calculate the preferred size only for JPEG, PNG and BMP //other formats like WMF, EMF and PICT are not supported in Java case Workbook.PICTURE_TYPE_JPEG: case Workbook.PICTURE_TYPE_PNG: @@ -255,11 +254,11 @@ public class XSSFPicture extends XSSFShape { //if DPI is zero then assume standard 96 DPI //since cannot divide by zero - if (dpi[0] == 0) dpi[0] = 96; - if (dpi[1] == 0) dpi[1] = 96; + if (dpi[0] == 0) dpi[0] = PIXEL_DPI; + if (dpi[1] == 0) dpi[1] = PIXEL_DPI; - size.width = img.getWidth()*96/dpi[0]; - size.height = img.getHeight()*96/dpi[1]; + size.width = img.getWidth()*PIXEL_DPI/dpi[0]; + size.height = img.getHeight()*PIXEL_DPI/dpi[1]; } catch (IOException e){ //silently return if ImageIO failed to read the image @@ -282,7 +281,7 @@ public class XSSFPicture extends XSSFShape { * {96, 96} is the default. */ protected static int[] getResolution(ImageReader r) throws IOException { - int hdpi=96, vdpi=96; + int hdpi = PIXEL_DPI, vdpi = PIXEL_DPI; double mm2inch = 25.4; NodeList lst; @@ -296,16 +295,6 @@ public class XSSFPicture extends XSSFShape { return new int[]{hdpi, vdpi}; } - /** - * return the anchor that is used by this shape. - * - * @return the anchor that is used by this shape. - */ - public XSSFClientAnchor getAnchor(){ - CTTwoCellAnchor ctAnchor = (CTTwoCellAnchor)getShapeContainer(); - return new XSSFClientAnchor(ctAnchor.getFrom(), ctAnchor.getTo()); - } - /** * Return picture data for this shape * @@ -322,4 +311,8 @@ public class XSSFPicture extends XSSFShape { return null; } + protected CTShapeProperties getShapeProperties(){ + return ctPicture.getSpPr(); + } + } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRichTextString.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRichTextString.java index 799479dc98..8d1a585730 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRichTextString.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRichTextString.java @@ -108,7 +108,7 @@ public class XSSFRichTextString implements RichTextString { font.setFontName("#" + fontIndex); fontIdRuns = new ArrayList(); } else { - font = (XSSFFont)styles.getFontAt(fontIndex); + font = styles.getFontAt(fontIndex); } applyFont(startIndex, endIndex, font); } @@ -219,7 +219,7 @@ public class XSSFRichTextString implements RichTextString { font.setFontName("#" + fontIndex); fontIdRuns = new ArrayList(); } else { - font = (XSSFFont)styles.getFontAt(fontIndex); + font = styles.getFontAt(fontIndex); } applyFont(font); } @@ -425,7 +425,7 @@ public class XSSFRichTextString implements RichTextString { String fontName = pr.getRFontArray(0).getVal(); if(fontName.startsWith("#")){ int idx = Integer.parseInt(fontName.substring(1)); - XSSFFont font = (XSSFFont)styles.getFontAt(idx); + XSSFFont font = styles.getFontAt(idx); pr.removeRFont(0); setRunAttributes(font.getCTFont(), pr); } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java index 5c90429dd2..e65224e72f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRow.java @@ -28,7 +28,7 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow; -public class XSSFRow implements Row { +public class XSSFRow implements Row, Comparable { private CTRow row; @@ -76,8 +76,20 @@ public class XSSFRow implements Row { } public int compareTo(Object obj) { - // TODO Auto-generated method stub - return 0; + XSSFRow loc = (XSSFRow) obj; + if (this.getRowNum() == loc.getRowNum()) + { + return 0; + } + if (this.getRowNum() < loc.getRowNum()) + { + return -1; + } + if (this.getRowNum() > loc.getRowNum()) + { + return 1; + } + return -1; } public XSSFCell createCell(int column) { @@ -184,18 +196,29 @@ public class XSSFRow implements Row { return -1; } + /** + * Get the row's height measured in twips (1/20th of a point). If the height is not set, the default worksheet value is returned, + * See {@link org.apache.poi.xssf.usermodel.XSSFSheet#getDefaultRowHeightInPoints()} + * + * @return row height measured in twips (1/20th of a point) + */ public short getHeight() { - if (this.row.getHt() > 0) { - return (short) (this.row.getHt()); - } - return -1; + return (short)(getHeightInPoints()*20); } + /** + * Returns row height measured in point size. If the height is not set, the default worksheet value is returned, + * See {@link org.apache.poi.xssf.usermodel.XSSFSheet#getDefaultRowHeightInPoints()} + * + * @return row height measured in point size + * @see org.apache.poi.xssf.usermodel.XSSFSheet#getDefaultRowHeightInPoints() + */ public float getHeightInPoints() { - if (this.row.getHt() > 0) { - return (short) this.row.getHt(); - } - return -1; + if (this.row.isSetHt()) { + return (float) this.row.getHt(); + } else { + return sheet.getDefaultRowHeightInPoints(); + } } /** @@ -259,18 +282,28 @@ public class XSSFRow implements Row { } } + /** + * Set the height in "twips" or 1/20th of a point. + * + * @param height the height in "twips" or 1/20th of a point. -1 resets to the default height + */ public void setHeight(short height) { - this.row.setHt((double) height); - this.row.setCustomHeight(true); - } + if(height == -1){ + this.row.unsetHt(); + this.row.unsetCustomHeight(); + } else { + this.row.setHt((double)height/20); + this.row.setCustomHeight(true); - public void setHeight(double height) { - this.row.setHt((double) height); - this.row.setCustomHeight(true); + } } - + /** + * Set the row's height in points. + * + * @param height the height in points. -1 resets to the default height + */ public void setHeightInPoints(float height) { - setHeight((short)height); + setHeight((short)(height*20)); } public void setRowNum(int rowNum) { diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java index 861c96b525..ad6c27271b 100755 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShape.java @@ -21,73 +21,135 @@ import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAn import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTAbsoluteAnchor; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTOneCellAnchor; import org.openxmlformats.schemas.drawingml.x2006.chartDrawing.CTGroupShape; +import org.openxmlformats.schemas.drawingml.x2006.main.*; /** * Represents a shape in a SpreadsheetML drawing. - * + * * @author Yegor Kozlov */ public abstract class XSSFShape { + public static final int EMU_PER_PIXEL = 9525; public static final int EMU_PER_POINT = 12700; + public static final int POINT_DPI = 72; + public static final int PIXEL_DPI = 96; /** - * Shape container. Can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape + * Parent drawing */ - private XmlObject spContainer; + protected XSSFDrawing drawing; /** - * Parent drawing + * The parent shape, always not-null for shapes in groups */ - private XSSFDrawing drawing; + protected XSSFShapeGroup parent; /** - * The parent shape, always not-null for shapes in groups + * anchor that is used by this shape + */ + protected XSSFAnchor anchor; + + /** + * Return the drawing that owns this shape + * + * @return the parent drawing that owns this shape + */ + public XSSFDrawing getDrawing(){ + return drawing; + } + + /** + * Gets the parent shape. + */ + public XSSFShapeGroup getParent() + { + return parent; + } + + /** + * @return the anchor that is used by this shape. */ - private XSSFShape parent; + public XSSFAnchor getAnchor() + { + return anchor; + } + + /** + * Returns xml bean with shape properties. + * + * @return xml bean with shape properties. + */ + protected abstract CTShapeProperties getShapeProperties(); /** - * Construct a new XSSFSimpleShape object. + * Whether this shape is not filled with a color * - * @param parent the XSSFDrawing that owns this shape - * @param anchor an object that encloses the shape bean, - * can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape + * @return true if this shape is not filled with a color. */ - protected XSSFShape(XSSFDrawing parent, XmlObject anchor){ - drawing = parent; - if(!(anchor instanceof CTTwoCellAnchor) && !(anchor instanceof CTOneCellAnchor) && - !(anchor instanceof CTAbsoluteAnchor) && !(anchor instanceof CTGroupShape)) { - throw new IllegalArgumentException("anchor must be one of the following types: " + - "CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape"); - } - spContainer = anchor; + public boolean isNoFill() { + return getShapeProperties().isSetNoFill(); } /** - * Return the anchor bean that encloses this shape. - * Can be CTTwoCellAnchor, CTOneCellAnchor, CTAbsoluteAnchor or CTGroupShape. + * Sets whether this shape is filled or transparent. * - * @return the anchor bean that encloses this shape + * @param noFill if true then no fill will be applied to the shape element. */ - public XmlObject getShapeContainer(){ - return spContainer; + public void setNoFill(boolean noFill) { + CTShapeProperties props = getShapeProperties(); + //unset solid and pattern fills if they are set + if (props.isSetPattFill()) props.unsetPattFill(); + if (props.isSetSolidFill()) props.unsetSolidFill(); + + props.setNoFill(CTNoFillProperties.Factory.newInstance()); } /** - * Return the drawing that owns this shape + * Sets the color used to fill this shape using the solid fill pattern. + */ + public void setFillColor(int red, int green, int blue) { + CTShapeProperties props = getShapeProperties(); + CTSolidColorFillProperties fill = props.isSetSolidFill() ? props.getSolidFill() : props.addNewSolidFill(); + CTSRgbColor rgb = CTSRgbColor.Factory.newInstance(); + rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue}); + fill.setSrgbClr(rgb); + } + + /** + * The color applied to the lines of this shape. + */ + public void setLineStyleColor( int red, int green, int blue ) { + CTShapeProperties props = getShapeProperties(); + CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn(); + CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln.getSolidFill() : ln.addNewSolidFill(); + CTSRgbColor rgb = CTSRgbColor.Factory.newInstance(); + rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue}); + fill.setSrgbClr(rgb); + } + + /** + * Specifies the width to be used for the underline stroke. * - * @return the parent drawing that owns this shape + * @param lineWidth width in points */ - public XSSFDrawing getDrawing(){ - return drawing; + public void setLineWidth( double lineWidth ) { + CTShapeProperties props = getShapeProperties(); + CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn(); + ln.setW((int)(lineWidth*EMU_PER_POINT)); } /** - * Gets the parent shape. + * Sets the line style. + * + * @param lineStyle */ - public XSSFShape getParent() - { - return parent; + public void setLineStyle( int lineStyle ) { + CTShapeProperties props = getShapeProperties(); + CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn(); + CTPresetLineDashProperties dashStyle = CTPresetLineDashProperties.Factory.newInstance(); + dashStyle.setVal(STPresetLineDashVal.Enum.forInt(lineStyle+1)); + ln.setPrstDash(dashStyle); } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShapeGroup.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShapeGroup.java new file mode 100755 index 0000000000..f483393a70 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShapeGroup.java @@ -0,0 +1,189 @@ +/* ==================================================================== + 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.xssf.usermodel; + +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*; +import org.openxmlformats.schemas.drawingml.x2006.main.*; +import org.openxml4j.opc.PackagePartName; +import org.openxml4j.opc.PackageRelationship; +import org.openxml4j.opc.TargetMode; + +import java.util.List; + +/** + * This object specifies a group shape that represents many shapes grouped together. This shape is to be treated + * just as if it were a regular shape but instead of being described by a single geometry it is made up of all the + * shape geometries encompassed within it. Within a group shape each of the shapes that make up the group are + * specified just as they normally would. + * + * @author Yegor Kozlov + */ +public class XSSFShapeGroup extends XSSFShape { + private static CTGroupShape prototype = null; + + private CTGroupShape ctGroup; + + /** + * Construct a new XSSFSimpleShape object. + * + * @param drawing the XSSFDrawing that owns this shape + * @param ctGroup the XML bean that stores this group content + */ + public XSSFShapeGroup(XSSFDrawing drawing, CTGroupShape ctGroup) { + this.drawing = drawing; + this.ctGroup = ctGroup; + } + + /** + * Initialize default structure of a new shape group + */ + protected static CTGroupShape prototype() { + if (prototype == null) { + CTGroupShape shape = CTGroupShape.Factory.newInstance(); + + CTGroupShapeNonVisual nv = shape.addNewNvGrpSpPr(); + CTNonVisualDrawingProps nvpr = nv.addNewCNvPr(); + nvpr.setId(0); + nvpr.setName("Group 0"); + nv.addNewCNvGrpSpPr(); + CTGroupShapeProperties sp = shape.addNewGrpSpPr(); + CTGroupTransform2D t2d = sp.addNewXfrm(); + CTPositiveSize2D p1 = t2d.addNewExt(); + p1.setCx(0); + p1.setCy(0); + CTPoint2D p2 = t2d.addNewOff(); + p2.setX(0); + p2.setY(0); + CTPositiveSize2D p3 = t2d.addNewChExt(); + p3.setCx(0); + p3.setCy(0); + CTPoint2D p4 = t2d.addNewChOff(); + p4.setX(0); + p4.setY(0); + + prototype = shape; + } + return prototype; + } + + /** + * Constructs a textbox. + * + * @param anchor the child anchor describes how this shape is attached + * to the group. + * @return the newly created textbox. + */ + public XSSFTextBox createTextbox(XSSFChildAnchor anchor){ + CTShape ctShape = ctGroup.addNewSp(); + ctShape.set(XSSFSimpleShape.prototype()); + + XSSFTextBox shape = new XSSFTextBox(getDrawing(), ctShape); + shape.parent = this; + shape.anchor = anchor; + shape.getCTShape().getSpPr().setXfrm(anchor.getCTTransform2D()); + return shape; + + } + /** + * Creates a simple shape. This includes such shapes as lines, rectangles, + * and ovals. + * + * @param anchor the child anchor describes how this shape is attached + * to the group. + * @return the newly created shape. + */ + public XSSFSimpleShape createSimpleShape(XSSFChildAnchor anchor) { + CTShape ctShape = ctGroup.addNewSp(); + ctShape.set(XSSFSimpleShape.prototype()); + + XSSFSimpleShape shape = new XSSFSimpleShape(getDrawing(), ctShape); + shape.parent = this; + shape.anchor = anchor; + shape.getCTShape().getSpPr().setXfrm(anchor.getCTTransform2D()); + return shape; + } + + /** + * Creates a simple shape. This includes such shapes as lines, rectangles, + * and ovals. + * + * @param anchor the child anchor describes how this shape is attached + * to the group. + * @return the newly created shape. + */ + public XSSFConnector createConnector(XSSFChildAnchor anchor) { + CTConnector ctShape = ctGroup.addNewCxnSp(); + ctShape.set(XSSFConnector.prototype()); + + XSSFConnector shape = new XSSFConnector(getDrawing(), ctShape); + shape.parent = this; + shape.anchor = anchor; + shape.getCTConnector().getSpPr().setXfrm(anchor.getCTTransform2D()); + return shape; + } + + /** + * Creates a picture. + * + * @param anchor the client anchor describes how this picture is attached to the sheet. + * @param pictureIndex the index of the picture in the workbook collection of pictures, + * {@link XSSFWorkbook#getAllPictures()} . + * @return the newly created picture shape. + */ + public XSSFPicture createPicture(XSSFClientAnchor anchor, int pictureIndex) { + PackageRelationship rel = getDrawing().addPictureReference(pictureIndex); + + CTPicture ctShape = ctGroup.addNewPic(); + ctShape.set(XSSFPicture.prototype()); + + XSSFPicture shape = new XSSFPicture(getDrawing(), ctShape); + shape.parent = this; + shape.anchor = anchor; + shape.setPictureReference(rel); + return shape; + } + + public CTGroupShape getCTGroupShape() { + return ctGroup; + } + + /** + * Sets the coordinate space of this group. All children are constrained + * to these coordinates. + */ + public void setCoordinates(int x1, int y1, int x2, int y2) { + CTGroupTransform2D t2d = ctGroup.getGrpSpPr().getXfrm(); + CTPoint2D off = t2d.getOff(); + off.setX(x1); + off.setY(y1); + CTPositiveSize2D ext = t2d.getExt(); + ext.setCx(x2); + ext.setCy(y2); + + CTPoint2D chOff = t2d.getChOff(); + chOff.setX(x1); + chOff.setY(y1); + CTPositiveSize2D chExt = t2d.getChExt(); + chExt.setCx(x2); + chExt.setCy(y2); + } + + protected CTShapeProperties getShapeProperties() { + throw new IllegalStateException("Not supported for shape group"); + } + +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index 127e438510..e2632b7d17 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -60,6 +60,15 @@ import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelations public class XSSFSheet extends POIXMLDocumentPart implements Sheet { private static POILogger logger = POILogFactory.getLogger(XSSFSheet.class); + /** + * Column width measured as the number of characters of the maximum digit width of the + * numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. There are 4 pixels of margin + * padding (two on each side), plus 1 pixel padding for the gridlines. + * + * This value is the same for default font in Office 2007 (Calibry) and Office 2003 and earlier (Arial) + */ + private static float DEFAULT_COLUMN_WIDTH = 9.140625f; + protected CTSheet sheet; protected CTWorksheet worksheet; protected CTDialogsheet dialogsheet; @@ -260,7 +269,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { CTDrawing ctDrawing = worksheet.getDrawing(); if(ctDrawing == null) { //drawingNumber = #drawings.size() + 1 - int drawingNumber = getPackagePart().getPackage().getPartsByRelationshipType(XSSFRelation.DRAWINGS.getRelation()).size() + 1; + int drawingNumber = getPackagePart().getPackage().getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()).size() + 1; drawing = (XSSFDrawing)createRelationship(XSSFRelation.DRAWINGS, XSSFFactory.getInstance(), drawingNumber); String relId = drawing.getPackageRelationship().getId(); @@ -425,32 +434,62 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return worksheet.getColBreaks(); } + /** + * Get the actual column width (in units of 1/256th of a character width ) + * + *

+ * Note, the returned value is always gerater that {@link #getDefaultColumnWidth()} because the latter does not include margins. + * Actual column width measured as the number of characters of the maximum digit width of the + * numbers 0, 1, 2, ..., 9 as rendered in the normal style's font. There are 4 pixels of margin + * padding (two on each side), plus 1 pixel padding for the gridlines. + *

+ * + * @param columnIndex - the column to set (0-based) + * @return width - the width in units of 1/256th of a character width + */ public int getColumnWidth(int columnIndex) { CTCol col = columnHelper.getColumn(columnIndex, false); - return col == null ? getDefaultColumnWidth() : (int)col.getWidth(); - } - public short getColumnWidth(short column) { - return (short) getColumnWidth(column & 0xFFFF); + double width = col == null || !col.isSetWidth() ? DEFAULT_COLUMN_WIDTH : col.getWidth(); + return (int)(width*256); } + /** + * Get the default column width for the sheet (if the columns do not define their own width) in + * characters. + *

+ * Note, this value is different from {@link #getColumnWidth(int)}. The latter is always greater and includes + * 4 pixels of margin padding (two on each side), plus 1 pixel padding for the gridlines. + *

+ * @return default column width + */ public int getDefaultColumnWidth() { CTSheetFormatPr pr = getSheetTypeSheetFormatPr(); - return pr.isSetDefaultColWidth() ? (int)pr.getDefaultColWidth() : (int)pr.getBaseColWidth(); + return (int)pr.getBaseColWidth(); } + /** + * Get the default row height for the sheet (if the rows do not define their own height) in + * twips (1/20 of a point) + * + * @return default row height + */ public short getDefaultRowHeight() { return (short) (getSheetTypeSheetFormatPr().getDefaultRowHeight() * 20); } - protected CTSheetFormatPr getSheetTypeSheetFormatPr() { - if (worksheet.getSheetFormatPr() == null) { - worksheet.setSheetFormatPr(CTSheetFormatPr.Factory.newInstance()); - } - return worksheet.getSheetFormatPr(); + /** + * Get the default row height for the sheet measued in point size (if the rows do not define their own height). + * + * @return default row height in points + */ + public float getDefaultRowHeightInPoints() { + return (float)getSheetTypeSheetFormatPr().getDefaultRowHeight(); } - public float getDefaultRowHeightInPoints() { - return (short) getSheetTypeSheetFormatPr().getDefaultRowHeight(); + protected CTSheetFormatPr getSheetTypeSheetFormatPr() { + return worksheet.isSetSheetFormatPr() ? + worksheet.getSheetFormatPr() : + worksheet.addNewSheetFormatPr(); } public boolean getDialog() { @@ -589,8 +628,7 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { * when set, used on even pages. */ public Header getEvenHeader() { - return new XSSFEvenHeader(getSheetTypeHeaderFooter() -); + return new XSSFEvenHeader(getSheetTypeHeaderFooter()); } /** * Returns the first page header. Not there by @@ -931,21 +969,39 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return false; } + /** + * Get the hidden state for a given column. + * + * @param columnIndex - the column to set (0-based) + * @return hidden - false if the column is visible + */ public boolean isColumnHidden(int columnIndex) { return columnHelper.getColumn(columnIndex, false).getHidden(); } - public boolean isColumnHidden(short column) { - return isColumnHidden(column & 0xFFFF); - } + /** + * Gets the flag indicating whether this sheet should display formulas. + * + * @return true if this sheet should display formulas. + */ public boolean isDisplayFormulas() { return getSheetTypeSheetView().getShowFormulas(); } + /** + * Gets the flag indicating whether this sheet should display gridlines. + * + * @return true if this sheet should display gridlines. + */ public boolean isDisplayGridlines() { return getSheetTypeSheetView().getShowGridLines(); } + /** + * Gets the flag indicating whether this sheet should display row and column headings. + * + * @return true if this sheet should display row and column headings. + */ public boolean isDisplayRowColHeadings() { return getSheetTypeSheetView().getShowRowColHeaders(); } @@ -1098,36 +1154,57 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } - public void setColumnHidden(int columnIndex, boolean hidden) { + /** + * Get the visibility state for a given column. + * + * @param columnIndex - the column to get (0-based) + * @param hidden - the visiblity state of the column + */ + public void setColumnHidden(int columnIndex, boolean hidden) { columnHelper.setColHidden(columnIndex, hidden); - } - public void setColumnHidden(short column, boolean hidden) { - setColumnHidden(column & 0xFFFF, hidden); - } + } + /** + * Set the width (in units of 1/256th of a character width) + * + * @param columnIndex - the column to set (0-based) + * @param width - the width in units of 1/256th of a character width + */ public void setColumnWidth(int columnIndex, int width) { - columnHelper.setColWidth(columnIndex, width); - } - public void setColumnWidth(short column, short width) { - setColumnWidth(column & 0xFFFF, width & 0xFFFF); + columnHelper.setColWidth(columnIndex, (double)width/256); } public void setDefaultColumnStyle(short column, CellStyle style) { columnHelper.setColDefaultStyle(column, style); } + /** + * Specifies the number of characters of the maximum digit width of the normal style's font. + * This value does not include margin padding or extra padding for gridlines. It is only the + * number of characters. + * + * @param width the number of characters. Default value is 8. + */ public void setDefaultColumnWidth(int width) { - getSheetTypeSheetFormatPr().setDefaultColWidth(width); - } - public void setDefaultColumnWidth(short width) { - setDefaultColumnWidth(width & 0xFFFF); + getSheetTypeSheetFormatPr().setBaseColWidth(width); } + /** + * Set the default row height for the sheet (if the rows do not define their own height) in + * twips (1/20 of a point) + * + * @param height default row height in twips (1/20 of a point) + */ public void setDefaultRowHeight(short height) { - getSheetTypeSheetFormatPr().setDefaultRowHeight(height / 20); + getSheetTypeSheetFormatPr().setDefaultRowHeight((double)height / 20); } + /** + * Sets default row height measured in point size. + * + * @param height default row height measured in point size. + */ public void setDefaultRowHeightInPoints(float height) { getSheetTypeSheetFormatPr().setDefaultRowHeight(height); @@ -1142,6 +1219,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } } + /** + * Sets the flag indicating whether this sheet should display formulas. + * + * @param show true if this sheet should display formulas. + */ public void setDisplayFormulas(boolean show) { getSheetTypeSheetView().setShowFormulas(show); } @@ -1153,15 +1235,30 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return getDefaultSheetView(); } + /** + * Sets the flag indicating whether this sheet should display gridlines. + * + * @param show true if this sheet should display gridlines. + */ public void setDisplayGridlines(boolean show) { getSheetTypeSheetView().setShowGridLines(show); } + /** + * Sets the flag indicating whether this sheet should display row and column headings. + * + * @param show true if this sheet should display row and column headings. + */ public void setDisplayRowColHeadings(boolean show) { getSheetTypeSheetView().setShowRowColHeaders(show); } - public void setFitToPage(boolean b) { + /** + * Flag indicating whether the Fit to Page print option is enabled. + * + * @param b true if the Fit to Page print option is enabled. + */ + public void setFitToPage(boolean b) { getSheetTypePageSetUpPr().setFitToPage(b); } @@ -1169,6 +1266,11 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { setPrintGridlines(value); } + /** + * Center on page horizontally when printing. + * + * @param value whether to center on page horizontally when printing. + */ public void setHorizontallyCenter(boolean value) { getSheetTypePrintOptions().setHorizontalCentered(value); } @@ -1306,15 +1408,45 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { getSheetTypeSheetView().setZoomScaleSheetLayoutView(scale); } + /** + * Shifts rows between startRow and endRow n number of rows. + * If you use a negative number, it will shift rows up. + * Code ensures that rows don't wrap around. + * + * Calls shiftRows(startRow, endRow, n, false, false); + * + *

+ * Additionally shifts merged regions that are completely defined in these + * rows (ie. merged 2 cells on a row to be shifted). + * @param startRow the row to start shifting + * @param endRow the row to end shifting + * @param n the number of rows to shift + */ public void shiftRows(int startRow, int endRow, int n) { shiftRows(startRow, endRow, n, false, false); } + /** + * Shifts rows between startRow and endRow n number of rows. + * If you use a negative number, it will shift rows up. + * Code ensures that rows don't wrap around + * + *

+ * Additionally shifts merged regions that are completely defined in these + * rows (ie. merged 2 cells on a row to be shifted). + *

+ * TODO Might want to add bounds checking here + * @param startRow the row to start shifting + * @param endRow the row to end shifting + * @param n the number of rows to shift + * @param copyRowHeight whether to copy the row height during the shift + * @param resetOriginalRowHeight whether to set the original row's height to the default + */ public void shiftRows(int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) { for (Iterator it = rowIterator() ; it.hasNext() ; ) { Row row = it.next(); if (!copyRowHeight) { - row.setHeight((short)0); + row.setHeight((short)-1); } if (resetOriginalRowHeight && getDefaultRowHeight() >= 0) { row.setHeight(getDefaultRowHeight()); diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java index a564013d13..220765015d 100755 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java @@ -16,85 +16,96 @@ ==================================================================== */ package org.apache.poi.xssf.usermodel; -import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual; import org.openxmlformats.schemas.drawingml.x2006.main.*; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.*; /** - * Represents an auto-shape in a SpreadsheetML drawing. + * Represents a shape with a predefined geometry in a SpreadsheetML drawing. + * Possible shape types are defined in {@link ShapeTypes} * * @author Yegor Kozlov */ public class XSSFSimpleShape extends XSSFShape { - - private CTShape ctShape; + /** + * A default instance of CTShape used for creating new shapes. + */ + private static CTShape prototype = null; /** - * Construct a new XSSFSimpleShape object. - * - * @param parent the XSSFDrawing that owns this shape - * @param anchor the two cell anchor placeholder for this shape, - * this object encloses the shape bean that holds all the shape properties + * Xml bean that stores properties of this shape */ - protected XSSFSimpleShape(XSSFDrawing parent, CTTwoCellAnchor anchor) { - super(parent, anchor); - ctShape = anchor.addNewSp(); - newShape(ctShape); + private CTShape ctShape; + + protected XSSFSimpleShape(XSSFDrawing drawing, CTShape ctShape) { + this.drawing = drawing; + this.ctShape = ctShape; } /** - * Initialize default structure of a new auto-shape - * - * @param shape newly created shape to initialize + * Prototype with the default structure of a new auto-shape. */ - private static void newShape(CTShape shape) { - CTShapeNonVisual nv = shape.addNewNvSpPr(); - CTNonVisualDrawingProps nvp = nv.addNewCNvPr(); - int shapeId = 1; - nvp.setId(shapeId); - nvp.setName("Shape " + shapeId); - nv.addNewCNvSpPr(); - - CTShapeProperties sp = shape.addNewSpPr(); - CTTransform2D t2d = sp.addNewXfrm(); - CTPositiveSize2D p1 = t2d.addNewExt(); - p1.setCx(0); - p1.setCy(0); - CTPoint2D p2 = t2d.addNewOff(); - p2.setX(0); - p2.setY(0); - - CTPresetGeometry2D geom = sp.addNewPrstGeom(); - geom.setPrst(STShapeType.RECT); - geom.addNewAvLst(); - - CTShapeStyle style = shape.addNewStyle(); - CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr(); - scheme.setVal(STSchemeColorVal.ACCENT_1); - scheme.addNewShade().setVal(50000); - style.getLnRef().setIdx(2); - - CTStyleMatrixReference fillref = style.addNewFillRef(); - fillref.setIdx(1); - fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1); - - CTStyleMatrixReference effectRef = style.addNewEffectRef(); - effectRef.setIdx(0); - effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1); - - CTFontReference fontRef = style.addNewFontRef(); - fontRef.setIdx(STFontCollectionIndex.MINOR); - fontRef.addNewSchemeClr().setVal(STSchemeColorVal.LT_1); - - CTTextBody body = shape.addNewTxBody(); - CTTextBodyProperties bodypr = body.addNewBodyPr(); - bodypr.setAnchor(STTextAnchoringType.CTR); - bodypr.setRtlCol(false); - CTTextParagraph p = body.addNewP(); - p.addNewPPr().setAlgn(STTextAlignType.CTR); - - body.addNewLstStyle(); + protected static CTShape prototype() { + if(prototype == null) { + CTShape shape = CTShape.Factory.newInstance(); + + CTShapeNonVisual nv = shape.addNewNvSpPr(); + CTNonVisualDrawingProps nvp = nv.addNewCNvPr(); + nvp.setId(1); + nvp.setName("Shape 1"); + nv.addNewCNvSpPr(); + + CTShapeProperties sp = shape.addNewSpPr(); + CTTransform2D t2d = sp.addNewXfrm(); + CTPositiveSize2D p1 = t2d.addNewExt(); + p1.setCx(0); + p1.setCy(0); + CTPoint2D p2 = t2d.addNewOff(); + p2.setX(0); + p2.setY(0); + + CTPresetGeometry2D geom = sp.addNewPrstGeom(); + geom.setPrst(STShapeType.RECT); + geom.addNewAvLst(); + + CTShapeStyle style = shape.addNewStyle(); + CTSchemeColor scheme = style.addNewLnRef().addNewSchemeClr(); + scheme.setVal(STSchemeColorVal.ACCENT_1); + scheme.addNewShade().setVal(50000); + style.getLnRef().setIdx(2); + + CTStyleMatrixReference fillref = style.addNewFillRef(); + fillref.setIdx(1); + fillref.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1); + + CTStyleMatrixReference effectRef = style.addNewEffectRef(); + effectRef.setIdx(0); + effectRef.addNewSchemeClr().setVal(STSchemeColorVal.ACCENT_1); + + CTFontReference fontRef = style.addNewFontRef(); + fontRef.setIdx(STFontCollectionIndex.MINOR); + fontRef.addNewSchemeClr().setVal(STSchemeColorVal.LT_1); + + CTTextBody body = shape.addNewTxBody(); + CTTextBodyProperties bodypr = body.addNewBodyPr(); + bodypr.setAnchor(STTextAnchoringType.CTR); + bodypr.setRtlCol(false); + CTTextParagraph p = body.addNewP(); + p.addNewPPr().setAlgn(STTextAlignType.CTR); + CTTextCharacterProperties endPr = p.addNewEndParaRPr(); + endPr.setLang("en-US"); + endPr.setSz(1100); + + body.addNewLstStyle(); + + prototype = shape; + } + return prototype; + } + + public CTShape getCTShape(){ + return ctShape; } /** @@ -117,62 +128,52 @@ public class XSSFSimpleShape extends XSSFShape { ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type)); } - - /** - * Whether this shape is not filled with a color - * - * @return true if this shape is not filled with a color. - */ - public boolean isNoFill() { - return ctShape.getSpPr().isSetNoFill(); + protected CTShapeProperties getShapeProperties(){ + return ctShape.getSpPr(); } - /** - * Sets whether this shape is filled or transparent. - * - * @param noFill if true then no fill will be applied to the shape element. - */ - public void setNoFill(boolean noFill) { - CTShapeProperties props = ctShape.getSpPr(); - //unset solid and pattern fills if they are set - if (props.isSetPattFill()) props.unsetPattFill(); - if (props.isSetSolidFill()) props.unsetSolidFill(); + public void setText(XSSFRichTextString str){ - props.setNoFill(CTNoFillProperties.Factory.newInstance()); - } + XSSFWorkbook wb = (XSSFWorkbook)getDrawing().getParent().getParent(); + str.setStylesTableReference(wb.getStylesSource()); - /** - * Sets the color used to fill this shape using the solid fill pattern. - */ - public void setFillColor(int red, int green, int blue) { - CTShapeProperties props = ctShape.getSpPr(); - CTSolidColorFillProperties fill = props.isSetSolidFill() ? props.getSolidFill() : props.addNewSolidFill(); - CTSRgbColor rgb = CTSRgbColor.Factory.newInstance(); - rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue}); - fill.setSrgbClr(rgb); - } + CTTextParagraph p = CTTextParagraph.Factory.newInstance(); + if(str.numFormattingRuns() == 0){ + CTRegularTextRun r = p.addNewR(); + CTTextCharacterProperties rPr = r.addNewRPr(); + rPr.setLang("en-US"); + rPr.setSz(1100); + r.setT(str.getString()); + + } else { + for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) { + CTRElt lt = str.getCTRst().getRArray(i); + CTRPrElt ltPr = lt.getRPr(); + + CTRegularTextRun r = p.addNewR(); + CTTextCharacterProperties rPr = r.addNewRPr(); + rPr.setLang("en-US"); + + applyAttributes(ltPr, rPr); + + r.setT(lt.getT()); + } + } + ctShape.getTxBody().setPArray(new CTTextParagraph[]{p}); - /** - * The color applied to the lines of this shape. - */ - public void setLineStyleColor( int red, int green, int blue ) { - CTShapeProperties props = ctShape.getSpPr(); - CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn(); - CTSolidColorFillProperties fill = ln.isSetSolidFill() ? ln.getSolidFill() : ln.addNewSolidFill(); - CTSRgbColor rgb = CTSRgbColor.Factory.newInstance(); - rgb.setVal(new byte[]{(byte)red, (byte)green, (byte)blue}); - fill.setSrgbClr(rgb); } /** - * Specifies the width to be used for the underline stroke. * - * @param lineWidth width in points + * CTRPrElt --> CTFont adapter */ - public void setLineWidth( double lineWidth ) { - CTShapeProperties props = ctShape.getSpPr(); - CTLineProperties ln = props.isSetLn() ? props.getLn() : props.addNewLn(); - ln.setW((int)(lineWidth*EMU_PER_POINT)); - } + private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr){ + + if(pr.sizeOfBArray() > 0) rPr.setB(pr.getBArray(0).getVal()); + //if(pr.sizeOfUArray() > 0) rPr.setU(pr.getUArray(0).getVal()); + if(pr.sizeOfIArray() > 0) rPr.setI(pr.getIArray(0).getVal()); + CTTextFont rFont = rPr.addNewLatin(); + rFont.setTypeface(pr.sizeOfRFontArray() > 0 ? pr.getRFontArray(0).getVal() : "Arial"); + } } diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTextBox.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTextBox.java new file mode 100755 index 0000000000..85032ab171 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTextBox.java @@ -0,0 +1,33 @@ +/* ==================================================================== + 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.xssf.usermodel; + +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.*; +import org.openxmlformats.schemas.drawingml.x2006.main.*; + +/** + * Represents a text box in a SpreadsheetML drawing. + * + * @author Yegor Kozlov + */ +public class XSSFTextBox extends XSSFSimpleShape { + + protected XSSFTextBox(XSSFDrawing drawing, CTShape ctShape) { + super(drawing, ctShape); + } + +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java index 8a10a266ce..c12c7ab779 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java @@ -19,6 +19,7 @@ package org.apache.poi.xssf.usermodel; import java.io.IOException; import java.io.OutputStream; +import java.io.InputStream; import java.util.*; import javax.xml.namespace.QName; import org.apache.poi.POIXMLDocument; @@ -30,6 +31,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; import org.apache.poi.util.PackageHelper; +import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.model.*; import org.apache.poi.POIXMLException; import org.apache.xmlbeans.XmlObject; @@ -279,6 +281,31 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable xssf="+xcell.toString() + " - hssf="+hcell.toString()); //BOOLEAN xcell.setCellValue(true); xcell.setCellType(Cell.CELL_TYPE_BOOLEAN); hcell.setCellValue(true); hcell.setCellType(Cell.CELL_TYPE_BOOLEAN); - System.out.println("BOOLEAN==> xssf="+xcell.toString() + " - hssf="+hcell.toString()); assertEquals(hcell.toString(),xcell.toString()); //NUMERIC @@ -415,7 +413,6 @@ public final class TestXSSFCell extends TestCase { xcell.setCellType(Cell.CELL_TYPE_NUMERIC); hcell.setCellValue(1234); hcell.setCellType(Cell.CELL_TYPE_NUMERIC); - System.out.println("NUMERIC==> xssf="+xcell.toString() + " - hssf="+hcell.toString()); assertEquals(hcell.toString(),xcell.toString()); //DATE ******************** @@ -434,7 +431,6 @@ public final class TestXSSFCell extends TestCase { hstyle.setDataFormat(hformat.getFormat("YYYY-MM-DD")); hcell.setCellStyle(hstyle); - System.out.println("DATE==> xssf="+xcell.toString() + " - hssf="+hcell.toString()); assertEquals(hcell.toString(),xcell.toString()); @@ -443,7 +439,6 @@ public final class TestXSSFCell extends TestCase { xcell.setCellType(Cell.CELL_TYPE_STRING); hcell.setCellValue(new HSSFRichTextString("text string")); hcell.setCellType(Cell.CELL_TYPE_STRING); - System.out.println("STRING==> xssf="+xcell.toString() + " - hssf="+hcell.toString()); assertEquals(hcell.toString(),xcell.toString()); //ERROR @@ -453,13 +448,11 @@ public final class TestXSSFCell extends TestCase { hcell.setCellErrorValue((byte)0); hcell.setCellType(Cell.CELL_TYPE_ERROR); - System.out.println("ERROR==> xssf="+xcell.toString() + " - hssf="+hcell.toString()); assertEquals(hcell.toString(),xcell.toString()); //FORMULA xcell.setCellFormula("A1+B2"); hcell.setCellValue("A1+B2"); - System.out.println("FORMULA==> xssf="+xcell.toString() + " - hssf="+hcell.toString()); assertEquals(hcell.toString(),xcell.toString()); } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java index c2ff6acad3..430924c856 100755 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFDrawing.java @@ -67,4 +67,13 @@ public class TestXSSFDrawing extends TestCase { assertEquals(drawingId, sheet.getWorksheet().getDrawing().getId()); } + public void testMultipleDrawings(){ + XSSFWorkbook wb = new XSSFWorkbook(); + for (int i = 0; i < 3; i++) { + XSSFSheet sheet = wb.createSheet(); + XSSFDrawing drawing = sheet.createDrawingPatriarch(); + } + org.openxml4j.opc.Package pkg = wb.getPackage(); + assertEquals(3, pkg.getPartsByContentType(XSSFRelation.DRAWINGS.getContentType()).size()); + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRow.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRow.java index 8e2f437233..f10b9e216f 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRow.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFRow.java @@ -25,6 +25,8 @@ import junit.framework.TestCase; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.XSSFTestDataSamples; import org.apache.poi.hssf.usermodel.HSSFSheet; @@ -131,15 +133,15 @@ public final class TestXSSFRow extends TestCase { XSSFRow row = getSampleRow(); // I assume that "ht" attribute value is in 'points', please verify that // Test that no rowHeight is set - assertEquals((short) -1, row.getHeight()); + assertEquals(row.getSheet().getDefaultRowHeight(), row.getHeight()); // Set a rowHeight and test the new value row.setHeight((short) 240); assertEquals((short) 240.0, row.getHeight()); - assertEquals((float)240.0, row.getHeightInPoints()); + assertEquals(12.0f, row.getHeightInPoints()); // Set a new rowHeight in points and test the new value row.setHeightInPoints(13); assertEquals((float) 13.0, row.getHeightInPoints()); - assertEquals((short) 13.0, row.getHeight()); + assertEquals((short)(13.0*20), row.getHeight()); } public void testGetSetZeroHeight() throws Exception { @@ -225,8 +227,7 @@ public final class TestXSSFRow extends TestCase { private static XSSFSheet createParentObjects() { XSSFWorkbook wb = new XSSFWorkbook(); - wb.setSharedStringSource(new SharedStringsTable()); - return new XSSFSheet(wb); + return wb.createSheet(); } /** @@ -298,4 +299,37 @@ public final class TestXSSFRow extends TestCase { assertEquals(-1, sheet.getRow(0).getLastCellNum()); assertEquals(-1, sheet.getRow(0).getFirstCellNum()); } + + public void testRowHeightCompatibility(){ + Workbook wb1 = new HSSFWorkbook(); + Workbook wb2 = new XSSFWorkbook(); + + Sheet sh1 = wb1.createSheet(); + Sheet sh2 = wb2.createSheet(); + + sh2.setDefaultRowHeight(sh1.getDefaultRowHeight()); + + assertEquals(sh1.getDefaultRowHeight(), sh2.getDefaultRowHeight()); + + //junit.framework.AssertionFailedError: expected:<12.0> but was:<12.75> + //YK: there is a bug in HSSF version, it trunkates decimal part + //assertEquals(sh1.getDefaultRowHeightInPoints(), sh2.getDefaultRowHeightInPoints()); + + Row row1 = sh1.createRow(0); + Row row2 = sh2.createRow(0); + + assertEquals(row1.getHeight(), row2.getHeight()); + assertEquals(row1.getHeightInPoints(), row2.getHeightInPoints()); + row1.setHeight((short)100); + row2.setHeight((short)100); + assertEquals(row1.getHeight(), row2.getHeight()); + assertEquals(row1.getHeightInPoints(), row2.getHeightInPoints()); + + row1.setHeightInPoints(25.5f); + row2.setHeightInPoints(25.5f); + assertEquals(row1.getHeight(), row2.getHeight()); + assertEquals(row1.getHeightInPoints(), row2.getHeightInPoints()); + + + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java index 0400c5b4d7..ea6bd8c154 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java @@ -29,6 +29,7 @@ import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.helpers.ColumnHelper; import org.apache.poi.xssf.XSSFTestDataSamples; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment; @@ -126,7 +127,7 @@ public class TestXSSFSheet extends TestCase { assertEquals((float) 18, sheet.getDefaultRowHeightInPoints()); // Test that defaultRowHeight is a truncated short: E.G. 360inPoints -> 18; 361inPoints -> 18 sheet.setDefaultRowHeight((short) 361); - assertEquals((float) 18, sheet.getDefaultRowHeightInPoints()); + assertEquals((float)361/20, sheet.getDefaultRowHeightInPoints()); // Set a new default row height in points and test getting the value in twips sheet.setDefaultRowHeightInPoints((short) 17); assertEquals((short) 340, sheet.getDefaultRowHeight()); @@ -398,13 +399,13 @@ public class TestXSSFSheet extends TestCase { public void testGetSetColumnWidth() { XSSFWorkbook workbook = new XSSFWorkbook(); - Sheet sheet = workbook.createSheet("Sheet 1"); - sheet.setColumnWidth((short) 1,(short) 22); - assertEquals(22, sheet.getColumnWidth((short) 1)); + XSSFSheet sheet = workbook.createSheet("Sheet 1"); + sheet.setColumnWidth(1, 22*256); + assertEquals(22*256, sheet.getColumnWidth(1)); // Now check the low level stuff, and check that's all // been set correctly - XSSFSheet xs = (XSSFSheet)sheet; + XSSFSheet xs = sheet; CTWorksheet cts = xs.getWorksheet(); CTCols[] cols_s = cts.getColsArray(); @@ -420,7 +421,7 @@ public class TestXSSFSheet extends TestCase { // Now set another - sheet.setColumnWidth((short) 3,(short) 33); + sheet.setColumnWidth(3, 33*256); cols_s = cts.getColsArray(); assertEquals(1, cols_s.length); @@ -534,7 +535,7 @@ public class TestXSSFSheet extends TestCase { public void testTopRowLeftCol() { XSSFWorkbook workbook = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet) workbook.createSheet("Sheet 1"); + XSSFSheet sheet = workbook.createSheet("Sheet 1"); sheet.showInPane((short)1, (short)1); assertEquals((short) 1, sheet.getTopRow()); assertEquals((short) 1, sheet.getLeftCol()); @@ -546,7 +547,7 @@ public class TestXSSFSheet extends TestCase { public void testShiftRows() { XSSFWorkbook workbook = new XSSFWorkbook(); - XSSFSheet sheet = (XSSFSheet) createSheet(workbook, "Sheet 1"); + XSSFSheet sheet = createSheet(workbook, "Sheet 1"); sheet.shiftRows(1, 2, 4, true, false); assertEquals((short) 1, sheet.getRow(5).getHeight()); assertEquals((short) 2, sheet.getRow(6).getHeight()); @@ -554,7 +555,7 @@ public class TestXSSFSheet extends TestCase { assertNull(sheet.getRow(2)); assertEquals(8, sheet.getPhysicalNumberOfRows()); - XSSFSheet sheet2 = (XSSFSheet) createSheet(workbook, "Sheet 2"); + XSSFSheet sheet2 = createSheet(workbook, "Sheet 2"); sheet2.shiftRows(1, 5, 3, true, false); assertEquals((short) 1, sheet2.getRow(4).getHeight()); assertEquals((short) 2, sheet2.getRow(5).getHeight()); @@ -566,7 +567,7 @@ public class TestXSSFSheet extends TestCase { assertNull(sheet2.getRow(3)); assertEquals(7, sheet2.getPhysicalNumberOfRows()); - XSSFSheet sheet3 = (XSSFSheet) createSheet(workbook, "Sheet 3"); + XSSFSheet sheet3 = createSheet(workbook, "Sheet 3"); sheet3.shiftRows(5, 7, -3, true, false); assertEquals(5, sheet3.getRow(2).getHeight()); assertEquals(6, sheet3.getRow(3).getHeight()); @@ -576,7 +577,7 @@ public class TestXSSFSheet extends TestCase { assertNull(sheet3.getRow(7)); assertEquals(7, sheet3.getPhysicalNumberOfRows()); - XSSFSheet sheet4 = (XSSFSheet) createSheet(workbook, "Sheet 4"); + XSSFSheet sheet4 = createSheet(workbook, "Sheet 4"); sheet4.shiftRows(5, 7, -2, true, false); assertEquals(5, sheet4.getRow(3).getHeight()); assertEquals(6, sheet4.getRow(4).getHeight()); @@ -586,17 +587,17 @@ public class TestXSSFSheet extends TestCase { assertEquals(8, sheet4.getPhysicalNumberOfRows()); // Test without copying rowHeight - XSSFSheet sheet5 = (XSSFSheet) createSheet(workbook, "Sheet 5"); + XSSFSheet sheet5 = createSheet(workbook, "Sheet 5"); sheet5.shiftRows(5, 7, -2, false, false); - assertEquals(-1, sheet5.getRow(3).getHeight()); - assertEquals(-1, sheet5.getRow(4).getHeight()); - assertEquals(-1, sheet5.getRow(5).getHeight()); + assertEquals(sheet5.getDefaultRowHeight(), sheet5.getRow(3).getHeight()); + assertEquals(sheet5.getDefaultRowHeight(), sheet5.getRow(4).getHeight()); + assertEquals(sheet5.getDefaultRowHeight(), sheet5.getRow(5).getHeight()); assertNull(sheet5.getRow(6)); assertNull(sheet5.getRow(7)); assertEquals(8, sheet5.getPhysicalNumberOfRows()); // Test without copying rowHeight and resetting to default height - XSSFSheet sheet6 = (XSSFSheet) createSheet(workbook, "Sheet 6"); + XSSFSheet sheet6 = createSheet(workbook, "Sheet 6"); sheet6.setDefaultRowHeight((short) 200); sheet6.shiftRows(5, 7, -2, false, true); assertEquals(200, sheet6.getRow(3).getHeight()); @@ -738,7 +739,7 @@ public class TestXSSFSheet extends TestCase { private XSSFSheet createSheet(XSSFWorkbook workbook, String name) { - XSSFSheet sheet = (XSSFSheet) workbook.createSheet(name); + XSSFSheet sheet = workbook.createSheet(name); Row row0 = sheet.createRow(0); row0.setHeight((short) 1); Row row1 = sheet.createRow(1); @@ -875,4 +876,29 @@ public class TestXSSFSheet extends TestCase { assertFalse(sheet.getRowSumsRight()); } + + public void testColumnWidthCompatibility() { + Workbook wb1 = new HSSFWorkbook(); + Workbook wb2 = new XSSFWorkbook(); + + Sheet sh1 = wb1.createSheet(); + Sheet sh2 = wb2.createSheet(); + + assertEquals(sh1.getDefaultColumnWidth(), sh2.getDefaultColumnWidth()); + + //if column width is not set, HSSF returns a wrong value which does not take into account + //margins and borders, it is always less than the actual column width + assertEquals(2048, sh1.getColumnWidth(0)); + assertEquals(2340, sh2.getColumnWidth(0)); + + sh1.setDefaultColumnWidth(1000); + sh2.setDefaultColumnWidth(1000); + assertEquals(1000, sh2.getDefaultColumnWidth()); + assertEquals(sh1.getDefaultColumnWidth(), sh2.getDefaultColumnWidth()); + + sh1.setColumnWidth(0, 500); + sh2.setColumnWidth(0, 500); + assertEquals(500, sh2.getColumnWidth(0)); + assertEquals(sh1.getColumnWidth(0), sh2.getColumnWidth(0)); + } } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java index ce1de14e18..49e47c937d 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFWorkbook.java @@ -154,16 +154,13 @@ public final class TestXSSFWorkbook extends TestCase { /** * Tests that we can save a new document */ - public void testSaveNew() throws IOException { + public void testSaveNew() { XSSFWorkbook workbook = new XSSFWorkbook(); workbook.createSheet("sheet1"); workbook.createSheet("sheet2"); workbook.createSheet("sheet3"); - File file = File.createTempFile("poi-", ".xlsx"); - System.out.println("Saving newly created file to " + file.getAbsolutePath()); - OutputStream out = new FileOutputStream(file); - workbook.write(out); - out.close(); + + XSSFTestDataSamples.writeOutAndReadBack(workbook); } /** @@ -258,7 +255,6 @@ public final class TestXSSFWorkbook extends TestCase { font.setUnderline(Font.U_DOUBLE); StylesTable styleSource=new StylesTable(); long index=styleSource.putFont(font); - System.out.println("index="+index); workbook.setStylesSource(styleSource); fontFind=workbook.findFont(Font.BOLDWEIGHT_BOLD, IndexedColors.BLACK.getIndex(), (short)15, "Calibri", false, false, Font.SS_NONE, Font.U_DOUBLE); assertNull(fontFind); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java index 34db8b57c4..62f465cc54 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestColumnHelper.java @@ -186,9 +186,6 @@ public final class TestColumnHelper extends TestCase { col9.setMax(27); helper.addCleanColIntoCols(cols1, col9); - if (false) { - System.err.println(cols1); - } // TODO - assert something interesting CTCol[] colArray = cols1.getColArray(); assertEquals(12, colArray.length);