]> source.dussan.org Git - poi.git/commitdiff
test integration of XDDF text entities
authorAlain Béarez <abearez@apache.org>
Sun, 26 Aug 2018 21:33:16 +0000 (21:33 +0000)
committerAlain Béarez <abearez@apache.org>
Sun, 26 Aug 2018 21:33:16 +0000 (21:33 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1839259 13f79535-47bb-0310-9956-ffa450edef68

12 files changed:
build.xml
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFShapeGroup.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSimpleShape.java
src/ooxml/testcases/org/apache/poi/xddf/usermodel/text/TestXDDFTextBodyProperties.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/xddf/usermodel/text/TestXDDFTextRun.java [new file with mode: 0644]
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSimpleShape.java

index 123867991bd6e7df9748c888b5adf0e97af4d4c8..6050b6b492539573d94e82ad95b391447589e608 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -1152,10 +1152,8 @@ under the License.
 
     <target name="retest-ooxml" depends="jar">
         <delete dir="${ooxml.reports.test}"/>
-        <delete dir="${ooxml.output.test}"/>
         <delete dir="${ooxml.output.test.dir}"/>
         <mkdir dir="${ooxml.reports.test}"/>
-        <mkdir dir="${ooxml.output.test}"/>
         <mkdir dir="${ooxml.output.test.dir}"/> 
         <!-- compile the sources -->
         <javac target="${jdk.version.class}"
index 708dc9b745e272e2dd59028edba553f565ccbed9..d9d2c891636e99fb50dab36743f739bb6e144a8a 100644 (file)
@@ -21,34 +21,28 @@ package org.apache.poi.xslf.usermodel;
 
 import org.apache.poi.sl.usermodel.AutoShape;
 import org.apache.poi.util.Beta;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
 import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;
 
-
 /**
  * Represents a shape with a preset geometry.
  *
  * @author Yegor Kozlov
  */
 @Beta
-public class XSLFAutoShape extends XSLFTextShape
-    implements AutoShape<XSLFShape,XSLFTextParagraph> {
+public class XSLFAutoShape extends XSLFTextShape implements AutoShape<XSLFShape, XSLFTextParagraph> {
 
-    /*package*/ XSLFAutoShape(CTShape shape, XSLFSheet sheet) {
+    /* package */ XSLFAutoShape(CTShape shape, XSLFSheet sheet) {
         super(shape, sheet);
     }
 
-    /*package*/
+    /* package */
     static XSLFAutoShape create(CTShape shape, XSLFSheet sheet) {
         if (shape.getSpPr().isSetCustGeom()) {
             return new XSLFFreeformShape(shape, sheet);
@@ -60,7 +54,8 @@ public class XSLFAutoShape extends XSLFTextShape
     }
 
     /**
-     * @param shapeId 1-based shapeId
+     * @param shapeId
+     *            1-based shapeId
      */
     static CTShape prototype(int shapeId) {
         CTShape ct = CTShape.Factory.newInstance();
@@ -76,22 +71,10 @@ public class XSLFAutoShape extends XSLFTextShape
         prst.addNewAvLst();
         return ct;
     }
-    
-    protected static void initTextBody(CTTextBody txBody) {
-        CTTextBodyProperties bodypr = txBody.addNewBodyPr();
-        bodypr.setAnchor(STTextAnchoringType.T);
-        bodypr.setRtlCol(false);
-        CTTextParagraph p = txBody.addNewP();
-        p.addNewPPr().setAlgn(STTextAlignType.L);
-        CTTextCharacterProperties endPr = p.addNewEndParaRPr();
-        endPr.setLang("en-US");
-        endPr.setSz(1100);   
-        p.addNewR().setT("");
-        txBody.addNewLstStyle();
-    }
 
-    protected CTTextBody getTextBody(boolean create){
-        CTShape shape = (CTShape)getXmlObject();
+    @Override
+    protected CTTextBody getTextBody(boolean create) {
+        CTShape shape = (CTShape) getXmlObject();
         CTTextBody txBody = shape.getTxBody();
         if (txBody == null && create) {
             txBody = shape.addNewTxBody();
@@ -101,7 +84,7 @@ public class XSLFAutoShape extends XSLFTextShape
     }
 
     @Override
-    public String toString(){
+    public String toString() {
         return "[" + getClass().getSimpleName() + "] " + getShapeName();
     }
 
index 63f1965932458e7206ed44222e544ca6e2714773..213ad99599dd28f41315798fc4bc37f29d4ede23 100644 (file)
@@ -33,6 +33,7 @@ import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
 import org.apache.poi.sl.usermodel.TableCell;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
 import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
 import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
 import org.apache.poi.xslf.usermodel.XSLFTableStyle.TablePartStyle;
 import org.apache.xmlbeans.XmlObject;
@@ -67,7 +68,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
 /**
  * Represents a cell of a table in a .pptx presentation
  */
-public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,XSLFTextParagraph> {
+public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape, XSLFTextParagraph> {
     private CTTableCellProperties _tcPr;
     private final XSLFTable table;
     private int row, col;
@@ -77,18 +78,20 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
      */
     private Rectangle2D anchor;
 
-    /*package*/ XSLFTableCell(CTTableCell cell, XSLFTable table){
+    /* package */ XSLFTableCell(CTTableCell cell, XSLFTable table) {
         super(cell, table.getSheet());
         this.table = table;
     }
 
     @Override
-    protected CTTextBody getTextBody(boolean create){
+    protected CTTextBody getTextBody(boolean create) {
         CTTableCell cell = getCell();
         CTTextBody txBody = cell.getTxBody();
         if (txBody == null && create) {
-            txBody = cell.addNewTxBody();
-            XSLFAutoShape.initTextBody(txBody);
+            XDDFTextBody body = new XDDFTextBody(this);
+            initTextBody(body);
+            cell.setTxBody(body.getXmlObject());
+            txBody = cell.getTxBody();
         }
         return txBody;
     }
@@ -116,25 +119,25 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     }
 
     @Override
-    public void setLeftInset(double margin){
+    public void setLeftInset(double margin) {
         CTTableCellProperties pr = getCellProperties(true);
         pr.setMarL(Units.toEMU(margin));
     }
 
     @Override
-    public void setRightInset(double margin){
+    public void setRightInset(double margin) {
         CTTableCellProperties pr = getCellProperties(true);
         pr.setMarR(Units.toEMU(margin));
     }
 
     @Override
-    public void setTopInset(double margin){
+    public void setTopInset(double margin) {
         CTTableCellProperties pr = getCellProperties(true);
         pr.setMarT(Units.toEMU(margin));
     }
 
     @Override
-    public void setBottomInset(double margin){
+    public void setBottomInset(double margin) {
         CTTableCellProperties pr = getCellProperties(true);
         pr.setMarB(Units.toEMU(margin));
     }
@@ -150,16 +153,16 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         }
 
         switch (edge) {
-            case bottom:
-                return (pr.isSetLnB()) ? pr.getLnB() : (create ? pr.addNewLnB() : null);
-            case left:
-                return (pr.isSetLnL()) ? pr.getLnL() : (create ? pr.addNewLnL() : null);
-            case top:
-                return (pr.isSetLnT()) ? pr.getLnT() : (create ? pr.addNewLnT() : null);
-            case right:
-                return (pr.isSetLnR()) ? pr.getLnR() : (create ? pr.addNewLnR() : null);
-            default:
-                return null;
+        case bottom:
+            return (pr.isSetLnB()) ? pr.getLnB() : (create ? pr.addNewLnB() : null);
+        case left:
+            return (pr.isSetLnL()) ? pr.getLnL() : (create ? pr.addNewLnL() : null);
+        case top:
+            return (pr.isSetLnT()) ? pr.getLnT() : (create ? pr.addNewLnT() : null);
+        case right:
+            return (pr.isSetLnR()) ? pr.getLnR() : (create ? pr.addNewLnR() : null);
+        default:
+            return null;
         }
     }
 
@@ -170,28 +173,28 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
             return;
         }
         switch (edge) {
-            case bottom:
-                if (pr.isSetLnB()) {
-                    pr.unsetLnB();
-                }
-                break;
-            case left:
-                if (pr.isSetLnL()) {
-                    pr.unsetLnL();
-                }
-                break;
-            case top:
-                if (pr.isSetLnT()) {
-                    pr.unsetLnT();
-                }
-                break;
-            case right:
-                if (pr.isSetLnR()) {
-                    pr.unsetLnB();
-                }
-                break;
-            default:
-                throw new IllegalArgumentException();
+        case bottom:
+            if (pr.isSetLnB()) {
+                pr.unsetLnB();
+            }
+            break;
+        case left:
+            if (pr.isSetLnL()) {
+                pr.unsetLnL();
+            }
+            break;
+        case top:
+            if (pr.isSetLnT()) {
+                pr.unsetLnT();
+            }
+            break;
+        case right:
+            if (pr.isSetLnR()) {
+                pr.unsetLnB();
+            }
+            break;
+        default:
+            throw new IllegalArgumentException();
         }
     }
 
@@ -276,7 +279,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
             ln.unsetNoFill();
         }
 
-        if(!ln.isSetPrstDash()) {
+        if (!ln.isSetPrstDash()) {
             ln.addNewPrstDash().setVal(STPresetLineDashVal.SOLID);
         }
         if (!ln.isSetCmpd()) {
@@ -396,19 +399,19 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         ln.setCap(STLineCap.Enum.forInt(cap.ooxmlId));
     }
 
-
-
     /**
-     * Specifies a solid color fill. The shape is filled entirely with the specified color.
+     * Specifies a solid color fill. The shape is filled entirely with the
+     * specified color.
      *
-     * @param color the solid color fill.
-     * The value of <code>null</code> unsets the solidFIll attribute from the underlying xml
+     * @param color
+     *            the solid color fill. The value of <code>null</code> unsets
+     *            the solidFIll attribute from the underlying xml
      */
     @Override
     public void setFillColor(Color color) {
         CTTableCellProperties spPr = getCellProperties(true);
         if (color == null) {
-            if(spPr.isSetSolidFill()) {
+            if (spPr.isSetSolidFill()) {
                 spPr.unsetSolidFill();
             }
         } else {
@@ -423,13 +426,13 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
      * @return solid fill color of null if not set
      */
     @Override
-    public Color getFillColor(){
+    public Color getFillColor() {
         PaintStyle ps = getFillPaint();
         if (ps instanceof SolidPaint) {
-            ColorStyle cs = ((SolidPaint)ps).getSolidColor();
+            ColorStyle cs = ((SolidPaint) ps).getSolidColor();
             return DrawPaint.applyColorTransform(cs);
         }
-        
+
         return null;
     }
 
@@ -465,23 +468,24 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         } else {
             return null;
         }
-        
+
         fp = XSLFPropertiesDelegate.getFillDelegate(props);
-        if (fp != null)  {
+        if (fp != null) {
             PaintStyle paint = XSLFShape.selectPaint(fp, null, slideShow.getPackagePart(), theme, hasPlaceholder);
             if (paint != null) {
                 return paint;
             }
         }
-        
+
         return null;
     }
 
     /**
      * Retrieves the part style depending on the location of this cell
      *
-     * @param tablePartStyle the part to be returned, usually this is null
-     *  and only set when used as a helper method
+     * @param tablePartStyle
+     *            the part to be returned, usually this is null and only set
+     *            when used as a helper method
      * @return the table part style
      */
     private CTTablePartStyle getTablePartStyle(TablePartStyle tablePartStyle) {
@@ -503,11 +507,11 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
             tps = tablePartStyle;
         } else if (row == 0 && firstRow) {
             tps = TablePartStyle.firstRow;
-        } else if (row == table.getNumberOfRows()-1 && lastRow) {
+        } else if (row == table.getNumberOfRows() - 1 && lastRow) {
             tps = TablePartStyle.lastRow;
         } else if (col == 0 && firstCol) {
             tps = TablePartStyle.firstCol;
-        } else if (col == table.getNumberOfColumns()-1 && lastCol) {
+        } else if (col == table.getNumberOfColumns() - 1 && lastCol) {
             tps = TablePartStyle.lastCol;
         } else {
             tps = TablePartStyle.wholeTbl;
@@ -559,28 +563,28 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     }
 
     @Override
-    public void setVerticalAlignment(VerticalAlignment anchor){
-       CTTableCellProperties cellProps = getCellProperties(true);
-               if(anchor == null) {
-                       if(cellProps.isSetAnchor()) {
-                               cellProps.unsetAnchor();
-                       }
-               } else {
-                       cellProps.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
-               }
+    public void setVerticalAlignment(VerticalAlignment anchor) {
+        CTTableCellProperties cellProps = getCellProperties(true);
+        if (anchor == null) {
+            if (cellProps.isSetAnchor()) {
+                cellProps.unsetAnchor();
+            }
+        } else {
+            cellProps.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
+        }
     }
 
     @Override
-    public VerticalAlignment getVerticalAlignment(){
+    public VerticalAlignment getVerticalAlignment() {
         CTTableCellProperties cellProps = getCellProperties(false);
 
         VerticalAlignment align = VerticalAlignment.TOP;
-        if(cellProps != null && cellProps.isSetAnchor()) {
+        if (cellProps != null && cellProps.isSetAnchor()) {
             int ival = cellProps.getAnchor().intValue();
             align = VerticalAlignment.values()[ival - 1];
         }
         return align;
-     }
+    }
 
     /**
      * @since POI 3.15-beta2
@@ -588,7 +592,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     @Override
     public void setTextDirection(TextDirection orientation) {
         CTTableCellProperties cellProps = getCellProperties(true);
-        if(orientation == null) {
+        if (orientation == null) {
             if (cellProps.isSetVert()) {
                 cellProps.unsetVert();
             }
@@ -629,23 +633,23 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         }
 
         switch (orientation.intValue()) {
-            default:
-            case STTextVerticalType.INT_HORZ:
-                return TextDirection.HORIZONTAL;
-            case STTextVerticalType.INT_VERT:
-            case STTextVerticalType.INT_EA_VERT:
-            case STTextVerticalType.INT_MONGOLIAN_VERT:
-                return TextDirection.VERTICAL;
-            case STTextVerticalType.INT_VERT_270:
-                return TextDirection.VERTICAL_270;
-            case STTextVerticalType.INT_WORD_ART_VERT:
-            case STTextVerticalType.INT_WORD_ART_VERT_RTL:
-                return TextDirection.STACKED;
+        default:
+        case STTextVerticalType.INT_HORZ:
+            return TextDirection.HORIZONTAL;
+        case STTextVerticalType.INT_VERT:
+        case STTextVerticalType.INT_EA_VERT:
+        case STTextVerticalType.INT_MONGOLIAN_VERT:
+            return TextDirection.VERTICAL;
+        case STTextVerticalType.INT_VERT_270:
+            return TextDirection.VERTICAL_270;
+        case STTextVerticalType.INT_WORD_ART_VERT:
+        case STTextVerticalType.INT_WORD_ART_VERT_RTL:
+            return TextDirection.STACKED;
         }
     }
 
     private CTTableCell getCell() {
-        return (CTTableCell)getXmlObject();
+        return (CTTableCell) getXmlObject();
     }
 
     /* package */ void setRowColIndex(int row, int col) {
@@ -669,15 +673,16 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     }
 
     /**
-     * There's no real anchor for table cells - this method is used to temporarily store the location
-     * of the cell for a later retrieval, e.g. for rendering
+     * There's no real anchor for table cells - this method is used to
+     * temporarily store the location of the cell for a later retrieval, e.g.
+     * for rendering
      *
      * @since POI 3.15-beta2
      */
     @Override
     public void setAnchor(Rectangle2D anchor) {
         if (this.anchor == null) {
-            this.anchor = (Rectangle2D)anchor.clone();
+            this.anchor = (Rectangle2D) anchor.clone();
         } else {
             this.anchor.setRect(anchor);
         }
@@ -692,7 +697,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
             table.updateCellAnchor();
         }
         // anchor should be set, after updateCellAnchor is through
-        assert(anchor != null);
+        assert (anchor != null);
         return anchor;
     }
 
@@ -717,7 +722,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     protected XmlObject getShapeProperties() {
         return getCellProperties(false);
     }
-    
+
     /**
      * @since POI 3.15-beta2
      */
@@ -741,7 +746,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         }
 
         @Override
-        public PaintStyle getFontColor(){
+        public PaintStyle getFontColor() {
             CTTableStyleTextStyle txStyle = getTextStyle();
             if (txStyle == null) {
                 return super.getFontColor();
@@ -752,7 +757,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
             if (fontRef != null) {
                 phClr = fontRef.getSchemeClr();
             }
-            
+
             XSLFTheme theme = getSheet().getTheme();
             final XSLFColor c = new XSLFColor(txStyle, theme, phClr);
             return DrawPaint.createSolidPaint(c.getColorStyle());
@@ -777,7 +782,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
                 return txStyle.isSetI() && txStyle.getI().intValue() == STOnOffStyleType.INT_ON;
             }
         }
+
         private CTTableStyleTextStyle getTextStyle() {
             CTTablePartStyle tps = getTablePartStyle(null);
             if (tps == null || !tps.isSetTcTxStyle()) {
index 6fcb94eedd0f3a770a81ef1a0c67b4eff3b7dfeb..7fe3252995b51dc35cfd98851b628f94acda0c1d 100644 (file)
@@ -21,27 +21,30 @@ package org.apache.poi.xslf.usermodel;
 
 import org.apache.poi.sl.usermodel.TextBox;
 import org.apache.poi.util.Beta;
-import org.openxmlformats.schemas.drawingml.x2006.main.*;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;
 
-
 /**
  * @author Yegor Kozlov
  */
 @Beta
-public class XSLFTextBox extends XSLFAutoShape
-    implements TextBox<XSLFShape,XSLFTextParagraph> {
+public class XSLFTextBox extends XSLFAutoShape implements TextBox<XSLFShape, XSLFTextParagraph> {
 
-    /*package*/ XSLFTextBox(CTShape shape, XSLFSheet sheet){
+    /* package */ XSLFTextBox(CTShape shape, XSLFSheet sheet) {
         super(shape, sheet);
     }
 
     /**
      *
-     * @param shapeId   1-based shapeId
+     * @param shapeId
+     *            1-based shapeId
      */
-    static CTShape prototype(int shapeId){
+    static CTShape prototype(int shapeId) {
         CTShape ct = CTShape.Factory.newInstance();
         CTShapeNonVisual nvSpPr = ct.addNewNvSpPr();
         CTNonVisualDrawingProps cnv = nvSpPr.addNewCNvPr();
@@ -53,9 +56,10 @@ public class XSLFTextBox extends XSLFAutoShape
         CTPresetGeometry2D prst = spPr.addNewPrstGeom();
         prst.setPrst(STShapeType.RECT);
         prst.addNewAvLst();
-        CTTextBody txBody = ct.addNewTxBody();
-        XSLFAutoShape.initTextBody(txBody);
+        XDDFTextBody body = new XDDFTextBody(null);
+        initTextBody(body);
+        ct.setTxBody(body.getXmlObject());
 
         return ct;
     }
-}
\ No newline at end of file
+}
index a52feaa3e7ad52c1302df31d51158ecb2bfc44f9..9286d5354aacd23b81cded89256b7769ce6478e7 100644 (file)
@@ -24,6 +24,8 @@ import java.awt.geom.Rectangle2D;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
 
 import org.apache.poi.ooxml.POIXMLException;
 import org.apache.poi.sl.draw.DrawFactory;
@@ -34,6 +36,9 @@ import org.apache.poi.sl.usermodel.TextShape;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.text.TextContainer;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
+import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
 import org.apache.poi.xslf.model.PropertyFetcher;
 import org.apache.poi.xslf.model.TextBodyPropertyFetcher;
 import org.apache.xmlbeans.XmlObject;
@@ -52,10 +57,10 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
  */
 @Beta
 public abstract class XSLFTextShape extends XSLFSimpleShape
-    implements TextShape<XSLFShape,XSLFTextParagraph> {
+    implements TextContainer, TextShape<XSLFShape, XSLFTextParagraph> {
     private final List<XSLFTextParagraph> _paragraphs;
 
-    /*package*/ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
+    /* package */ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
         super(shape, sheet);
 
         _paragraphs = new ArrayList<>();
@@ -67,8 +72,22 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
         }
     }
 
+    protected static void initTextBody(XDDFTextBody body) {
+        XDDFTextParagraph p = body.getParagraph(0);
+        p.appendRegularRun("");
+    }
+
+    @Beta
+    public XDDFTextBody getTextBody() {
+        CTTextBody txBody = getTextBody(false);
+        if (txBody == null) {
+            return null;
+        }
+        return new XDDFTextBody(this, txBody);
+    }
+
     @Override
-    public Iterator<XSLFTextParagraph> iterator(){
+    public Iterator<XSLFTextParagraph> iterator() {
         return getTextParagraphs().iterator();
     }
 
@@ -87,7 +106,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     /**
      * unset text from this shape
      */
-    public void clearText(){
+    public void clearText() {
         _paragraphs.clear();
         CTTextBody txBody = getTextBody(true);
         txBody.setPArray(null); // remove any existing paragraphs
@@ -95,13 +114,14 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     @Override
     public XSLFTextRun setText(String text) {
-        // calling clearText or setting to a new Array leads to a XmlValueDisconnectedException
+        // calling clearText or setting to a new Array leads to a
+        // XmlValueDisconnectedException
         if (!_paragraphs.isEmpty()) {
             CTTextBody txBody = getTextBody(false);
             int cntPs = txBody.sizeOfPArray();
             for (int i = cntPs; i > 1; i--) {
-                txBody.removeP(i-1);
-                _paragraphs.remove(i-1);
+                txBody.removeP(i - 1);
+                _paragraphs.remove(i - 1);
             }
 
             _paragraphs.get(0).clearButKeepProperties();
@@ -127,18 +147,19 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
             para = null;
         } else {
             firstPara = !newParagraph;
-            para = _paragraphs.get(_paragraphs.size()-1);
+            para = _paragraphs.get(_paragraphs.size() - 1);
             CTTextParagraph ctp = para.getXmlObject();
             otherPPr = ctp.getPPr();
             List<XSLFTextRun> runs = para.getTextRuns();
             if (!runs.isEmpty()) {
-                XSLFTextRun r0 = runs.get(runs.size()-1);
+                XSLFTextRun r0 = runs.get(runs.size() - 1);
                 otherRPr = r0.getRPr(false);
                 if (otherRPr == null) {
                     otherRPr = ctp.getEndParaRPr();
                 }
             }
-            // don't copy endParaRPr to the run in case there aren't any other runs
+            // don't copy endParaRPr to the run in case there aren't any other
+            // runs
             // this is the case when setText() was called initially
             // otherwise the master style will be overridden/ignored
         }
@@ -173,7 +194,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
             firstPara = false;
         }
 
-        assert(run != null);
+        assert (run != null);
         return run;
     }
 
@@ -203,11 +224,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public void setVerticalAlignment(VerticalAlignment anchor){
+    public void setVerticalAlignment(VerticalAlignment anchor) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-             if(anchor == null) {
-                if(bodyPr.isSetAnchor()) {
+            if (anchor == null) {
+                if (bodyPr.isSetAnchor()) {
                     bodyPr.unsetAnchor();
                 }
             } else {
@@ -217,11 +238,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public VerticalAlignment getVerticalAlignment(){
-        PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){
+    public VerticalAlignment getVerticalAlignment() {
+        PropertyFetcher<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-                if(props.isSetAnchor()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetAnchor()) {
                     int val = props.getAnchor().intValue();
                     setValue(VerticalAlignment.values()[val - 1]);
                     return true;
@@ -234,10 +255,10 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public void setHorizontalCentered(Boolean isCentered){
+    public void setHorizontalCentered(Boolean isCentered) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-             if (isCentered == null) {
+            if (isCentered == null) {
                 if (bodyPr.isSetAnchorCtr()) {
                     bodyPr.unsetAnchorCtr();
                 }
@@ -248,11 +269,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public boolean isHorizontalCentered(){
-        PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
+    public boolean isHorizontalCentered() {
+        PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-                if(props.isSetAnchorCtr()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetAnchorCtr()) {
                     setValue(props.getAnchorCtr());
                     return true;
                 }
@@ -264,11 +285,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public void setTextDirection(TextDirection orientation){
+    public void setTextDirection(TextDirection orientation) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            if(orientation == null) {
-                if(bodyPr.isSetVert()) {
+            if (orientation == null) {
+                if (bodyPr.isSetVert()) {
                     bodyPr.unsetVert();
                 }
             } else {
@@ -278,24 +299,24 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public TextDirection getTextDirection(){
+    public TextDirection getTextDirection() {
         CTTextBodyProperties bodyPr = getTextBodyPr();
         if (bodyPr != null) {
             STTextVerticalType.Enum val = bodyPr.getVert();
-            if(val != null) {
+            if (val != null) {
                 switch (val.intValue()) {
-                    default:
-                    case STTextVerticalType.INT_HORZ:
-                        return TextDirection.HORIZONTAL;
-                    case STTextVerticalType.INT_EA_VERT:
-                    case STTextVerticalType.INT_MONGOLIAN_VERT:
-                    case STTextVerticalType.INT_VERT:
-                        return TextDirection.VERTICAL;
-                    case STTextVerticalType.INT_VERT_270:
-                        return TextDirection.VERTICAL_270;
-                    case STTextVerticalType.INT_WORD_ART_VERT_RTL:
-                    case STTextVerticalType.INT_WORD_ART_VERT:
-                        return TextDirection.STACKED;
+                default:
+                case STTextVerticalType.INT_HORZ:
+                    return TextDirection.HORIZONTAL;
+                case STTextVerticalType.INT_EA_VERT:
+                case STTextVerticalType.INT_MONGOLIAN_VERT:
+                case STTextVerticalType.INT_VERT:
+                    return TextDirection.VERTICAL;
+                case STTextVerticalType.INT_VERT_270:
+                    return TextDirection.VERTICAL_270;
+                case STTextVerticalType.INT_WORD_ART_VERT_RTL:
+                case STTextVerticalType.INT_WORD_ART_VERT:
+                    return TextDirection.STACKED;
                 }
             }
         }
@@ -315,22 +336,22 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     public void setTextRotation(Double rotation) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            bodyPr.setRot((int)(rotation * 60000.));
+            bodyPr.setRot((int) (rotation * 60000.));
         }
     }
 
-
     /**
-     * Returns the distance (in points) between the bottom of the text frame
-     * and the bottom of the inscribed rectangle of the shape that contains the text.
+     * Returns the distance (in points) between the bottom of the text frame and
+     * the bottom of the inscribed rectangle of the shape that contains the
+     * text.
      *
      * @return the bottom inset in points
      */
-    public double getBottomInset(){
-        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+    public double getBottomInset() {
+        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-                if(props.isSetBIns()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetBIns()) {
                     double val = Units.toPoints(props.getBIns());
                     setValue(val);
                     return true;
@@ -344,17 +365,17 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     /**
-     *  Returns the distance (in points) between the left edge of the text frame
-     *  and the left edge of the inscribed rectangle of the shape that contains
-     *  the text.
+     * Returns the distance (in points) between the left edge of the text frame
+     * and the left edge of the inscribed rectangle of the shape that contains
+     * the text.
      *
      * @return the left inset in points
      */
-    public double getLeftInset(){
-        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+    public double getLeftInset() {
+        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-                if(props.isSetLIns()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetLIns()) {
                     double val = Units.toPoints(props.getLIns());
                     setValue(val);
                     return true;
@@ -368,17 +389,17 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     /**
-     *  Returns the distance (in points) between the right edge of the
-     *  text frame and the right edge of the inscribed rectangle of the shape
-     *  that contains the text.
+     * Returns the distance (in points) between the right edge of the text frame
+     * and the right edge of the inscribed rectangle of the shape that contains
+     * the text.
      *
      * @return the right inset in points
      */
-    public double getRightInset(){
-        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+    public double getRightInset() {
+        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-                if(props.isSetRIns()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetRIns()) {
                     double val = Units.toPoints(props.getRIns());
                     setValue(val);
                     return true;
@@ -392,16 +413,16 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     /**
-     *  Returns the distance (in points) between the top of the text frame
-     *  and the top of the inscribed rectangle of the shape that contains the text.
+     * Returns the distance (in points) between the top of the text frame and
+     * the top of the inscribed rectangle of the shape that contains the text.
      *
      * @return the top inset in points
      */
-    public double getTopInset(){
-        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>(){
+    public double getTopInset() {
+        PropertyFetcher<Double> fetcher = new TextBodyPropertyFetcher<Double>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-                if(props.isSetTIns()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetTIns()) {
                     double val = Units.toPoints(props.getTIns());
                     setValue(val);
                     return true;
@@ -416,14 +437,16 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     /**
      * Sets the bottom margin.
+     *
      * @see #getBottomInset()
      *
-     * @param margin    the bottom margin
+     * @param margin
+     *            the bottom margin
      */
-    public void setBottomInset(double margin){
+    public void setBottomInset(double margin) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            if(margin == -1) {
+            if (margin == -1) {
                 bodyPr.unsetBIns();
             } else {
                 bodyPr.setBIns(Units.toEMU(margin));
@@ -433,14 +456,16 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     /**
      * Sets the left margin.
+     *
      * @see #getLeftInset()
      *
-     * @param margin    the left margin
+     * @param margin
+     *            the left margin
      */
-    public void setLeftInset(double margin){
+    public void setLeftInset(double margin) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            if(margin == -1) {
+            if (margin == -1) {
                 bodyPr.unsetLIns();
             } else {
                 bodyPr.setLIns(Units.toEMU(margin));
@@ -450,14 +475,16 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     /**
      * Sets the right margin.
+     *
      * @see #getRightInset()
      *
-     * @param margin    the right margin
+     * @param margin
+     *            the right margin
      */
-    public void setRightInset(double margin){
+    public void setRightInset(double margin) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            if(margin == -1) {
+            if (margin == -1) {
                 bodyPr.unsetRIns();
             } else {
                 bodyPr.setRIns(Units.toEMU(margin));
@@ -467,14 +494,16 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     /**
      * Sets the top margin.
+     *
      * @see #getTopInset()
      *
-     * @param margin    the top margin
+     * @param margin
+     *            the top margin
      */
-    public void setTopInset(double margin){
+    public void setTopInset(double margin) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            if(margin == -1) {
+            if (margin == -1) {
                 bodyPr.unsetTIns();
             } else {
                 bodyPr.setTIns(Units.toEMU(margin));
@@ -496,11 +525,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public boolean getWordWrap(){
-        PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
+    public boolean getWordWrap() {
+        PropertyFetcher<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>() {
             @Override
-            public boolean fetch(CTTextBodyProperties props){
-               if(props.isSetWrap()){
+            public boolean fetch(CTTextBodyProperties props) {
+                if (props.isSetWrap()) {
                     setValue(props.getWrap() == STTextWrappingType.SQUARE);
                     return true;
                 }
@@ -512,7 +541,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     }
 
     @Override
-    public void setWordWrap(boolean wrap){
+    public void setWordWrap(boolean wrap) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
             bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
@@ -521,28 +550,36 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
 
     /**
      *
-     * Specifies that a shape should be auto-fit to fully contain the text described within it.
-     * Auto-fitting is when text within a shape is scaled in order to contain all the text inside
+     * Specifies that a shape should be auto-fit to fully contain the text
+     * described within it. Auto-fitting is when text within a shape is scaled
+     * in order to contain all the text inside
      *
-     * @param value type of autofit
+     * @param value
+     *            type of autofit
      */
-    public void setTextAutofit(TextAutofit value){
+    public void setTextAutofit(TextAutofit value) {
         CTTextBodyProperties bodyPr = getTextBodyPr(true);
         if (bodyPr != null) {
-            if(bodyPr.isSetSpAutoFit()) {
+            if (bodyPr.isSetSpAutoFit()) {
                 bodyPr.unsetSpAutoFit();
             }
-            if(bodyPr.isSetNoAutofit()) {
+            if (bodyPr.isSetNoAutofit()) {
                 bodyPr.unsetNoAutofit();
             }
-            if(bodyPr.isSetNormAutofit()) {
+            if (bodyPr.isSetNormAutofit()) {
                 bodyPr.unsetNormAutofit();
             }
 
-            switch(value){
-                case NONE: bodyPr.addNewNoAutofit(); break;
-                case NORMAL: bodyPr.addNewNormAutofit(); break;
-                case SHAPE: bodyPr.addNewSpAutoFit(); break;
+            switch (value) {
+            case NONE:
+                bodyPr.addNewNoAutofit();
+                break;
+            case NORMAL:
+                bodyPr.addNewNormAutofit();
+                break;
+            case SHAPE:
+                bodyPr.addNewSpAutoFit();
+                break;
             }
         }
     }
@@ -551,10 +588,10 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
      *
      * @return type of autofit
      */
-    public TextAutofit getTextAutofit(){
+    public TextAutofit getTextAutofit() {
         CTTextBodyProperties bodyPr = getTextBodyPr();
         if (bodyPr != null) {
-            if(bodyPr.isSetNoAutofit()) {
+            if (bodyPr.isSetNoAutofit()) {
                 return TextAutofit.NONE;
             } else if (bodyPr.isSetNormAutofit()) {
                 return TextAutofit.NORMAL;
@@ -565,7 +602,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
         return TextAutofit.NORMAL;
     }
 
-    protected CTTextBodyProperties getTextBodyPr(){
+    protected CTTextBodyProperties getTextBodyPr() {
         return getTextBodyPr(false);
     }
 
@@ -588,89 +625,88 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
         super.setPlaceholder(placeholder);
     }
 
-    public Placeholder getTextType(){
+    public Placeholder getTextType() {
         return getPlaceholder();
     }
 
     @Override
-    public double getTextHeight(){
+    public double getTextHeight() {
         return getTextHeight(null);
     }
-    
+
     @Override
-    public double getTextHeight(Graphics2D graphics){
+    public double getTextHeight(Graphics2D graphics) {
         DrawFactory drawFact = DrawFactory.getInstance(graphics);
         DrawTextShape dts = drawFact.getDrawable(this);
         return dts.getTextHeight(graphics);
     }
 
     @Override
-    public Rectangle2D resizeToFitText(){
+    public Rectangle2D resizeToFitText() {
         return resizeToFitText(null);
     }
-    
+
     @Override
     public Rectangle2D resizeToFitText(Graphics2D graphics) {
         Rectangle2D anchor = getAnchor();
 
-        if(anchor.getWidth() == 0.) {
+        if (anchor.getWidth() == 0.) {
             throw new POIXMLException("Anchor of the shape was not set.");
         }
         double height = getTextHeight(graphics);
         height += 1; // add a pixel to compensate rounding errors
 
         Insets2D insets = getInsets();
-        anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height+insets.top+insets.bottom);
+        anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height + insets.top + insets.bottom);
         setAnchor(anchor);
 
         return anchor;
     }
 
-
     @Override
-    void copy(XSLFShape other){
+    void copy(XSLFShape other) {
         super.copy(other);
 
-        XSLFTextShape otherTS = (XSLFTextShape)other;
+        XSLFTextShape otherTS = (XSLFTextShape) other;
         CTTextBody otherTB = otherTS.getTextBody(false);
         CTTextBody thisTB = getTextBody(true);
         if (otherTB == null) {
             return;
         }
 
-        thisTB.setBodyPr((CTTextBodyProperties)otherTB.getBodyPr().copy());
+        thisTB.setBodyPr((CTTextBodyProperties) otherTB.getBodyPr().copy());
 
         if (thisTB.isSetLstStyle()) {
             thisTB.unsetLstStyle();
         }
         if (otherTB.isSetLstStyle()) {
-            thisTB.setLstStyle((CTTextListStyle)otherTB.getLstStyle().copy());
+            thisTB.setLstStyle((CTTextListStyle) otherTB.getLstStyle().copy());
         }
 
         boolean srcWordWrap = otherTS.getWordWrap();
-        if(srcWordWrap != getWordWrap()){
+        if (srcWordWrap != getWordWrap()) {
             setWordWrap(srcWordWrap);
         }
 
         double leftInset = otherTS.getLeftInset();
-        if(leftInset != getLeftInset()) {
+        if (leftInset != getLeftInset()) {
             setLeftInset(leftInset);
         }
         double rightInset = otherTS.getRightInset();
-        if(rightInset != getRightInset()) {
+        if (rightInset != getRightInset()) {
             setRightInset(rightInset);
         }
         double topInset = otherTS.getTopInset();
-        if(topInset != getTopInset()) {
+        if (topInset != getTopInset()) {
             setTopInset(topInset);
         }
         double bottomInset = otherTS.getBottomInset();
-        if(bottomInset != getBottomInset()) {
+        if (bottomInset != getBottomInset()) {
             setBottomInset(bottomInset);
         }
 
         VerticalAlignment vAlign = otherTS.getVerticalAlignment();
-        if(vAlign != getVerticalAlignment()) {
+        if (vAlign != getVerticalAlignment()) {
             setVerticalAlignment(vAlign);
         }
 
@@ -685,26 +721,26 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     @Override
     public void setTextPlaceholder(TextPlaceholder placeholder) {
         switch (placeholder) {
-            default:
-            case NOTES:
-            case HALF_BODY:
-            case QUARTER_BODY:
-            case BODY:
-                setPlaceholder(Placeholder.BODY);
-                break;
-            case TITLE:
-                setPlaceholder(Placeholder.TITLE);
-                break;
-            case CENTER_BODY:
-                setPlaceholder(Placeholder.BODY);
-                setHorizontalCentered(true);
-                break;
-            case CENTER_TITLE:
-                setPlaceholder(Placeholder.CENTERED_TITLE);
-                break;
-            case OTHER:
-                setPlaceholder(Placeholder.CONTENT);
-                break;
+        default:
+        case NOTES:
+        case HALF_BODY:
+        case QUARTER_BODY:
+        case BODY:
+            setPlaceholder(Placeholder.BODY);
+            break;
+        case TITLE:
+            setPlaceholder(Placeholder.TITLE);
+            break;
+        case CENTER_BODY:
+            setPlaceholder(Placeholder.BODY);
+            setHorizontalCentered(true);
+            break;
+        case CENTER_TITLE:
+            setPlaceholder(Placeholder.CENTERED_TITLE);
+            break;
+        case OTHER:
+            setPlaceholder(Placeholder.CONTENT);
+            break;
         }
     }
 
@@ -715,18 +751,23 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
             return TextPlaceholder.BODY;
         }
         switch (ph) {
-        case BODY: return TextPlaceholder.BODY;
-        case TITLE: return TextPlaceholder.TITLE;
-        case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE;
+        case BODY:
+            return TextPlaceholder.BODY;
+        case TITLE:
+            return TextPlaceholder.TITLE;
+        case CENTERED_TITLE:
+            return TextPlaceholder.CENTER_TITLE;
         default:
-        case CONTENT: return TextPlaceholder.OTHER;
+        case CONTENT:
+            return TextPlaceholder.OTHER;
         }
     }
 
     /**
      * Helper method to allow subclasses to provide their own text paragraph
      *
-     * @param p the xml reference
+     * @param p
+     *            the xml reference
      *
      * @return a new text paragraph
      *
@@ -735,4 +776,19 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
     protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) {
         return new XSLFTextParagraph(p, this);
     }
-}
\ No newline at end of file
+
+    @Override
+    public <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
+        Function<CTTextParagraphProperties, R> getter) {
+        // TODO Auto-generated method stub
+        return Optional.empty();
+    }
+
+    @Override
+    public <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
+        Function<CTTextCharacterProperties, R> getter) {
+        // TODO Auto-generated method stub
+        return Optional.empty();
+    }
+
+}
index b44b3ae80e373da2aa33ca655a67e8ed381a55c7..dc1ef9f2eb2536d8b23df8ed5f529bcaf5a98fd5 100644 (file)
@@ -74,7 +74,7 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
     private XSSFGraphicFrame frame;
 
     @Deprecated
-    @Removal(version="4.2")
+    @Removal(version = "4.2")
     List<XSSFChartAxis> axis = new ArrayList<>();
 
     /**
@@ -89,7 +89,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
      * Construct a SpreadsheetML chart from a package part.
      *
      * @param part
-     *            the package part holding the chart data, the content type must be
+     *            the package part holding the chart data, the content type must
+     *            be
      *            <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code>
      *
      * @since POI 3.14-Beta1
@@ -114,7 +115,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
     }
 
     /**
-     * Construct a new CTChartSpace bean. By default, it's just an empty placeholder for chart objects.
+     * Construct a new CTChartSpace bean. By default, it's just an empty
+     * placeholder for chart objects.
      */
     private void createChart() {
         CTPlotArea plotArea = getCTPlotArea();
@@ -140,12 +142,15 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
         XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
 
         /*
-         * Saved chart space must have the following namespaces set: <c:chartSpace
+         * Saved chart space must have the following namespaces set:
+         * <c:chartSpace
          * xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"
-         * xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r=
+         * xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
+         * xmlns:r=
          * "http://schemas.openxmlformats.org/officeDocument/2006/relationships">
          */
-        xmlOptions.setSaveSyntheticDocumentElement(new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
+        xmlOptions.setSaveSyntheticDocumentElement(
+            new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
 
         PackagePart part = getPackagePart();
         try (OutputStream out = part.getOutputStream()) {
@@ -171,76 +176,76 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFChartDataFactory getChartDataFactory() {
-               return XSSFChartDataFactory.getInstance();
-       }
+    @Removal(version = "4.2")
+    public XSSFChartDataFactory getChartDataFactory() {
+        return XSSFChartDataFactory.getInstance();
+    }
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFChart getChartAxisFactory() {
-               return this;
-       }
+    @Removal(version = "4.2")
+    public XSSFChart getChartAxisFactory() {
+        return this;
+    }
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public void plot(ChartData data, ChartAxis... chartAxis) {
-               data.fillChart(this, chartAxis);
-       }
+    @Removal(version = "4.2")
+    public void plot(ChartData data, ChartAxis... chartAxis) {
+        data.fillChart(this, chartAxis);
+    }
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFValueAxis createValueAxis(org.apache.poi.ss.usermodel.charts.AxisPosition pos) {
-               long id = axis.size() + 1;
-               XSSFValueAxis valueAxis = new XSSFValueAxis(this, id, pos);
-               if (axis.size() == 1) {
-                       ChartAxis ax = axis.get(0);
-                       ax.crossAxis(valueAxis);
-                       valueAxis.crossAxis(ax);
-               }
-               axis.add(valueAxis);
-               return valueAxis;
-       }
+    @Removal(version = "4.2")
+    public XSSFValueAxis createValueAxis(org.apache.poi.ss.usermodel.charts.AxisPosition pos) {
+        long id = axis.size() + 1;
+        XSSFValueAxis valueAxis = new XSSFValueAxis(this, id, pos);
+        if (axis.size() == 1) {
+            ChartAxis ax = axis.get(0);
+            ax.crossAxis(valueAxis);
+            valueAxis.crossAxis(ax);
+        }
+        axis.add(valueAxis);
+        return valueAxis;
+    }
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFCategoryAxis createCategoryAxis(org.apache.poi.ss.usermodel.charts.AxisPosition pos) {
-               long id = axis.size() + 1;
-               XSSFCategoryAxis categoryAxis = new XSSFCategoryAxis(this, id, pos);
-               if (axis.size() == 1) {
-                       ChartAxis ax = axis.get(0);
-                       ax.crossAxis(categoryAxis);
-                       categoryAxis.crossAxis(ax);
-               }
-               axis.add(categoryAxis);
-               return categoryAxis;
-       }
+    @Removal(version = "4.2")
+    public XSSFCategoryAxis createCategoryAxis(org.apache.poi.ss.usermodel.charts.AxisPosition pos) {
+        long id = axis.size() + 1;
+        XSSFCategoryAxis categoryAxis = new XSSFCategoryAxis(this, id, pos);
+        if (axis.size() == 1) {
+            ChartAxis ax = axis.get(0);
+            ax.crossAxis(categoryAxis);
+            categoryAxis.crossAxis(ax);
+        }
+        axis.add(categoryAxis);
+        return categoryAxis;
+    }
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFDateAxis createDateAxis(org.apache.poi.ss.usermodel.charts.AxisPosition pos) {
-               long id = axis.size() + 1;
-               XSSFDateAxis dateAxis = new XSSFDateAxis(this, id, pos);
-               if (axis.size() == 1) {
-                       ChartAxis ax = axis.get(0);
-                       ax.crossAxis(dateAxis);
-                       dateAxis.crossAxis(ax);
-               }
-               axis.add(dateAxis);
-               return dateAxis;
-       }
+    @Removal(version = "4.2")
+    public XSSFDateAxis createDateAxis(org.apache.poi.ss.usermodel.charts.AxisPosition pos) {
+        long id = axis.size() + 1;
+        XSSFDateAxis dateAxis = new XSSFDateAxis(this, id, pos);
+        if (axis.size() == 1) {
+            ChartAxis ax = axis.get(0);
+            ax.crossAxis(dateAxis);
+            dateAxis.crossAxis(ax);
+        }
+        axis.add(dateAxis);
+        return dateAxis;
+    }
 
     /**
      * @deprecated use {@link #getAxes()} instead
      */
     @Override
     @Deprecated
-    @Removal(version="4.2")
+    @Removal(version = "4.2")
     public List<? extends XSSFChartAxis> getAxis() {
         if (axis.isEmpty() && hasAxis()) {
             parseAxis();
@@ -250,56 +255,57 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFManualLayout getManualLayout() {
-               return new XSSFManualLayout(this);
-       }
-
-       /**
-        * Returns the title static text, or null if none is set.
-        * Note that a title formula may be set instead.
-        * @return static title text, if set
-        * @deprecated POI 3.16, use {@link #getTitleText()} instead.
-        */
+    @Removal(version = "4.2")
+    public XSSFManualLayout getManualLayout() {
+        return new XSSFManualLayout(this);
+    }
+
+    /**
+     * Returns the title static text, or null if none is set. Note that a title
+     * formula may be set instead.
+     *
+     * @return static title text, if set
+     * @deprecated POI 3.16, use {@link #getTitleText()} instead.
+     */
     @Deprecated
-    @Removal(version="4.0")
-       public XSSFRichTextString getTitle() {
-           return getTitleText();
-       }
-
-       /**
-     * Returns the title static text, or null if none is set.
-     * Note that a title formula may be set instead.
-     * Empty text result is for backward compatibility, and could mean the title text is empty or there is a formula instead.
-     * Check for a formula first, falling back on text for cleaner logic.
-     * @return static title text if set,
-     *         null if there is no title,
-     *         empty string if the title text is empty or the title uses a formula instead
-        */
-       public XSSFRichTextString getTitleText() {
-               if(! chart.isSetTitle()) {
-                       return null;
-               }
-
-               // TODO Do properly
-               CTTitle title = chart.getTitle();
-
-               StringBuilder text = new StringBuilder(64);
-               XmlObject[] t = title
-                       .selectPath("declare namespace a='"+XSSFDrawing.NAMESPACE_A+"' .//a:t");
-               for (XmlObject element : t) {
-                       NodeList kids = element.getDomNode().getChildNodes();
-                       final int count = kids.getLength();
-                       for (int n = 0; n < count; n++) {
-                               Node kid = kids.item(n);
-                               if (kid instanceof Text) {
-                                       text.append(kid.getNodeValue());
-                               }
-                       }
-               }
-
-               return new XSSFRichTextString(text.toString());
-       }
+    @Removal(version = "4.0")
+    public XSSFRichTextString getTitle() {
+        return getTitleText();
+    }
+
+    /**
+     * Returns the title static text, or null if none is set. Note that a title
+     * formula may be set instead. Empty text result is for backward
+     * compatibility, and could mean the title text is empty or there is a
+     * formula instead. Check for a formula first, falling back on text for
+     * cleaner logic.
+     *
+     * @return static title text if set, null if there is no title, empty string
+     *         if the title text is empty or the title uses a formula instead
+     */
+    public XSSFRichTextString getTitleText() {
+        if (!chart.isSetTitle()) {
+            return null;
+        }
+
+        // TODO Do properly
+        CTTitle title = chart.getTitle();
+
+        StringBuilder text = new StringBuilder(64);
+        XmlObject[] t = title.selectPath("declare namespace a='" + XSSFDrawing.NAMESPACE_A + "' .//a:t");
+        for (XmlObject element : t) {
+            NodeList kids = element.getDomNode().getChildNodes();
+            final int count = kids.getLength();
+            for (int n = 0; n < count; n++) {
+                Node kid = kids.item(n);
+                if (kid instanceof Text) {
+                    text.append(kid.getNodeValue());
+                }
+            }
+        }
+
+        return new XSSFRichTextString(text.toString());
+    }
 
     /**
      * Sets the title text as a static string.
@@ -331,7 +337,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
             rich = tx.getRich();
         } else {
             rich = tx.addNewRich();
-            rich.addNewBodyPr(); // body properties must exist (but can be empty)
+            rich.addNewBodyPr(); // body properties must exist (but can be
+                                 // empty)
         }
 
         CTTextParagraph para;
@@ -414,21 +421,22 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
 
     @Override
     @Deprecated
-    @Removal(version="4.2")
-       public XSSFChartLegend getOrCreateLegend() {
-               return new XSSFChartLegend(this);
-       }
-
-       @Deprecated
-       @Removal(version="4.2")
-       private boolean hasAxis() {
+    @Removal(version = "4.2")
+    public XSSFChartLegend getOrCreateLegend() {
+        return new XSSFChartLegend(this);
+    }
+
+    @Deprecated
+    @Removal(version = "4.2")
+    private boolean hasAxis() {
         CTPlotArea ctPlotArea = chart.getPlotArea();
-        int totalAxisCount = ctPlotArea.sizeOfValAxArray() + ctPlotArea.sizeOfCatAxArray() + ctPlotArea.sizeOfDateAxArray() + ctPlotArea.sizeOfSerAxArray();
+        int totalAxisCount = ctPlotArea.sizeOfValAxArray() + ctPlotArea.sizeOfCatAxArray() + ctPlotArea
+            .sizeOfDateAxArray() + ctPlotArea.sizeOfSerAxArray();
         return totalAxisCount > 0;
-       }
+    }
 
     @Deprecated
-    @Removal(version="4.2")
+    @Removal(version = "4.2")
     private void parseAxis() {
         // TODO: add other axis types
         parseCategoryAxis();
@@ -437,7 +445,7 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
     }
 
     @Deprecated
-    @Removal(version="4.2")
+    @Removal(version = "4.2")
     private void parseCategoryAxis() {
         for (CTCatAx catAx : chart.getPlotArea().getCatAxArray()) {
             axis.add(new XSSFCategoryAxis(this, catAx));
@@ -445,7 +453,7 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
     }
 
     @Deprecated
-    @Removal(version="4.2")
+    @Removal(version = "4.2")
     private void parseDateAxis() {
         for (CTDateAx dateAx : chart.getPlotArea().getDateAxArray()) {
             axis.add(new XSSFDateAxis(this, dateAx));
@@ -453,7 +461,7 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
     }
 
     @Deprecated
-    @Removal(version="4.2")
+    @Removal(version = "4.2")
     private void parseValueAxis() {
         for (CTValAx valAx : chart.getPlotArea().getValAxArray()) {
             axis.add(new XSSFValueAxis(this, valAx));
index 31d5964c86fd4e2db705c3f0b0ffafe81f0932b5..96c7c9bcd3670cddab73fcf7a6b4f5b56bf655e7 100644 (file)
@@ -103,7 +103,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
         XSSFTextBox shape = new XSSFTextBox(getDrawing(), ctShape);
         shape.parent = this;
         shape.anchor = anchor;
-        shape.getCTShape().getSpPr().setXfrm(anchor.getCTTransform2D());
+        shape.setXfrm(anchor.getCTTransform2D());
         return shape;
 
     }
@@ -122,7 +122,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
         XSSFSimpleShape shape = new XSSFSimpleShape(getDrawing(), ctShape);
         shape.parent = this;
         shape.anchor = anchor;
-        shape.getCTShape().getSpPr().setXfrm(anchor.getCTTransform2D());
+        shape.setXfrm(anchor.getCTTransform2D());
         return shape;
     }
 
@@ -179,9 +179,9 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
         XSSFShapeGroup shape = new XSSFShapeGroup(getDrawing(), ctShape);
         shape.parent = this;
         shape.anchor = anchor;
-        
+
         // TODO: calculate bounding rectangle on anchor and set off/ext correctly
-        
+
         CTGroupTransform2D xfrm = shape.getCTGroupShape().getGrpSpPr().getXfrm();
         CTTransform2D t2 = anchor.getCTTransform2D();
         xfrm.setOff(t2.getOff());
@@ -190,7 +190,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
         xfrm.setChExt(t2.getExt());
         xfrm.setFlipH(t2.getFlipH());
         xfrm.setFlipV(t2.getFlipV());
-        
+
         return shape;
     }
 
@@ -220,6 +220,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
         chExt.setCy(y2);
     }
 
+    @Override
     protected CTShapeProperties getShapeProperties() {
         throw new IllegalStateException("Not supported for shape group");
     }
index 4696030ba666662f222de42942e96b0b57fc2242..b8ba72522c2f140b60c62baf31d9ca6153be60ae 100644 (file)
@@ -21,13 +21,44 @@ import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Optional;
+import java.util.function.Function;
 
 import org.apache.poi.hssf.util.HSSFColor;
 import org.apache.poi.ss.usermodel.SimpleShape;
 import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
-import org.apache.poi.util.Units;
-import org.openxmlformats.schemas.drawingml.x2006.main.*;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFColorRgbBinary;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xddf.usermodel.text.TextContainer;
+import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
+import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
+import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextHorzOverflowType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextVertOverflowType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
 import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt;
@@ -36,12 +67,17 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnderlineValues;
 
 /**
  * Represents a shape with a predefined geometry in a SpreadsheetML drawing.
- * Possible shape types are defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}
+ * Possible shape types are defined in
+ * {@link org.apache.poi.ss.usermodel.ShapeTypes}
  */
-public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph>, SimpleShape {
-       /**
-        * List of the paragraphs that make up the text in this shape
-        */
+public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph>, SimpleShape, TextContainer {
+    /**
+     * The text body containing the paragraphs for this shape.
+     */
+    private final XDDFTextBody _textBody;
+    /**
+     * List of the paragraphs that make up the text in this shape
+     */
     private final List<XSSFTextParagraph> _paragraphs;
     /**
      * A default instance of CTShape used for creating new shapes.
@@ -49,22 +85,26 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
     private static CTShape prototype;
 
     /**
-     *  Xml bean that stores properties of this shape
+     * Xml bean that stores properties of this shape
      */
     private CTShape ctShape;
 
     protected XSSFSimpleShape(XSSFDrawing drawing, CTShape ctShape) {
         this.drawing = drawing;
         this.ctShape = ctShape;
-        
+
         _paragraphs = new ArrayList<>();
-        
-        // initialize any existing paragraphs - this will be the default body paragraph in a new shape, 
+
+        // initialize any existing paragraphs - this will be the default body
+        // paragraph in a new shape,
         // or existing paragraphs that have been loaded from the file
         CTTextBody body = ctShape.getTxBody();
-        if(body != null) {
-            for(int i = 0; i < body.sizeOfPArray(); i++) {
-                _paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape));            
+        if (body == null) {
+            _textBody = null;
+        } else {
+            _textBody = new XDDFTextBody(this, body);
+            for (int i = 0; i < body.sizeOfPArray(); i++) {
+                _paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape));
             }
         }
     }
@@ -73,7 +113,7 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
      * Prototype with the default structure of a new auto-shape.
      */
     protected static CTShape prototype() {
-        if(prototype == null) {
+        if (prototype == null) {
             CTShape shape = CTShape.Factory.newInstance();
 
             CTShapeNonVisual nv = shape.addNewNvSpPr();
@@ -95,19 +135,12 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
             geom.setPrst(STShapeType.RECT);
             geom.addNewAvLst();
 
-            CTTextBody body = shape.addNewTxBody();
-            CTTextBodyProperties bodypr = body.addNewBodyPr();
-            bodypr.setAnchor(STTextAnchoringType.T);
-            bodypr.setRtlCol(false);
-            CTTextParagraph p = body.addNewP();
-            p.addNewPPr().setAlgn(STTextAlignType.L);
-            CTTextCharacterProperties endPr = p.addNewEndParaRPr();
-            endPr.setLang("en-US");
-            endPr.setSz(1100);   
-            CTSolidColorFillProperties scfpr = endPr.addNewSolidFill();
-            scfpr.addNewSrgbClr().setVal(new byte[] { 0, 0, 0 });
-                        
-            body.addNewLstStyle();
+            XDDFTextBody body = new XDDFTextBody(null, shape.addNewTxBody());
+            XDDFTextParagraph p = body.initialize();
+            XDDFRunProperties rp = p.getAfterLastRunProperties();
+            XDDFColor black = new XDDFColorRgbBinary(new byte[] { 0, 0, 0 });
+            XDDFFillProperties fp = new XDDFSolidFillProperties(black);
+            rp.setFillProperties(fp);
 
             prototype = shape;
         }
@@ -115,119 +148,147 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
     }
 
     @Internal
-    public CTShape getCTShape(){
+    public CTShape getCTShape() {
         return ctShape;
     }
 
+    @Beta
+    public XDDFTextBody getTextBody() {
+        return _textBody;
+    }
 
-    public Iterator<XSSFTextParagraph> iterator(){
+    protected void setXfrm(CTTransform2D t2d) {
+        ctShape.getSpPr().setXfrm(t2d);
+    }
+
+    @Override
+    public Iterator<XSSFTextParagraph> iterator() {
         return _paragraphs.iterator();
     }
 
     /**
-     * Returns the text from all paragraphs in the shape. Paragraphs are separated by new lines.
-     * 
-     * @return  text contained within this shape or empty string
+     * Returns the text from all paragraphs in the shape. Paragraphs are
+     * separated by new lines.
+     *
+     * @return text contained within this shape or empty string
      */
     public String getText() {
         final int MAX_LEVELS = 9;
         StringBuilder out = new StringBuilder();
-        List<Integer> levelCount = new ArrayList<>(MAX_LEVELS);        // maximum 9 levels
+        List<Integer> levelCount = new ArrayList<>(MAX_LEVELS); // maximum 9
+                                                                // levels
         XSSFTextParagraph p = null;
-        
-        // initialise the levelCount array - this maintains a record of the numbering to be used at each level
-        for (int k = 0; k < MAX_LEVELS; k++){
-               levelCount.add(0);
+
+        // initialise the levelCount array - this maintains a record of the
+        // numbering to be used at each level
+        for (int k = 0; k < MAX_LEVELS; k++) {
+            levelCount.add(0);
         }
 
-        for(int i = 0; i < _paragraphs.size(); i++) {
-            if (out.length() > 0) out.append('\n');
+        for (int i = 0; i < _paragraphs.size(); i++) {
+            if (out.length() > 0) {
+                out.append('\n');
+            }
             p = _paragraphs.get(i);
 
-            if(p.isBullet() && p.getText().length() > 0){
-               
+            if (p.isBullet() && p.getText().length() > 0) {
+
                 int level = Math.min(p.getLevel(), MAX_LEVELS - 1);
-                
-                if(p.isBulletAutoNumber()){
+
+                if (p.isBulletAutoNumber()) {
                     i = processAutoNumGroup(i, level, levelCount, out);
                 } else {
                     // indent appropriately for the level
-                    for(int j = 0; j < level; j++){
+                    for (int j = 0; j < level; j++) {
                         out.append('\t');
-                    }               
+                    }
                     String character = p.getBulletCharacter();
                     out.append(character.length() > 0 ? character + " " : "- ");
                     out.append(p.getText());
-                }               
+                }
             } else {
                 out.append(p.getText());
-                
+
                 // this paragraph is not a bullet, so reset the count array
-                for (int k = 0; k < MAX_LEVELS; k++){
+                for (int k = 0; k < MAX_LEVELS; k++) {
                     levelCount.set(k, 0);
                 }
-            }            
+            }
         }
 
         return out.toString();
     }
 
     /**
-     * 
+     *
      */
-    private int processAutoNumGroup(int index, int level, List<Integer> levelCount, StringBuilder out){
+    private int processAutoNumGroup(int index, int level, List<Integer> levelCount, StringBuilder out) {
         XSSFTextParagraph p = null;
         XSSFTextParagraph nextp = null;
         ListAutoNumber scheme, nextScheme;
         int startAt, nextStartAt;
-        
+
         p = _paragraphs.get(index);
-        
-        // The rules for generating the auto numbers are as follows. If the following paragraph is also
-        // an auto-number, has the same type/scheme (and startAt if defined on this paragraph) then they are
-        // considered part of the same group. An empty bullet paragraph is counted as part of the same
-        // group but does not increment the count for the group. A change of type, startAt or the paragraph
+
+        // The rules for generating the auto numbers are as follows. If the
+        // following paragraph is also
+        // an auto-number, has the same type/scheme (and startAt if defined on
+        // this paragraph) then they are
+        // considered part of the same group. An empty bullet paragraph is
+        // counted as part of the same
+        // group but does not increment the count for the group. A change of
+        // type, startAt or the paragraph
         // not being a bullet resets the count for that level to 1.
-        
-        // first auto-number paragraph so initialise to 1 or the bullets startAt if present
+
+        // first auto-number paragraph so initialise to 1 or the bullets startAt
+        // if present
         startAt = p.getBulletAutoNumberStart();
         scheme = p.getBulletAutoNumberScheme();
-        if(levelCount.get(level) == 0) {
+        if (levelCount.get(level) == 0) {
             levelCount.set(level, startAt == 0 ? 1 : startAt);
         }
         // indent appropriately for the level
-        for(int j = 0; j < level; j++){
+        for (int j = 0; j < level; j++) {
             out.append('\t');
         }
-        if (p.getText().length() > 0){
+        if (p.getText().length() > 0) {
             out.append(getBulletPrefix(scheme, levelCount.get(level)));
             out.append(p.getText());
         }
-        while(true) {                        
+        while (true) {
             nextp = (index + 1) == _paragraphs.size() ? null : _paragraphs.get(index + 1);
-            if(nextp == null) break; // out of paragraphs
-            if(!(nextp.isBullet() && p.isBulletAutoNumber())) break; // not an auto-number bullet                      
-            if(nextp.getLevel() > level) { 
+            if (nextp == null) {
+                break; // out of paragraphs
+            }
+            if (!(nextp.isBullet() && p.isBulletAutoNumber())) {
+                break; // not an auto-number bullet
+            }
+            if (nextp.getLevel() > level) {
                 // recurse into the new level group
-                if (out.length() > 0) out.append('\n');
+                if (out.length() > 0) {
+                    out.append('\n');
+                }
                 index = processAutoNumGroup(index + 1, nextp.getLevel(), levelCount, out);
                 continue; // restart the loop given the new index
-            } else if(nextp.getLevel() < level) {
-                break; // changed level   
+            } else if (nextp.getLevel() < level) {
+                break; // changed level
             }
             nextScheme = nextp.getBulletAutoNumberScheme();
             nextStartAt = nextp.getBulletAutoNumberStart();
-            
-            if(nextScheme == scheme && nextStartAt == startAt) {
-                // bullet is valid, so increment i 
+
+            if (nextScheme == scheme && nextStartAt == startAt) {
+                // bullet is valid, so increment i
                 ++index;
-                if (out.length() > 0) out.append('\n');
+                if (out.length() > 0) {
+                    out.append('\n');
+                }
                 // indent for the level
-                for(int j = 0; j < level; j++){
+                for (int j = 0; j < level; j++) {
                     out.append('\t');
                 }
-                // check for empty text - only output a bullet if there is text, but it is still part of the group
-                if(nextp.getText().length() > 0) {
+                // check for empty text - only output a bullet if there is text,
+                // but it is still part of the group
+                if (nextp.getText().length() > 0) {
                     // increment the count for this level
                     levelCount.set(level, levelCount.get(level) + 1);
                     out.append(getBulletPrefix(nextScheme, levelCount.get(level)));
@@ -235,36 +296,45 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
                 }
             } else {
                 // something doesn't match so stop
-                break; 
+                break;
             }
         }
-        // end of the group so reset the count for this level 
-        levelCount.set(level, 0);      
-        
-        return index; 
+        // end of the group so reset the count for this level
+        levelCount.set(level, 0);
+
+        return index;
     }
+
     /**
-     * Returns a string containing an appropriate prefix for an auto-numbering bullet
-     * @param scheme the auto-numbering scheme used by the bullet
-     * @param value the value of the bullet
+     * Returns a string containing an appropriate prefix for an auto-numbering
+     * bullet
+     *
+     * @param scheme
+     *            the auto-numbering scheme used by the bullet
+     * @param value
+     *            the value of the bullet
      * @return appropriate prefix for an auto-numbering bullet
      */
-    private String getBulletPrefix(ListAutoNumber scheme, int value){
+    private String getBulletPrefix(ListAutoNumber scheme, int value) {
         StringBuilder out = new StringBuilder();
-        
-        switch(scheme) {
+
+        switch (scheme) {
         case ALPHA_LC_PARENT_BOTH:
         case ALPHA_LC_PARENT_R:
-            if(scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) out.append('(');
+            if (scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) {
+                out.append('(');
+            }
             out.append(valueToAlpha(value).toLowerCase(Locale.ROOT));
             out.append(')');
             break;
         case ALPHA_UC_PARENT_BOTH:
         case ALPHA_UC_PARENT_R:
-            if(scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) out.append('(');
+            if (scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) {
+                out.append('(');
+            }
             out.append(valueToAlpha(value));
             out.append(')');
-            break;        
+            break;
         case ALPHA_LC_PERIOD:
             out.append(valueToAlpha(value).toLowerCase(Locale.ROOT));
             out.append('.');
@@ -275,7 +345,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
             break;
         case ARABIC_PARENT_BOTH:
         case ARABIC_PARENT_R:
-            if(scheme == ListAutoNumber.ARABIC_PARENT_BOTH) out.append('(');
+            if (scheme == ListAutoNumber.ARABIC_PARENT_BOTH) {
+                out.append('(');
+            }
             out.append(value);
             out.append(')');
             break;
@@ -285,19 +357,23 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
             break;
         case ARABIC_PLAIN:
             out.append(value);
-            break;            
+            break;
         case ROMAN_LC_PARENT_BOTH:
         case ROMAN_LC_PARENT_R:
-            if(scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) out.append('(');
+            if (scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) {
+                out.append('(');
+            }
             out.append(valueToRoman(value).toLowerCase(Locale.ROOT));
             out.append(')');
             break;
         case ROMAN_UC_PARENT_BOTH:
         case ROMAN_UC_PARENT_R:
-            if(scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) out.append('(');
+            if (scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) {
+                out.append('(');
+            }
             out.append(valueToRoman(value));
             out.append(')');
-            break;        
+            break;
         case ROMAN_LC_PERIOD:
             out.append(valueToRoman(value).toLowerCase(Locale.ROOT));
             out.append('.');
@@ -307,13 +383,14 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
             out.append('.');
             break;
         default:
-            out.append('\u2022');   // can't set the font to wingdings so use the default bullet character
-            break;            
+            out.append('\u2022'); // can't set the font to wingdings so use the
+                                  // default bullet character
+            break;
         }
-        out.append(" ");        
+        out.append(" ");
         return out.toString();
     }
-    
+
     /**
      * Convert an integer to its alpha equivalent e.g. 1 = A, 2 = B, 27 = AA etc
      */
@@ -322,59 +399,66 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
         int modulo;
         while (value > 0) {
             modulo = (value - 1) % 26;
-            alpha = (char)(65 + modulo) + alpha;
+            alpha = (char) (65 + modulo) + alpha;
             value = (value - modulo) / 26;
         }
         return alpha;
     }
-    
-    private static String[] _romanChars = new String[] { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" };
-    private static int[] _romanAlphaValues = new int[] { 1000,900,500,400,100,90,50,40,10,9,5,4,1 };
-        
+
+    private static String[] _romanChars = new String[] { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V",
+            "IV", "I" };
+    private static int[] _romanAlphaValues = new int[] { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
+
     /**
      * Convert an integer to its roman equivalent e.g. 1 = I, 9 = IX etc
      */
     private String valueToRoman(int value) {
         StringBuilder out = new StringBuilder();
-        for(int i = 0; value > 0 && i < _romanChars.length; i++) {
-            while(_romanAlphaValues[i] <= value) {
+        for (int i = 0; value > 0 && i < _romanChars.length; i++) {
+            while (_romanAlphaValues[i] <= value) {
                 out.append(_romanChars[i]);
                 value -= _romanAlphaValues[i];
             }
         }
         return out.toString();
     }
-    
+
     /**
      * Clear all text from this shape
      */
-    public void clearText(){
+    public void clearText() {
         _paragraphs.clear();
         CTTextBody txBody = ctShape.getTxBody();
         txBody.setPArray(null); // remove any existing paragraphs
     }
-    
+
     /**
-     * Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
-     * @param text     string representing the paragraph text
+     * Set a single paragraph of text on the shape. Note this will replace all
+     * existing paragraphs created on the shape.
+     *
+     * @param text
+     *            string representing the paragraph text
      */
-    public void setText(String text){
+    public void setText(String text) {
         clearText();
 
         addNewTextParagraph().addNewTextRun().setText(text);
     }
 
     /**
-     * Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape.
-     * @param str      rich text string representing the paragraph text
+     * Set a single paragraph of text on the shape. Note this will replace all
+     * existing paragraphs created on the shape.
+     *
+     * @param str
+     *            rich text string representing the paragraph text
      */
-    public void setText(XSSFRichTextString str){
+    public void setText(XSSFRichTextString str) {
 
-        XSSFWorkbook wb = (XSSFWorkbook)getDrawing().getParent().getParent();
+        XSSFWorkbook wb = (XSSFWorkbook) getDrawing().getParent().getParent();
         str.setStylesTableReference(wb.getStylesSource());
 
         CTTextParagraph p = CTTextParagraph.Factory.newInstance();
-        if(str.numFormattingRuns() == 0){
+        if (str.numFormattingRuns() == 0) {
             CTRegularTextRun r = p.addNewR();
             CTTextCharacterProperties rPr = r.addNewRPr();
             rPr.setLang("en-US");
@@ -385,7 +469,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
             for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
                 CTRElt lt = str.getCTRst().getRArray(i);
                 CTRPrElt ltPr = lt.getRPr();
-                if(ltPr == null) ltPr = lt.addNewRPr();
+                if (ltPr == null) {
+                    ltPr = lt.addNewRPr();
+                }
 
                 CTRegularTextRun r = p.addNewR();
                 CTTextCharacterProperties rPr = r.addNewRPr();
@@ -396,15 +482,16 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
                 r.setT(lt.getT());
             }
         }
-        
-        clearText();                
-        ctShape.getTxBody().setPArray(new CTTextParagraph[]{p});
+
+        clearText();
+        ctShape.getTxBody().setPArray(new CTTextParagraph[] { p });
         _paragraphs.add(new XSSFTextParagraph(ctShape.getTxBody().getPArray(0), ctShape));
-    }    
-    
+    }
+
     /**
-     * Returns a collection of the XSSFTextParagraphs that are attached to this shape
-     * 
+     * Returns a collection of the XSSFTextParagraphs that are attached to this
+     * shape
+     *
      * @return text paragraphs in this shape
      */
     public List<XSSFTextParagraph> getTextParagraphs() {
@@ -422,7 +509,7 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
         XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
         _paragraphs.add(paragraph);
         return paragraph;
-    }    
+    }
 
     /**
      * Add a new paragraph run to this shape, set to the provided string
@@ -433,18 +520,19 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
         XSSFTextParagraph paragraph = addNewTextParagraph();
         paragraph.addNewTextRun().setText(text);
         return paragraph;
-    }   
-    
+    }
+
     /**
-     * Add a new paragraph run to this shape, set to the provided rich text string 
+     * Add a new paragraph run to this shape, set to the provided rich text
+     * string
      *
      * @return created paragraph run
      */
     public XSSFTextParagraph addNewTextParagraph(XSSFRichTextString str) {
         CTTextBody txBody = ctShape.getTxBody();
         CTTextParagraph p = txBody.addNewP();
-       
-        if(str.numFormattingRuns() == 0){
+
+        if (str.numFormattingRuns() == 0) {
             CTRegularTextRun r = p.addNewR();
             CTTextCharacterProperties rPr = r.addNewRPr();
             rPr.setLang("en-US");
@@ -455,7 +543,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
             for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
                 CTRElt lt = str.getCTRst().getRArray(i);
                 CTRPrElt ltPr = lt.getRPr();
-                if(ltPr == null) ltPr = lt.addNewRPr();
+                if (ltPr == null) {
+                    ltPr = lt.addNewRPr();
+                }
 
                 CTRegularTextRun r = p.addNewR();
                 CTTextCharacterProperties rPr = r.addNewRPr();
@@ -466,25 +556,29 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
                 r.setT(lt.getT());
             }
         }
-        
-        // Note: the XSSFTextParagraph constructor will create its required XSSFTextRuns from the provided CTTextParagraph
+
+        // Note: the XSSFTextParagraph constructor will create its required
+        // XSSFTextRuns from the provided CTTextParagraph
         XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
         _paragraphs.add(paragraph);
-        
+
         return paragraph;
     }
 
     /**
      * Sets the type of horizontal overflow for the text.
      *
-     * @param overflow - the type of horizontal overflow.
-     * A <code>null</code> values unsets this property.
+     * @param overflow
+     *            - the type of horizontal overflow. A <code>null</code> values
+     *            unsets this property.
      */
-    public void setTextHorizontalOverflow(TextHorizontalOverflow overflow){
+    public void setTextHorizontalOverflow(TextHorizontalOverflow overflow) {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-             if(overflow == null) {
-                if(bodyPr.isSetHorzOverflow()) bodyPr.unsetHorzOverflow();
+            if (overflow == null) {
+                if (bodyPr.isSetHorzOverflow()) {
+                    bodyPr.unsetHorzOverflow();
+                }
             } else {
                 bodyPr.setHorzOverflow(STTextHorzOverflowType.Enum.forInt(overflow.ordinal() + 1));
             }
@@ -496,27 +590,30 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
      *
      * @return the type of horizontal overflow
      */
-    public TextHorizontalOverflow getTextHorizontalOverflow(){
-       CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-       if(bodyPr != null) {
-               if(bodyPr.isSetHorzOverflow()){
-                       return TextHorizontalOverflow.values()[bodyPr.getHorzOverflow().intValue() - 1];
-               }                       
-       }
-       return TextHorizontalOverflow.OVERFLOW;
-    }    
-    
+    public TextHorizontalOverflow getTextHorizontalOverflow() {
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if (bodyPr.isSetHorzOverflow()) {
+                return TextHorizontalOverflow.values()[bodyPr.getHorzOverflow().intValue() - 1];
+            }
+        }
+        return TextHorizontalOverflow.OVERFLOW;
+    }
+
     /**
      * Sets the type of vertical overflow for the text.
      *
-     * @param overflow - the type of vertical overflow.
-     * A <code>null</code> values unsets this property.
+     * @param overflow
+     *            - the type of vertical overflow. A <code>null</code> values
+     *            unsets this property.
      */
-    public void setTextVerticalOverflow(TextVerticalOverflow overflow){
+    public void setTextVerticalOverflow(TextVerticalOverflow overflow) {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-             if(overflow == null) {
-                if(bodyPr.isSetVertOverflow()) bodyPr.unsetVertOverflow();
+            if (overflow == null) {
+                if (bodyPr.isSetVertOverflow()) {
+                    bodyPr.unsetVertOverflow();
+                }
             } else {
                 bodyPr.setVertOverflow(STTextVertOverflowType.Enum.forInt(overflow.ordinal() + 1));
             }
@@ -528,27 +625,30 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
      *
      * @return the type of vertical overflow
      */
-    public TextVerticalOverflow getTextVerticalOverflow(){
-       CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-       if(bodyPr != null) {
-               if(bodyPr.isSetVertOverflow()){
-                       return TextVerticalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
-               }                       
-       }
-       return TextVerticalOverflow.OVERFLOW;
-    }   
-    
+    public TextVerticalOverflow getTextVerticalOverflow() {
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if (bodyPr.isSetVertOverflow()) {
+                return TextVerticalOverflow.values()[bodyPr.getVertOverflow().intValue() - 1];
+            }
+        }
+        return TextVerticalOverflow.OVERFLOW;
+    }
+
     /**
      * Sets the type of vertical alignment for the text within the shape.
      *
-     * @param anchor - the type of alignment.
-     * A <code>null</code> values unsets this property.
+     * @param anchor
+     *            - the type of alignment. A <code>null</code> values unsets
+     *            this property.
      */
-    public void setVerticalAlignment(VerticalAlignment anchor){
+    public void setVerticalAlignment(VerticalAlignment anchor) {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-             if(anchor == null) {
-                if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor();
+            if (anchor == null) {
+                if (bodyPr.isSetAnchor()) {
+                    bodyPr.unsetAnchor();
+                }
             } else {
                 bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
             }
@@ -560,27 +660,30 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
      *
      * @return the type of vertical alignment
      */
-    public VerticalAlignment getVerticalAlignment(){
-       CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-       if(bodyPr != null) {
-               if(bodyPr.isSetAnchor()){
-                       return VerticalAlignment.values()[bodyPr.getAnchor().intValue() - 1];
-               }                       
-       }
-       return VerticalAlignment.TOP;
+    public VerticalAlignment getVerticalAlignment() {
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+        if (bodyPr != null) {
+            if (bodyPr.isSetAnchor()) {
+                return VerticalAlignment.values()[bodyPr.getAnchor().intValue() - 1];
+            }
+        }
+        return VerticalAlignment.TOP;
     }
 
     /**
      * Sets the vertical orientation of the text
-     * 
-     * @param orientation vertical orientation of the text
-     * A <code>null</code> values unsets this property.
+     *
+     * @param orientation
+     *            vertical orientation of the text A <code>null</code> values
+     *            unsets this property.
      */
-    public void setTextDirection(TextDirection orientation){
+    public void setTextDirection(TextDirection orientation) {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-            if(orientation == null) {
-                if(bodyPr.isSetVert()) bodyPr.unsetVert();
+            if (orientation == null) {
+                if (bodyPr.isSetVert()) {
+                    bodyPr.unsetVert();
+                }
             } else {
                 bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
             }
@@ -589,170 +692,174 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
 
     /**
      * Gets the vertical orientation of the text
-     * 
+     *
      * @return vertical orientation of the text
      */
-    public TextDirection getTextDirection(){
+    public TextDirection getTextDirection() {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
             STTextVerticalType.Enum val = bodyPr.getVert();
-            if(val != null){
+            if (val != null) {
                 return TextDirection.values()[val.intValue() - 1];
             }
         }
         return TextDirection.HORIZONTAL;
     }
 
-
     /**
-     * Returns the distance (in points) between the bottom of the text frame
-     * and the bottom of the inscribed rectangle of the shape that contains the text.
+     * Returns the distance (in points) between the bottom of the text frame and
+     * the bottom of the inscribed rectangle of the shape that contains the
+     * text.
      *
      * @return the bottom inset in points
      */
-    public double getBottomInset(){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-               if(bodyPr.isSetBIns()){
-                       return Units.toPoints(bodyPr.getBIns());
-               }
+    public double getBottomInset() {
+        Double inset = _textBody.getBodyProperties().getBottomInset();
+        if (inset == null) {
+            // If this attribute is omitted, then a value of 0.05 inches is
+            // implied
+            return 3.6;
+        } else {
+            return inset;
         }
-        // If this attribute is omitted, then a value of 0.05 inches is implied
-        return 3.6;    
     }
 
     /**
-     *  Returns the distance (in points) between the left edge of the text frame
-     *  and the left edge of the inscribed rectangle of the shape that contains
-     *  the text.
+     * Returns the distance (in points) between the left edge of the text frame
+     * and the left edge of the inscribed rectangle of the shape that contains
+     * the text.
      *
      * @return the left inset in points
      */
-    public double getLeftInset(){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-               if(bodyPr.isSetLIns()){
-                       return Units.toPoints(bodyPr.getLIns());
-               }
+    public double getLeftInset() {
+        Double inset = _textBody.getBodyProperties().getLeftInset();
+        if (inset == null) {
+            // If this attribute is omitted, then a value of 0.05 inches is
+            // implied
+            return 3.6;
+        } else {
+            return inset;
         }
-        // If this attribute is omitted, then a value of 0.05 inches is implied
-        return 3.6;
     }
 
     /**
-     *  Returns the distance (in points) between the right edge of the
-     *  text frame and the right edge of the inscribed rectangle of the shape
-     *  that contains the text.
+     * Returns the distance (in points) between the right edge of the text frame
+     * and the right edge of the inscribed rectangle of the shape that contains
+     * the text.
      *
      * @return the right inset in points
      */
-    public double getRightInset(){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-               if(bodyPr.isSetRIns()){
-                       return Units.toPoints(bodyPr.getRIns());
-               }
+    public double getRightInset() {
+        Double inset = _textBody.getBodyProperties().getRightInset();
+        if (inset == null) {
+            // If this attribute is omitted, then a value of 0.05 inches is
+            // implied
+            return 3.6;
+        } else {
+            return inset;
         }
-        // If this attribute is omitted, then a value of 0.05 inches is implied
-        return 3.6;
     }
 
     /**
-     *  Returns the distance (in points) between the top of the text frame
-     *  and the top of the inscribed rectangle of the shape that contains the text.
+     * Returns the distance (in points) between the top of the text frame and
+     * the top of the inscribed rectangle of the shape that contains the text.
      *
      * @return the top inset in points
      */
-    public double getTopInset(){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-               if(bodyPr.isSetTIns()){
-                       return Units.toPoints(bodyPr.getTIns());
-               }
+    public double getTopInset() {
+        Double inset = _textBody.getBodyProperties().getTopInset();
+        if (inset == null) {
+            // If this attribute is omitted, then a value of 0.05 inches is
+            // implied
+            return 3.6;
+        } else {
+            return inset;
         }
-        // If this attribute is omitted, then a value of 0.05 inches is implied
-        return 3.6;            
     }
 
     /**
      * Sets the bottom inset.
+     *
      * @see #getBottomInset()
      *
-     * @param margin    the bottom margin
+     * @param margin
+     *            the bottom margin
      */
-    public void setBottomInset(double margin){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-            if(margin == -1) {
-                if(bodyPr.isSetBIns()) bodyPr.unsetBIns();
-            } else bodyPr.setBIns(Units.toEMU(margin));
+    public void setBottomInset(double margin) {
+        if (margin == -1) {
+            _textBody.getBodyProperties().setBottomInset(null);
+        } else {
+            _textBody.getBodyProperties().setBottomInset(margin);
         }
     }
 
     /**
      * Sets the left inset.
+     *
      * @see #getLeftInset()
      *
-     * @param margin    the left margin
+     * @param margin
+     *            the left margin
      */
-    public void setLeftInset(double margin){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-            if(margin == -1) {
-                if(bodyPr.isSetLIns()) bodyPr.unsetLIns();
-            } else bodyPr.setLIns(Units.toEMU(margin));
+    public void setLeftInset(double margin) {
+        if (margin == -1) {
+            _textBody.getBodyProperties().setLeftInset(null);
+        } else {
+            _textBody.getBodyProperties().setLeftInset(margin);
         }
     }
 
     /**
      * Sets the right inset.
+     *
      * @see #getRightInset()
      *
-     * @param margin    the right margin
+     * @param margin
+     *            the right margin
      */
-    public void setRightInset(double margin){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-            if(margin == -1) {
-                if(bodyPr.isSetRIns()) bodyPr.unsetRIns();
-            } else bodyPr.setRIns(Units.toEMU(margin));
+    public void setRightInset(double margin) {
+        if (margin == -1) {
+            _textBody.getBodyProperties().setRightInset(null);
+        } else {
+            _textBody.getBodyProperties().setRightInset(margin);
         }
     }
 
     /**
      * Sets the top inset.
+     *
      * @see #getTopInset()
      *
-     * @param margin    the top margin
+     * @param margin
+     *            the top margin
      */
-    public void setTopInset(double margin){
-        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
-        if (bodyPr != null) {
-            if(margin == -1) {
-                if(bodyPr.isSetTIns()) bodyPr.unsetTIns();
-            } else bodyPr.setTIns(Units.toEMU(margin));
+    public void setTopInset(double margin) {
+        if (margin == -1) {
+            _textBody.getBodyProperties().setTopInset(null);
+        } else {
+            _textBody.getBodyProperties().setTopInset(margin);
         }
     }
 
-
     /**
      * @return whether to wrap words within the bounding rectangle
      */
-    public boolean getWordWrap(){
-       CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
+    public boolean getWordWrap() {
+        CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-               if(bodyPr.isSetWrap()){
-                       return bodyPr.getWrap() == STTextWrappingType.SQUARE;
-               }
+            if (bodyPr.isSetWrap()) {
+                return bodyPr.getWrap() == STTextWrappingType.SQUARE;
+            }
         }
         return true;
     }
 
     /**
      *
-     * @param wrap  whether to wrap words within the bounding rectangle
+     * @param wrap
+     *            whether to wrap words within the bounding rectangle
      */
-    public void setWordWrap(boolean wrap){
+    public void setWordWrap(boolean wrap) {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
             bodyPr.setWrap(wrap ? STTextWrappingType.SQUARE : STTextWrappingType.NONE);
@@ -761,22 +868,36 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
 
     /**
      *
-     * Specifies that a shape should be auto-fit to fully contain the text described within it.
-     * Auto-fitting is when text within a shape is scaled in order to contain all the text inside
+     * Specifies that a shape should be auto-fit to fully contain the text
+     * described within it. Auto-fitting is when text within a shape is scaled
+     * in order to contain all the text inside
      *
-     * @param value type of autofit
+     * @param value
+     *            type of autofit
      */
-    public void setTextAutofit(TextAutofit value){
+    public void setTextAutofit(TextAutofit value) {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-            if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit();
-            if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit();
-            if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit();
-
-            switch(value){
-                case NONE: bodyPr.addNewNoAutofit(); break;
-                case NORMAL: bodyPr.addNewNormAutofit(); break;
-                case SHAPE: bodyPr.addNewSpAutoFit(); break;
+            if (bodyPr.isSetSpAutoFit()) {
+                bodyPr.unsetSpAutoFit();
+            }
+            if (bodyPr.isSetNoAutofit()) {
+                bodyPr.unsetNoAutofit();
+            }
+            if (bodyPr.isSetNormAutofit()) {
+                bodyPr.unsetNormAutofit();
+            }
+
+            switch (value) {
+            case NONE:
+                bodyPr.addNewNoAutofit();
+                break;
+            case NORMAL:
+                bodyPr.addNewNormAutofit();
+                break;
+            case SHAPE:
+                bodyPr.addNewSpAutoFit();
+                break;
             }
         }
     }
@@ -785,18 +906,23 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
      *
      * @return type of autofit
      */
-    public TextAutofit getTextAutofit(){
+    public TextAutofit getTextAutofit() {
         CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
         if (bodyPr != null) {
-            if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE;
-            else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL;
-            else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE;
+            if (bodyPr.isSetNoAutofit()) {
+                return TextAutofit.NONE;
+            } else if (bodyPr.isSetNormAutofit()) {
+                return TextAutofit.NORMAL;
+            } else if (bodyPr.isSetSpAutoFit()) {
+                return TextAutofit.SHAPE;
+            }
         }
         return TextAutofit.NORMAL;
     }
-    
+
     /**
-     * Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
+     * Gets the shape type, one of the constants defined in
+     * {@link org.apache.poi.ss.usermodel.ShapeTypes}.
      *
      * @return the shape type
      * @see org.apache.poi.ss.usermodel.ShapeTypes
@@ -808,14 +934,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
     /**
      * Sets the shape types.
      *
-     * @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}.
+     * @param type
+     *            the shape type, one of the constants defined in
+     *            {@link org.apache.poi.ss.usermodel.ShapeTypes}.
      * @see org.apache.poi.ss.usermodel.ShapeTypes
      */
     public void setShapeType(int type) {
         ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
     }
 
-    protected CTShapeProperties getShapeProperties(){
+    @Override
+    protected CTShapeProperties getShapeProperties() {
         return ctShape.getSpPr();
     }
 
@@ -823,35 +952,42 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
      * org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt to
      * org.openxmlformats.schemas.drawingml.x2006.main.CTFont adapter
      */
-    private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr){
+    private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr) {
 
-        if(pr.sizeOfBArray() > 0) rPr.setB(pr.getBArray(0).getVal());
-        if(pr.sizeOfUArray() > 0) {
+        if (pr.sizeOfBArray() > 0) {
+            rPr.setB(pr.getBArray(0).getVal());
+        }
+        if (pr.sizeOfUArray() > 0) {
             STUnderlineValues.Enum u1 = pr.getUArray(0).getVal();
-            if(u1 == STUnderlineValues.SINGLE) rPr.setU(STTextUnderlineType.SNG);
-            else if(u1 == STUnderlineValues.DOUBLE) rPr.setU(STTextUnderlineType.DBL);
-            else if(u1 == STUnderlineValues.NONE) rPr.setU(STTextUnderlineType.NONE);
+            if (u1 == STUnderlineValues.SINGLE) {
+                rPr.setU(STTextUnderlineType.SNG);
+            } else if (u1 == STUnderlineValues.DOUBLE) {
+                rPr.setU(STTextUnderlineType.DBL);
+            } else if (u1 == STUnderlineValues.NONE) {
+                rPr.setU(STTextUnderlineType.NONE);
+            }
+        }
+        if (pr.sizeOfIArray() > 0) {
+            rPr.setI(pr.getIArray(0).getVal());
         }
-        if(pr.sizeOfIArray() > 0) rPr.setI(pr.getIArray(0).getVal());
 
-        if(pr.sizeOfRFontArray() > 0) {
+        if (pr.sizeOfRFontArray() > 0) {
             CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
             rFont.setTypeface(pr.getRFontArray(0).getVal());
         }
 
-        if(pr.sizeOfSzArray() > 0) {
-            int sz = (int)(pr.getSzArray(0).getVal()*100);
+        if (pr.sizeOfSzArray() > 0) {
+            int sz = (int) (pr.getSzArray(0).getVal() * 100);
             rPr.setSz(sz);
         }
-        
-        if(pr.sizeOfColorArray() > 0) {
+
+        if (pr.sizeOfColorArray() > 0) {
             CTSolidColorFillProperties fill = rPr.isSetSolidFill() ? rPr.getSolidFill() : rPr.addNewSolidFill();
             org.openxmlformats.schemas.spreadsheetml.x2006.main.CTColor xlsColor = pr.getColorArray(0);
-            if(xlsColor.isSetRgb()) {
+            if (xlsColor.isSetRgb()) {
                 CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
                 clr.setVal(xlsColor.getRgb());
-            }
-            else if(xlsColor.isSetIndexed()) {
+            } else if (xlsColor.isSetIndexed()) {
                 HSSFColor indexed = HSSFColor.getIndexHash().get((int) xlsColor.getIndexed());
                 if (indexed != null) {
                     byte[] rgb = new byte[3];
@@ -872,6 +1008,20 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
 
     @Override
     public int getShapeId() {
-        return (int)ctShape.getNvSpPr().getCNvPr().getId();
+        return (int) ctShape.getNvSpPr().getCNvPr().getId();
+    }
+
+    @Override
+    public <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
+        Function<CTTextParagraphProperties, R> getter) {
+        // TODO Auto-generated method stub
+        return Optional.empty();
+    }
+
+    @Override
+    public <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
+        Function<CTTextCharacterProperties, R> getter) {
+        // TODO Auto-generated method stub
+        return Optional.empty();
     }
 }
diff --git a/src/ooxml/testcases/org/apache/poi/xddf/usermodel/text/TestXDDFTextBodyProperties.java b/src/ooxml/testcases/org/apache/poi/xddf/usermodel/text/TestXDDFTextBodyProperties.java
new file mode 100644 (file)
index 0000000..3b137d6
--- /dev/null
@@ -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.xddf.usermodel.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.apache.poi.util.Units;
+import org.junit.Test;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
+
+public class TestXDDFTextBodyProperties {
+
+    @Test
+    public void testProperties() throws IOException {
+        XDDFBodyProperties body = new XDDFTextBody(null).getBodyProperties();
+        CTTextBodyProperties props = body.getXmlObject();
+
+        body.setBottomInset(null);
+        assertFalse(props.isSetBIns());
+        body.setBottomInset(3.6);
+        assertTrue(props.isSetBIns());
+        assertEquals(Units.toEMU(3.6), props.getBIns());
+
+        body.setLeftInset(null);
+        assertFalse(props.isSetLIns());
+        body.setLeftInset(3.6);
+        assertTrue(props.isSetLIns());
+        assertEquals(Units.toEMU(3.6), props.getLIns());
+
+        body.setRightInset(null);
+        assertFalse(props.isSetRIns());
+        body.setRightInset(3.6);
+        assertTrue(props.isSetRIns());
+        assertEquals(Units.toEMU(3.6), props.getRIns());
+
+        body.setTopInset(null);
+        assertFalse(props.isSetTIns());
+        body.setTopInset(3.6);
+        assertTrue(props.isSetTIns());
+        assertEquals(Units.toEMU(3.6), props.getTIns());
+
+        body.setAutoFit(null);
+        assertFalse(props.isSetNoAutofit());
+        assertFalse(props.isSetNormAutofit());
+        assertFalse(props.isSetSpAutoFit());
+
+        body.setAutoFit(new XDDFNoAutoFit());
+        assertTrue(props.isSetNoAutofit());
+        assertFalse(props.isSetNormAutofit());
+        assertFalse(props.isSetSpAutoFit());
+
+        body.setAutoFit(new XDDFNormalAutoFit());
+        assertFalse(props.isSetNoAutofit());
+        assertTrue(props.isSetNormAutofit());
+        assertFalse(props.isSetSpAutoFit());
+
+        body.setAutoFit(new XDDFShapeAutoFit());
+        assertFalse(props.isSetNoAutofit());
+        assertFalse(props.isSetNormAutofit());
+        assertTrue(props.isSetSpAutoFit());
+
+    }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/xddf/usermodel/text/TestXDDFTextRun.java b/src/ooxml/testcases/org/apache/poi/xddf/usermodel/text/TestXDDFTextRun.java
new file mode 100644 (file)
index 0000000..67d509f
--- /dev/null
@@ -0,0 +1,135 @@
+/* ====================================================================
+   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.xddf.usermodel.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.xslf.usermodel.XMLSlideShow;
+import org.apache.poi.xslf.usermodel.XSLFSlide;
+import org.apache.poi.xslf.usermodel.XSLFTextShape;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFTextBox;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.junit.Test;
+
+public class TestXDDFTextRun {
+
+    @Test
+    public void testTextRunPropertiesInSlide() throws IOException {
+        try (XMLSlideShow ppt = new XMLSlideShow()) {
+            XSLFSlide slide = ppt.createSlide();
+            XSLFTextShape sh = slide.createAutoShape();
+            sh.addNewTextParagraph();
+
+            XDDFTextBody body = sh.getTextBody();
+            XDDFTextParagraph para = body.getParagraph(0);
+            XDDFTextRun r = para.appendRegularRun("text");
+            assertEquals(LocaleUtil.getUserLocale().toLanguageTag(), r.getLanguage().toLanguageTag());
+
+            assertNull(r.getCharacterSpacing());
+            r.setCharacterSpacing(3.0);
+            assertEquals(3., r.getCharacterSpacing(), 0);
+            r.setCharacterSpacing(-3.0);
+            assertEquals(-3., r.getCharacterSpacing(), 0);
+            r.setCharacterSpacing(0.0);
+            assertEquals(0., r.getCharacterSpacing(), 0);
+
+            assertEquals(11.0, r.getFontSize(), 0);
+            r.setFontSize(13.0);
+            assertEquals(13.0, r.getFontSize(), 0);
+
+            assertFalse(r.isSuperscript());
+            r.setSuperscript(0.8);
+            assertTrue(r.isSuperscript());
+            r.setSuperscript(null);
+            assertFalse(r.isSuperscript());
+
+            assertFalse(r.isSubscript());
+            r.setSubscript(0.7);
+            assertTrue(r.isSubscript());
+            r.setSubscript(null);
+            assertFalse(r.isSubscript());
+
+            r.setBaseline(0.9);
+            assertTrue(r.isSuperscript());
+            r.setBaseline(-0.6);
+            assertTrue(r.isSubscript());
+        }
+    }
+
+    @Test
+    public void testTextRunPropertiesInSheet() throws IOException {
+        try (XSSFWorkbook wb = new XSSFWorkbook()) {
+            XSSFSheet sheet = wb.createSheet();
+            XSSFDrawing drawing = sheet.createDrawingPatriarch();
+
+            XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
+
+            shape.addNewTextParagraph().addNewTextRun().setText("Line 1");
+
+            XDDFTextBody body = shape.getTextBody();
+            XDDFTextParagraph para = body.getParagraph(1);
+            List<XDDFTextRun> runs = para.getTextRuns();
+            assertEquals(1, runs.size());
+
+            XDDFTextRun run = runs.get(0);
+            assertEquals("Line 1", run.getText());
+
+            assertFalse(run.isStrikeThrough());
+            run.setStrikeThrough(StrikeType.SINGLE_STRIKE);
+            assertTrue(run.isStrikeThrough());
+            run.setStrikeThrough(StrikeType.NO_STRIKE);
+            assertFalse(run.isStrikeThrough());
+
+            assertFalse(run.isCapitals());
+            run.setCapitals(CapsType.SMALL);
+            assertTrue(run.isCapitals());
+            run.setCapitals(CapsType.NONE);
+            assertFalse(run.isCapitals());
+
+            assertFalse(run.isBold());
+            run.setBold(true);
+            assertTrue(run.isBold());
+            run.setBold(false);
+            assertFalse(run.isBold());
+
+            assertFalse(run.isItalic());
+            run.setItalic(true);
+            assertTrue(run.isItalic());
+            run.setItalic(false);
+            assertFalse(run.isItalic());
+
+            assertFalse(run.isUnderline());
+            run.setUnderline(UnderlineType.WAVY_DOUBLE);
+            assertTrue(run.isUnderline());
+            run.setUnderline(UnderlineType.NONE);
+            assertFalse(run.isUnderline());
+
+            assertNotNull(run.getText());
+        }
+    }
+}
index 49dc0a3bfc663e1cebd347e19e8575f0ea14bd30..a67d4bef939745f07142b6f53b95f9b8330dc4c0 100644 (file)
@@ -30,6 +30,7 @@ import java.awt.Color;
 import java.io.File;
 import java.io.IOException;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.poi.POIDataSamples;
 import org.apache.poi.hslf.usermodel.HSLFTextShape;
@@ -38,6 +39,8 @@ import org.apache.poi.sl.usermodel.SlideShow;
 import org.apache.poi.sl.usermodel.SlideShowFactory;
 import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
 import org.apache.poi.sl.usermodel.VerticalAlignment;
+import org.apache.poi.xddf.usermodel.text.XDDFBodyProperties;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
 import org.apache.poi.xslf.XSLFTestDataSamples;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -83,6 +86,8 @@ public class TestXSLFTextShape {
         assertEquals("Title Slide",layout.getName());
 
         XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
+        XDDFTextBody tb1 = shape1.getTextBody();
+        XDDFBodyProperties tbp1 = tb1.getBodyProperties();
         CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
         assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType());
         // anchor is not defined in the shape
@@ -104,15 +109,24 @@ public class TestXSLFTextShape {
         assertEquals(3.6, shape1.getTopInset(), 0);  // 0.05"
         assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05"
         assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment());
+        assertNull(tbp1.getLeftInset());
+        assertNull(tbp1.getRightInset());
+        assertNull(tbp1.getBottomInset());
+        assertNull(tbp1.getTopInset());
+        assertNull(tbp1.getAnchoring());
 
         // now check text properties
         assertEquals("Centered Title", shape1.getText());
+        assertEquals("Centered Title",
+            tb1.getParagraphs().stream().map(p -> p.getText()).collect(Collectors.joining("\n")));
         XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0);
         assertEquals("Calibri", r1.getFontFamily());
         assertEquals(44.0, r1.getFontSize(), 0);
         assertTrue(sameColor(Color.black, r1.getFontColor()));
 
         XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
+        XDDFTextBody tb2 = shape2.getTextBody();
+        XDDFBodyProperties tbp2 = tb2.getBodyProperties();
         CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false);
         assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType());
         // anchor is not defined in the shape
@@ -134,8 +148,14 @@ public class TestXSLFTextShape {
         assertEquals(3.6, shape2.getTopInset(), 0);  // 0.05"
         assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05"
         assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
+        assertNull(tbp2.getLeftInset());
+        assertNull(tbp2.getRightInset());
+        assertNull(tbp2.getBottomInset());
+        assertNull(tbp2.getTopInset());
+        assertNull(tbp2.getAnchoring());
 
         assertEquals("subtitle", shape2.getText());
+        assertEquals("subtitle", tb2.getParagraphs().stream().map(p -> p.getText()).collect(Collectors.joining("\n")));
         XSLFTextRun r2 = shape2.getTextParagraphs().get(0).getTextRuns().get(0);
         assertEquals("Calibri", r2.getFontFamily());
         assertEquals(32.0, r2.getFontSize(), 0);
index 06733425ec3fca074c9f2a72d50a6eaad52fb09b..78c476c5b80c8084c24c8acd3e784e7e9cb5c636 100644 (file)
 ==================================================================== */
 package org.apache.poi.xssf.usermodel;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.awt.Color;
 import java.io.IOException;
+import java.util.List;
 
 import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.xddf.usermodel.text.XDDFBodyProperties;
+import org.apache.poi.xddf.usermodel.text.XDDFNoAutoFit;
+import org.apache.poi.xddf.usermodel.text.XDDFNormalAutoFit;
+import org.apache.poi.xddf.usermodel.text.XDDFShapeAutoFit;
+import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
+import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
 import org.junit.Test;
 
 public class TestXSSFSimpleShape {
@@ -31,43 +42,53 @@ public class TestXSSFSimpleShape {
         try {
             XSSFSheet sheet = wb.createSheet();
             XSSFDrawing drawing = sheet.createDrawingPatriarch();
-    
+
             XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
-            
+
             XSSFRichTextString rt = new XSSFRichTextString("Test String");
-            
+
             XSSFFont font = wb.createFont();
             Color color = new Color(0, 255, 255);
             font.setColor(new XSSFColor(color, wb.getStylesSource().getIndexedColors()));
             font.setFontName("Arial");
             rt.applyFont(font);
-    
+
             shape.setText(rt);
 
             assertNotNull(shape.getCTShape());
             assertNotNull(shape.iterator());
             assertNotNull(XSSFSimpleShape.prototype());
-            
-            for(ListAutoNumber nr : ListAutoNumber.values()) {
+
+            for (ListAutoNumber nr : ListAutoNumber.values()) {
                 shape.getTextParagraphs().get(0).setBullet(nr);
                 assertNotNull(shape.getText());
             }
-            
+
             shape.getTextParagraphs().get(0).setBullet(false);
             assertNotNull(shape.getText());
 
             shape.setText("testtext");
             assertEquals("testtext", shape.getText());
-            
+
             shape.setText(new XSSFRichTextString());
             assertEquals("null", shape.getText());
-            
+
             shape.addNewTextParagraph();
             shape.addNewTextParagraph("test-other-text");
             shape.addNewTextParagraph(new XSSFRichTextString("rtstring"));
             shape.addNewTextParagraph(new XSSFRichTextString());
             assertEquals("null\n\ntest-other-text\nrtstring\nnull", shape.getText());
-            
+
+            XDDFTextBody body = shape.getTextBody();
+            assertNotNull(body);
+            List<XDDFTextParagraph> paragraphs = body.getParagraphs();
+            assertEquals(5, paragraphs.size());
+            assertEquals("null", body.getParagraph(0).getText());
+            assertEquals("", body.getParagraph(1).getText());
+            assertEquals("test-other-text", body.getParagraph(2).getText());
+            assertEquals("rtstring", body.getParagraph(3).getText());
+            assertEquals("null", body.getParagraph(4).getText());
+
             assertEquals(TextHorizontalOverflow.OVERFLOW, shape.getTextHorizontalOverflow());
             shape.setTextHorizontalOverflow(TextHorizontalOverflow.CLIP);
             assertEquals(TextHorizontalOverflow.CLIP, shape.getTextHorizontalOverflow());
@@ -77,7 +98,7 @@ public class TestXSSFSimpleShape {
             assertEquals(TextHorizontalOverflow.OVERFLOW, shape.getTextHorizontalOverflow());
             shape.setTextHorizontalOverflow(null);
             assertEquals(TextHorizontalOverflow.OVERFLOW, shape.getTextHorizontalOverflow());
-            
+
             assertEquals(TextVerticalOverflow.OVERFLOW, shape.getTextVerticalOverflow());
             shape.setTextVerticalOverflow(TextVerticalOverflow.CLIP);
             assertEquals(TextVerticalOverflow.CLIP, shape.getTextVerticalOverflow());
@@ -108,38 +129,57 @@ public class TestXSSFSimpleShape {
             shape.setTextDirection(null);
             assertEquals(TextDirection.HORIZONTAL, shape.getTextDirection());
 
+            XDDFBodyProperties props = body.getBodyProperties();
+            assertNotNull(props);
+
             assertEquals(3.6, shape.getBottomInset(), 0.01);
+            assertNull(props.getBottomInset());
             shape.setBottomInset(12.32);
             assertEquals(12.32, shape.getBottomInset(), 0.01);
+            assertEquals(12.32, props.getBottomInset(), 0.01);
             shape.setBottomInset(-1);
             assertEquals(3.6, shape.getBottomInset(), 0.01);
+            assertNull(props.getBottomInset());
             shape.setBottomInset(-1);
             assertEquals(3.6, shape.getBottomInset(), 0.01);
-            
+            assertNull(props.getBottomInset());
+
             assertEquals(3.6, shape.getLeftInset(), 0.01);
+            assertNull(props.getLeftInset());
             shape.setLeftInset(12.31);
             assertEquals(12.31, shape.getLeftInset(), 0.01);
+            assertEquals(12.31, props.getLeftInset(), 0.01);
             shape.setLeftInset(-1);
             assertEquals(3.6, shape.getLeftInset(), 0.01);
+            assertNull(props.getLeftInset());
             shape.setLeftInset(-1);
             assertEquals(3.6, shape.getLeftInset(), 0.01);
+            assertNull(props.getLeftInset());
 
             assertEquals(3.6, shape.getRightInset(), 0.01);
+            assertNull(props.getRightInset());
             shape.setRightInset(13.31);
             assertEquals(13.31, shape.getRightInset(), 0.01);
+            assertEquals(13.31, props.getRightInset(), 0.01);
             shape.setRightInset(-1);
             assertEquals(3.6, shape.getRightInset(), 0.01);
+            assertNull(props.getRightInset());
             shape.setRightInset(-1);
             assertEquals(3.6, shape.getRightInset(), 0.01);
+            assertNull(props.getRightInset());
 
             assertEquals(3.6, shape.getTopInset(), 0.01);
+            assertNull(props.getTopInset());
             shape.setTopInset(23.31);
             assertEquals(23.31, shape.getTopInset(), 0.01);
+            assertEquals(23.31, props.getTopInset(), 0.01);
             shape.setTopInset(-1);
             assertEquals(3.6, shape.getTopInset(), 0.01);
+            assertNull(props.getTopInset());
             shape.setTopInset(-1);
             assertEquals(3.6, shape.getTopInset(), 0.01);
-            
+            assertNull(props.getTopInset());
+
             assertTrue(shape.getWordWrap());
             shape.setWordWrap(false);
             assertFalse(shape.getWordWrap());
@@ -147,23 +187,27 @@ public class TestXSSFSimpleShape {
             assertTrue(shape.getWordWrap());
 
             assertEquals(TextAutofit.NORMAL, shape.getTextAutofit());
+            assertTrue(props.getAutoFit() instanceof XDDFNormalAutoFit);
             shape.setTextAutofit(TextAutofit.NORMAL);
             assertEquals(TextAutofit.NORMAL, shape.getTextAutofit());
+            assertTrue(props.getAutoFit() instanceof XDDFNormalAutoFit);
             shape.setTextAutofit(TextAutofit.SHAPE);
             assertEquals(TextAutofit.SHAPE, shape.getTextAutofit());
+            assertTrue(props.getAutoFit() instanceof XDDFShapeAutoFit);
             shape.setTextAutofit(TextAutofit.NONE);
             assertEquals(TextAutofit.NONE, shape.getTextAutofit());
-            
+            assertTrue(props.getAutoFit() instanceof XDDFNoAutoFit);
+
             assertEquals(5, shape.getShapeType());
             shape.setShapeType(23);
             assertEquals(23, shape.getShapeType());
 
             // TODO: should this be supported?
-//            shape.setShapeType(-1);
-//            assertEquals(-1, shape.getShapeType());
-//            shape.setShapeType(-1);
-//            assertEquals(-1, shape.getShapeType());
-            
+            // shape.setShapeType(-1);
+            // assertEquals(-1, shape.getShapeType());
+            // shape.setShapeType(-1);
+            // assertEquals(-1, shape.getShapeType());
+
             assertNotNull(shape.getShapeProperties());
         } finally {
             wb.close();