]> source.dussan.org Git - poi.git/commitdiff
+svn:eol-style=native
authorJaven O'Neal <onealj@apache.org>
Mon, 15 Aug 2016 16:08:11 +0000 (16:08 +0000)
committerJaven O'Neal <onealj@apache.org>
Mon, 15 Aug 2016 16:08:11 +0000 (16:08 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1756398 13f79535-47bb-0310-9956-ffa450edef68

src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java

index c5a2ce069ded361ad49af6c818c70ea4c2f30ff9..38c298275b1576ab69b1f7c4d9dcb1e79e4e76eb 100644 (file)
-/* ====================================================================\r
-   Licensed to the Apache Software Foundation (ASF) under one or more\r
-   contributor license agreements.  See the NOTICE file distributed with\r
-   this work for additional information regarding copyright ownership.\r
-   The ASF licenses this file to You under the Apache License, Version 2.0\r
-   (the "License"); you may not use this file except in compliance with\r
-   the License.  You may obtain a copy of the License at\r
-\r
-       http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-   Unless required by applicable law or agreed to in writing, software\r
-   distributed under the License is distributed on an "AS IS" BASIS,\r
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-   See the License for the specific language governing permissions and\r
-   limitations under the License.\r
-==================================================================== */\r
-package org.apache.poi.xslf.usermodel;\r
-\r
-import java.awt.Color;\r
-import java.util.ArrayList;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-\r
-import org.apache.poi.sl.draw.DrawPaint;\r
-import org.apache.poi.sl.usermodel.AutoNumberingScheme;\r
-import org.apache.poi.sl.usermodel.PaintStyle;\r
-import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;\r
-import org.apache.poi.sl.usermodel.TextParagraph;\r
-import org.apache.poi.util.Beta;\r
-import org.apache.poi.util.Internal;\r
-import org.apache.poi.util.Units;\r
-import org.apache.poi.xslf.model.ParagraphPropertyFetcher;\r
-import org.apache.xmlbeans.XmlCursor;\r
-import org.apache.xmlbeans.XmlObject;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStopList;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.STTextFontAlignType;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
-import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
-\r
-/**\r
- * Represents a paragraph of text within the containing text body.\r
- * The paragraph is the highest level text separation mechanism.\r
- *\r
- * @since POI-3.8\r
- */\r
-@Beta\r
-public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagraph,XSLFTextRun> {\r
-    private final CTTextParagraph _p;\r
-    private final List<XSLFTextRun> _runs;\r
-    private final XSLFTextShape _shape;\r
-\r
-    XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){\r
-        _p = p;\r
-        _runs = new ArrayList<XSLFTextRun>();\r
-        _shape = shape;\r
-\r
-        for(XmlObject ch : _p.selectPath("*")){\r
-            if(ch instanceof CTRegularTextRun){\r
-                CTRegularTextRun r = (CTRegularTextRun)ch;\r
-                _runs.add(newTextRun(r));\r
-            } else if (ch instanceof CTTextLineBreak){\r
-                CTTextLineBreak br = (CTTextLineBreak)ch;\r
-                CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
-                r.setRPr(br.getRPr());\r
-                r.setT("\n");\r
-                _runs.add(newTextRun(r));\r
-            } else if (ch instanceof CTTextField){\r
-                CTTextField f = (CTTextField)ch;\r
-                CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
-                r.setRPr(f.getRPr());\r
-                r.setT(f.getT());\r
-                _runs.add(newTextRun(r));\r
-            }\r
-        }\r
-    }\r
-\r
-    public String getText(){\r
-        StringBuilder out = new StringBuilder();\r
-        for (XSLFTextRun r : _runs) {\r
-            out.append(r.getRawText());\r
-        }\r
-        return out.toString();\r
-    }\r
-\r
-    String getRenderableText(){\r
-        StringBuilder out = new StringBuilder();\r
-        for (XSLFTextRun r : _runs) {\r
-            out.append(r.getRenderableText());\r
-        }\r
-        return out.toString();\r
-    }\r
-\r
-    @Internal\r
-    public CTTextParagraph getXmlObject(){\r
-        return _p;\r
-    }\r
-\r
-    public XSLFTextShape getParentShape() {\r
-        return _shape;\r
-\r
-    }\r
-\r
-    @Override\r
-    public List<XSLFTextRun> getTextRuns(){\r
-        return _runs;\r
-    }\r
-\r
-    public Iterator<XSLFTextRun> iterator(){\r
-        return _runs.iterator();\r
-    }\r
-\r
-    /**\r
-     * Add a new run of text\r
-     *\r
-     * @return a new run of text\r
-     */\r
-    public XSLFTextRun addNewTextRun(){\r
-        CTRegularTextRun r = _p.addNewR();\r
-        CTTextCharacterProperties rPr = r.addNewRPr();\r
-        rPr.setLang("en-US");\r
-        XSLFTextRun run = newTextRun(r);\r
-        _runs.add(run);\r
-        return run;\r
-    }\r
-\r
-    /**\r
-     * Insert a line break\r
-     *\r
-     * @return text run representing this line break ('\n')\r
-     */\r
-    public XSLFTextRun addLineBreak(){\r
-        CTTextLineBreak br = _p.addNewBr();\r
-        CTTextCharacterProperties brProps = br.addNewRPr();\r
-        if(_runs.size() > 0){\r
-            // by default line break has the font size of the last text run\r
-            CTTextCharacterProperties prevRun = _runs.get(_runs.size() - 1).getRPr(true);\r
-            brProps.set(prevRun);\r
-        }\r
-        CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();\r
-        r.setRPr(brProps);\r
-        r.setT("\n");\r
-        XSLFTextRun run = new XSLFLineBreak(r, this, brProps);\r
-        _runs.add(run);\r
-        return run;\r
-    }\r
-\r
-    @Override\r
-    public TextAlign getTextAlign(){\r
-        ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetAlgn()){\r
-                    TextAlign val = TextAlign.values()[props.getAlgn().intValue() - 1];\r
-                    setValue(val);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    @Override\r
-    public void setTextAlign(TextAlign align) {\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if(align == null) {\r
-            if(pr.isSetAlgn()) pr.unsetAlgn();\r
-        } else {\r
-            pr.setAlgn(STTextAlignType.Enum.forInt(align.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public FontAlign getFontAlign(){\r
-        ParagraphPropertyFetcher<FontAlign> fetcher = new ParagraphPropertyFetcher<FontAlign>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetFontAlgn()){\r
-                    FontAlign val = FontAlign.values()[props.getFontAlgn().intValue() - 1];\r
-                    setValue(val);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    /**\r
-     * Specifies the font alignment that is to be applied to the paragraph.\r
-     * Possible values for this include auto, top, center, baseline and bottom.\r
-     * see {@link org.apache.poi.sl.usermodel.TextParagraph.FontAlign}.\r
-     *\r
-     * @param align font align\r
-     */\r
-    public void setFontAlign(FontAlign align){\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if(align == null) {\r
-            if(pr.isSetFontAlgn()) pr.unsetFontAlgn();\r
-        } else {\r
-            pr.setFontAlgn(STTextFontAlignType.Enum.forInt(align.ordinal() + 1));\r
-        }\r
-    }\r
-\r
-    \r
-\r
-    /**\r
-     * @return the font to be used on bullet characters within a given paragraph\r
-     */\r
-    public String getBulletFont(){\r
-        ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetBuFont()){\r
-                    setValue(props.getBuFont().getTypeface());\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    public void setBulletFont(String typeface){\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTTextFont font = pr.isSetBuFont() ? pr.getBuFont() : pr.addNewBuFont();\r
-        font.setTypeface(typeface);\r
-    }\r
-\r
-    /**\r
-     * @return the character to be used in place of the standard bullet point\r
-     */\r
-    public String getBulletCharacter(){\r
-        ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetBuChar()){\r
-                    setValue(props.getBuChar().getChar());\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    public void setBulletCharacter(String str){\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTTextCharBullet c = pr.isSetBuChar() ? pr.getBuChar() : pr.addNewBuChar();\r
-        c.setChar(str);\r
-    }\r
-\r
-    /**\r
-     *\r
-     * @return the color of bullet characters within a given paragraph.\r
-     * A <code>null</code> value means to use the text font color.\r
-     */\r
-    public PaintStyle getBulletFontColor(){\r
-        final XSLFTheme theme = getParentShape().getSheet().getTheme();\r
-        ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetBuClr()){\r
-                    XSLFColor c = new XSLFColor(props.getBuClr(), theme, null);\r
-                    setValue(c.getColor());\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        Color col = fetcher.getValue();\r
-        return (col == null) ? null : DrawPaint.createSolidPaint(col);\r
-    }\r
-\r
-    public void setBulletFontColor(Color color) {\r
-        setBulletFontColor(DrawPaint.createSolidPaint(color));\r
-    }\r
-    \r
-    \r
-    /**\r
-     * Set the color to be used on bullet characters within a given paragraph.\r
-     *\r
-     * @param color the bullet color\r
-     */\r
-    public void setBulletFontColor(PaintStyle color) {\r
-        if (!(color instanceof SolidPaint)) {\r
-            throw new IllegalArgumentException("Currently XSLF only supports SolidPaint");\r
-        }\r
-\r
-        // TODO: implement setting bullet color to null\r
-        SolidPaint sp = (SolidPaint)color;\r
-        Color col = DrawPaint.applyColorTransform(sp.getSolidColor());\r
-        \r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr();\r
-        CTSRgbColor clr = c.isSetSrgbClr() ? c.getSrgbClr() : c.addNewSrgbClr();\r
-        clr.setVal(new byte[]{(byte) col.getRed(), (byte) col.getGreen(), (byte) col.getBlue()});\r
-    }\r
-\r
-    /**\r
-     * Returns the bullet size that is to be used within a paragraph.\r
-     * This may be specified in two different ways, percentage spacing and font point spacing:\r
-     * <p>\r
-     * If bulletSize >= 0, then bulletSize is a percentage of the font size.\r
-     * If bulletSize < 0, then it specifies the size in points\r
-     * </p>\r
-     *\r
-     * @return the bullet size\r
-     */\r
-    public Double getBulletFontSize(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetBuSzPct()){\r
-                    setValue(props.getBuSzPct().getVal() * 0.001);\r
-                    return true;\r
-                }\r
-                if(props.isSetBuSzPts()){\r
-                    setValue( - props.getBuSzPts().getVal() * 0.01);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    /**\r
-     * Sets the bullet size that is to be used within a paragraph.\r
-     * This may be specified in two different ways, percentage spacing and font point spacing:\r
-     * <p>\r
-     * If bulletSize >= 0, then bulletSize is a percentage of the font size.\r
-     * If bulletSize < 0, then it specifies the size in points\r
-     * </p>\r
-     */\r
-    public void setBulletFontSize(double bulletSize){\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-\r
-        if(bulletSize >= 0) {\r
-            CTTextBulletSizePercent pt = pr.isSetBuSzPct() ? pr.getBuSzPct() : pr.addNewBuSzPct();\r
-            pt.setVal((int)(bulletSize*1000));\r
-            if(pr.isSetBuSzPts()) pr.unsetBuSzPts();\r
-        } else {\r
-            CTTextBulletSizePoint pt = pr.isSetBuSzPts() ? pr.getBuSzPts() : pr.addNewBuSzPts();\r
-            pt.setVal((int)(-bulletSize*100));\r
-            if(pr.isSetBuSzPct()) pr.unsetBuSzPct();\r
-        }\r
-   }\r
-\r
-    /**\r
-     * @return the auto numbering scheme, or null if not defined\r
-     */\r
-    public AutoNumberingScheme getAutoNumberingScheme() {\r
-        ParagraphPropertyFetcher<AutoNumberingScheme> fetcher = new ParagraphPropertyFetcher<AutoNumberingScheme>(getIndentLevel()) {\r
-            public boolean fetch(CTTextParagraphProperties props) {\r
-                if (props.isSetBuAutoNum()) {\r
-                    AutoNumberingScheme ans = AutoNumberingScheme.forOoxmlID(props.getBuAutoNum().getType().intValue());\r
-                    if (ans != null) {\r
-                        setValue(ans);\r
-                        return true;\r
-                    }\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    /**\r
-     * @return the auto numbering starting number, or null if not defined\r
-     */\r
-    public Integer getAutoNumberingStartAt() {\r
-        ParagraphPropertyFetcher<Integer> fetcher = new ParagraphPropertyFetcher<Integer>(getIndentLevel()) {\r
-            public boolean fetch(CTTextParagraphProperties props) {\r
-                if (props.isSetBuAutoNum()) {\r
-                    if (props.getBuAutoNum().isSetStartAt()) {\r
-                        setValue(props.getBuAutoNum().getStartAt());\r
-                        return true;\r
-                    }\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-    \r
-    \r
-    @Override\r
-    public void setIndent(Double indent){\r
-        if ((indent == null) && !_p.isSetPPr()) return;\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if(indent == null) {\r
-            if(pr.isSetIndent()) pr.unsetIndent();\r
-        } else {\r
-            pr.setIndent(Units.toEMU(indent));\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public Double getIndent() {\r
-\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetIndent()){\r
-                    setValue(Units.toPoints(props.getIndent()));\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    @Override\r
-    public void setLeftMargin(Double leftMargin){\r
-        if (leftMargin == null && !_p.isSetPPr()) return;\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if (leftMargin == null) {\r
-            if(pr.isSetMarL()) pr.unsetMarL();\r
-        } else {\r
-            pr.setMarL(Units.toEMU(leftMargin));\r
-        }\r
-\r
-    }\r
-\r
-    /**\r
-     * @return the left margin (in points) of the paragraph, null if unset\r
-     */\r
-    @Override\r
-    public Double getLeftMargin(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetMarL()){\r
-                    double val = Units.toPoints(props.getMarL());\r
-                    setValue(val);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        // if the marL attribute is omitted, then a value of 347663 is implied\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    @Override\r
-    public void setRightMargin(Double rightMargin){\r
-        if (rightMargin == null && !_p.isSetPPr()) return;\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if(rightMargin == null) {\r
-            if(pr.isSetMarR()) pr.unsetMarR();\r
-        } else {\r
-            pr.setMarR(Units.toEMU(rightMargin));\r
-        }\r
-    }\r
-\r
-    /**\r
-     *\r
-     * @return the right margin of the paragraph, null if unset\r
-     */\r
-    @Override\r
-    public Double getRightMargin(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetMarR()){\r
-                    double val = Units.toPoints(props.getMarR());\r
-                    setValue(val);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    @Override\r
-    public Double getDefaultTabSize(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetDefTabSz()){\r
-                    double val = Units.toPoints(props.getDefTabSz());\r
-                    setValue(val);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    public double getTabStop(final int idx){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetTabLst()){\r
-                    CTTextTabStopList tabStops = props.getTabLst();\r
-                    if(idx < tabStops.sizeOfTabArray() ) {\r
-                        CTTextTabStop ts = tabStops.getTabArray(idx);\r
-                        double val = Units.toPoints(ts.getPos());\r
-                        setValue(val);\r
-                        return true;\r
-                    }\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue() == null ? 0. : fetcher.getValue();\r
-    }\r
-\r
-    public void addTabStop(double value){\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTTextTabStopList tabStops = pr.isSetTabLst() ? pr.getTabLst() : pr.addNewTabLst();\r
-        tabStops.addNewTab().setPos(Units.toEMU(value));\r
-    }\r
-\r
-    @Override\r
-    public void setLineSpacing(Double lineSpacing){\r
-        if (lineSpacing == null && !_p.isSetPPr()) return;\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if(lineSpacing == null) {\r
-            if (pr.isSetLnSpc()) pr.unsetLnSpc();\r
-        } else {\r
-            CTTextSpacing spc = (pr.isSetLnSpc()) ? pr.getLnSpc() : pr.addNewLnSpc();\r
-            if (lineSpacing >= 0) {\r
-                (spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct()).setVal((int)(lineSpacing*1000));\r
-                if (spc.isSetSpcPts()) spc.unsetSpcPts();\r
-            } else {\r
-                (spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts()).setVal((int)(-lineSpacing*100));\r
-                if (spc.isSetSpcPct()) spc.unsetSpcPct();\r
-            }\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public Double getLineSpacing(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetLnSpc()){\r
-                    CTTextSpacing spc = props.getLnSpc();\r
-\r
-                    if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );\r
-                    else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-\r
-        Double lnSpc = fetcher.getValue();\r
-        if (lnSpc != null && lnSpc > 0) {\r
-            // check if the percentage value is scaled\r
-            CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit();\r
-            if(normAutofit != null) {\r
-                double scale = 1 - (double)normAutofit.getLnSpcReduction() / 100000;\r
-                lnSpc *= scale;\r
-            }\r
-        }\r
-        \r
-        return lnSpc;\r
-    }\r
-\r
-    @Override\r
-    public void setSpaceBefore(Double spaceBefore){\r
-        if (spaceBefore == null && !_p.isSetPPr()) {\r
-            return;\r
-        }\r
-\r
-        // unset the space before on null input\r
-        if (spaceBefore == null) {\r
-            if(_p.getPPr().isSetSpcBef()) {\r
-                _p.getPPr().unsetSpcBef();\r
-            }\r
-            return;\r
-        }\r
-\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTTextSpacing spc = CTTextSpacing.Factory.newInstance();\r
-\r
-        if(spaceBefore >= 0) {\r
-            spc.addNewSpcPct().setVal((int)(spaceBefore*1000));\r
-        } else {\r
-            spc.addNewSpcPts().setVal((int)(-spaceBefore*100));\r
-        }\r
-        pr.setSpcBef(spc);\r
-    }\r
-\r
-    @Override\r
-    public Double getSpaceBefore(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetSpcBef()){\r
-                    CTTextSpacing spc = props.getSpcBef();\r
-\r
-                    if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );\r
-                    else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    @Override\r
-    public void setSpaceAfter(Double spaceAfter){\r
-        if (spaceAfter == null && !_p.isSetPPr()) {\r
-            return;\r
-        }\r
-\r
-        // unset the space before on null input\r
-        if (spaceAfter == null) {\r
-            if(_p.getPPr().isSetSpcAft()) {\r
-                _p.getPPr().unsetSpcAft();\r
-            }\r
-            return;\r
-        }\r
-\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTTextSpacing spc = CTTextSpacing.Factory.newInstance();\r
-\r
-        if(spaceAfter >= 0) {\r
-            spc.addNewSpcPct().setVal((int)(spaceAfter*1000));\r
-        } else {\r
-            spc.addNewSpcPts().setVal((int)(-spaceAfter*100));\r
-        }\r
-        pr.setSpcAft(spc);\r
-    }\r
-\r
-    @Override\r
-    public Double getSpaceAfter(){\r
-        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetSpcAft()){\r
-                    CTTextSpacing spc = props.getSpcAft();\r
-\r
-                    if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );\r
-                    else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue();\r
-    }\r
-\r
-    @Override\r
-    public void setIndentLevel(int level){\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        pr.setLvl(level);\r
-    }\r
-\r
-    @Override\r
-    public int getIndentLevel() {\r
-        CTTextParagraphProperties pr = _p.getPPr();\r
-        return (pr == null || !pr.isSetLvl()) ? 0 : pr.getLvl();\r
-    }\r
-\r
-    /**\r
-     * Returns whether this paragraph has bullets\r
-     */\r
-    public boolean isBullet() {\r
-        ParagraphPropertyFetcher<Boolean> fetcher = new ParagraphPropertyFetcher<Boolean>(getIndentLevel()){\r
-            public boolean fetch(CTTextParagraphProperties props){\r
-                if(props.isSetBuNone()) {\r
-                    setValue(false);\r
-                    return true;\r
-                }\r
-                if(props.isSetBuFont() || props.isSetBuChar()){\r
-                    setValue(true);\r
-                    return true;\r
-                }\r
-                return false;\r
-            }\r
-        };\r
-        fetchParagraphProperty(fetcher);\r
-        return fetcher.getValue() == null ? false : fetcher.getValue();\r
-    }\r
-\r
-    /**\r
-     *\r
-     * @param flag whether text in this paragraph has bullets\r
-     */\r
-    public void setBullet(boolean flag) {\r
-        if(isBullet() == flag) return;\r
-\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        if(flag) {\r
-            pr.addNewBuFont().setTypeface("Arial");\r
-            pr.addNewBuChar().setChar("\u2022");\r
-        } else {\r
-            if (pr.isSetBuFont()) pr.unsetBuFont();\r
-            if (pr.isSetBuChar()) pr.unsetBuChar();\r
-            if (pr.isSetBuAutoNum()) pr.unsetBuAutoNum();\r
-            if (pr.isSetBuBlip()) pr.unsetBuBlip();\r
-            if (pr.isSetBuClr()) pr.unsetBuClr();\r
-            if (pr.isSetBuClrTx()) pr.unsetBuClrTx();\r
-            if (pr.isSetBuFont()) pr.unsetBuFont();\r
-            if (pr.isSetBuFontTx()) pr.unsetBuFontTx();\r
-            if (pr.isSetBuSzPct()) pr.unsetBuSzPct();\r
-            if (pr.isSetBuSzPts()) pr.unsetBuSzPts();\r
-            if (pr.isSetBuSzTx()) pr.unsetBuSzTx();\r
-            pr.addNewBuNone();\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Specifies that automatic numbered bullet points should be applied to this paragraph\r
-     *\r
-     * @param scheme type of auto-numbering\r
-     * @param startAt the number that will start number for a given sequence of automatically\r
-    numbered bullets (1-based).\r
-     */\r
-    public void setBulletAutoNumber(AutoNumberingScheme scheme, int startAt) {\r
-        if(startAt < 1) throw new IllegalArgumentException("Start Number must be greater or equal that 1") ;\r
-        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();\r
-        CTTextAutonumberBullet lst = pr.isSetBuAutoNum() ? pr.getBuAutoNum() : pr.addNewBuAutoNum();\r
-        lst.setType(STTextAutonumberScheme.Enum.forInt(scheme.ooxmlId));\r
-        lst.setStartAt(startAt);\r
-    }\r
-\r
-    @Override\r
-    public String toString(){\r
-        return "[" + getClass() + "]" + getText();\r
-    }\r
-\r
-\r
-    /**\r
-     * @return master style text paragraph properties, or <code>null</code> if \r
-     * there are no master slides or the master slides do not contain a text paragraph\r
-     */\r
-    /* package */ CTTextParagraphProperties getDefaultMasterStyle(){\r
-        CTPlaceholder ph = _shape.getCTPlaceholder();\r
-        String defaultStyleSelector;  \r
-        switch(ph == null ? -1 : ph.getType().intValue()) {\r
-            case STPlaceholderType.INT_TITLE:\r
-            case STPlaceholderType.INT_CTR_TITLE:\r
-                defaultStyleSelector = "titleStyle";\r
-                break;\r
-            case -1: // no placeholder means plain text box\r
-            case STPlaceholderType.INT_FTR:\r
-            case STPlaceholderType.INT_SLD_NUM:\r
-            case STPlaceholderType.INT_DT:\r
-                defaultStyleSelector = "otherStyle";\r
-                break;\r
-            default:\r
-                defaultStyleSelector = "bodyStyle";\r
-                break;\r
-        }\r
-        int level = getIndentLevel();\r
-\r
-        // wind up and find the root master sheet which must be slide master\r
-        final String nsPML = "http://schemas.openxmlformats.org/presentationml/2006/main";\r
-        final String nsDML = "http://schemas.openxmlformats.org/drawingml/2006/main";\r
-        XSLFSheet masterSheet = _shape.getSheet();\r
-        for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {\r
-            masterSheet = m;\r
-            XmlObject xo = masterSheet.getXmlObject();\r
-            XmlCursor cur = xo.newCursor();\r
-            try {\r
-                cur.push();\r
-                if ((cur.toChild(nsPML, "txStyles") && cur.toChild(nsPML, defaultStyleSelector)) ||\r
-                       (cur.pop() && cur.toChild(nsPML, "notesStyle"))) {\r
-                    while (level >= 0) {\r
-                        cur.push();\r
-                       if (cur.toChild(nsDML, "lvl" +(level+1)+ "pPr")) {\r
-                               return (CTTextParagraphProperties)cur.getObject();\r
-                       }\r
-                       cur.pop();\r
-                       level--;\r
-                    }\r
-                }\r
-            } finally {\r
-               cur.dispose();\r
-            }\r
-        }\r
-        \r
-        return null;\r
-    }\r
-\r
-    private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){\r
-        boolean ok = false;\r
-        XSLFTextShape shape = getParentShape();\r
-        XSLFSheet sheet = shape.getSheet();\r
-        \r
-        if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());\r
-        if (ok) return true;\r
-\r
-        ok = shape.fetchShapeProperty(visitor);\r
-        if (ok) return true;\r
-                \r
-        \r
-        CTPlaceholder ph = shape.getCTPlaceholder();\r
-        if(ph == null){\r
-            // if it is a plain text box then take defaults from presentation.xml\r
-            @SuppressWarnings("resource")\r
-            XMLSlideShow ppt = sheet.getSlideShow();\r
-            CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel());\r
-            if (themeProps != null) ok = visitor.fetch(themeProps);\r
-        }\r
-        if (ok) return true;\r
-\r
-        // defaults for placeholders are defined in the slide master\r
-        CTTextParagraphProperties defaultProps = getDefaultMasterStyle();\r
-        // TODO: determine master shape\r
-        if(defaultProps != null) ok = visitor.fetch(defaultProps);\r
-        if (ok) return true;\r
-\r
-        return false;\r
-    }\r
-\r
-    void copy(XSLFTextParagraph other){\r
-        if (other == this) return;\r
-        \r
-        CTTextParagraph thisP = getXmlObject();\r
-        CTTextParagraph otherP = other.getXmlObject();\r
-        \r
-        if (thisP.isSetPPr()) thisP.unsetPPr();\r
-        if (thisP.isSetEndParaRPr()) thisP.unsetEndParaRPr();\r
-        \r
-        _runs.clear();\r
-        for (int i=thisP.sizeOfBrArray(); i>0; i--) {\r
-            thisP.removeBr(i-1);\r
-        }\r
-        for (int i=thisP.sizeOfRArray(); i>0; i--) {\r
-            thisP.removeR(i-1);\r
-        }\r
-        for (int i=thisP.sizeOfFldArray(); i>0; i--) {\r
-            thisP.removeFld(i-1);\r
-        }\r
-\r
-        XmlCursor thisC = thisP.newCursor();\r
-        thisC.toEndToken();\r
-        XmlCursor otherC = otherP.newCursor();\r
-        otherC.copyXmlContents(thisC);\r
-        otherC.dispose();\r
-        thisC.dispose();\r
-        \r
-        List<XSLFTextRun> otherRs = other.getTextRuns();\r
-        int i=0;\r
-        for(CTRegularTextRun rtr : thisP.getRArray()) {\r
-            XSLFTextRun run = newTextRun(rtr);\r
-            run.copy(otherRs.get(i++));\r
-            _runs.add(run);\r
-        }\r
-        \r
-        \r
-        // set properties again, in case we are based on a different\r
-        // template\r
-        TextAlign srcAlign = other.getTextAlign();\r
-        if(srcAlign != getTextAlign()){\r
-            setTextAlign(srcAlign);\r
-        }\r
-\r
-        boolean isBullet = other.isBullet();\r
-        if(isBullet != isBullet()){\r
-            setBullet(isBullet);\r
-            if(isBullet) {\r
-                String buFont = other.getBulletFont();\r
-                if(buFont != null && !buFont.equals(getBulletFont())){\r
-                    setBulletFont(buFont);\r
-                }\r
-                String buChar = other.getBulletCharacter();\r
-                if(buChar != null && !buChar.equals(getBulletCharacter())){\r
-                    setBulletCharacter(buChar);\r
-                }\r
-                PaintStyle buColor = other.getBulletFontColor();\r
-                if(buColor != null && !buColor.equals(getBulletFontColor())){\r
-                    setBulletFontColor(buColor);\r
-                }\r
-                Double buSize = other.getBulletFontSize();\r
-                if(!doubleEquals(buSize, getBulletFontSize())){\r
-                    setBulletFontSize(buSize);\r
-                }\r
-            }\r
-        }\r
-\r
-        Double leftMargin = other.getLeftMargin();\r
-        if (!doubleEquals(leftMargin, getLeftMargin())){\r
-            setLeftMargin(leftMargin);\r
-        }\r
-\r
-        Double indent = other.getIndent();\r
-        if (!doubleEquals(indent, getIndent())) {\r
-            setIndent(indent);\r
-        }\r
-\r
-        Double spaceAfter = other.getSpaceAfter();\r
-        if (!doubleEquals(spaceAfter, getSpaceAfter())) {\r
-            setSpaceAfter(spaceAfter);\r
-        }\r
-        \r
-        Double spaceBefore = other.getSpaceBefore();\r
-        if (!doubleEquals(spaceBefore, getSpaceBefore())) {\r
-            setSpaceBefore(spaceBefore);\r
-        }\r
-        \r
-        Double lineSpacing = other.getLineSpacing();\r
-        if (!doubleEquals(lineSpacing, getLineSpacing())) {\r
-            setLineSpacing(lineSpacing);\r
-        }\r
-    }\r
-\r
-    private static boolean doubleEquals(Double d1, Double d2) {\r
-        return (d1 == d2 || (d1 != null && d1.equals(d2)));\r
-    }\r
-    \r
-    @Override\r
-    public Double getDefaultFontSize() {\r
-        CTTextCharacterProperties endPr = _p.getEndParaRPr();\r
-        if (endPr == null || !endPr.isSetSz()) {\r
-            // inherit the font size from the master style\r
-            CTTextParagraphProperties masterStyle = getDefaultMasterStyle();\r
-            if (masterStyle != null) {\r
-                endPr = masterStyle.getDefRPr();\r
-            }\r
-        }\r
-        return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);\r
-    }\r
-\r
-    @Override\r
-    public String getDefaultFontFamily() {\r
-        return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily());\r
-    }\r
-\r
-    @Override\r
-    public BulletStyle getBulletStyle() {\r
-        if (!isBullet()) return null;\r
-        return new BulletStyle(){\r
-            @Override\r
-            public String getBulletCharacter() {\r
-                return XSLFTextParagraph.this.getBulletCharacter();\r
-            }\r
-\r
-            @Override\r
-            public String getBulletFont() {\r
-                return XSLFTextParagraph.this.getBulletFont();\r
-            }\r
-\r
-            @Override\r
-            public Double getBulletFontSize() {\r
-                return XSLFTextParagraph.this.getBulletFontSize();\r
-            }\r
-\r
-            @Override\r
-            public PaintStyle getBulletFontColor() {\r
-                return XSLFTextParagraph.this.getBulletFontColor();\r
-            }\r
-            \r
-            @Override\r
-            public void setBulletFontColor(Color color) {\r
-                setBulletFontColor(DrawPaint.createSolidPaint(color));\r
-            }\r
-\r
-            @Override\r
-            public void setBulletFontColor(PaintStyle color) {\r
-                XSLFTextParagraph.this.setBulletFontColor(color);\r
-            }\r
-            \r
-            @Override\r
-            public AutoNumberingScheme getAutoNumberingScheme() {\r
-                return XSLFTextParagraph.this.getAutoNumberingScheme();\r
-            }\r
-\r
-            @Override\r
-            public Integer getAutoNumberingStartAt() {\r
-                return XSLFTextParagraph.this.getAutoNumberingStartAt();\r
-            }\r
-\r
-        };\r
-    }\r
-\r
-    @Override\r
-    public void setBulletStyle(Object... styles) {\r
-        if (styles.length == 0) {\r
-            setBullet(false);\r
-        } else {\r
-            setBullet(true);\r
-            for (Object ostyle : styles) {\r
-                if (ostyle instanceof Number) {\r
-                    setBulletFontSize(((Number)ostyle).doubleValue());\r
-                } else if (ostyle instanceof Color) {\r
-                    setBulletFontColor((Color)ostyle);\r
-                } else if (ostyle instanceof Character) {\r
-                    setBulletCharacter(ostyle.toString());\r
-                } else if (ostyle instanceof String) {\r
-                    setBulletFont((String)ostyle);\r
-                } else if (ostyle instanceof AutoNumberingScheme) {\r
-                    setBulletAutoNumber((AutoNumberingScheme)ostyle, 0);\r
-                }\r
-            }\r
-        }\r
-    }\r
-    \r
-    /**\r
-     * Helper method for appending text and keeping paragraph and character properties.\r
-     * The character properties are moved to the end paragraph marker\r
-     */\r
-    /* package */ void clearButKeepProperties() {\r
-        CTTextParagraph thisP = getXmlObject();\r
-        for (int i=thisP.sizeOfBrArray(); i>0; i--) {\r
-            thisP.removeBr(i-1);\r
-        }\r
-        for (int i=thisP.sizeOfFldArray(); i>0; i--) {\r
-            thisP.removeFld(i-1);\r
-        }\r
-        if (!_runs.isEmpty()) {\r
-            int size = _runs.size();\r
-            XSLFTextRun lastRun = _runs.get(size-1);\r
-            CTTextCharacterProperties cpOther = lastRun.getRPr(false);\r
-            if (cpOther != null) {\r
-                if (thisP.isSetEndParaRPr()) {\r
-                    thisP.unsetEndParaRPr();\r
-                }\r
-                CTTextCharacterProperties cp = thisP.addNewEndParaRPr();\r
-                cp.set(cpOther);\r
-            }\r
-            for (int i=size; i>0; i--) {\r
-                thisP.removeR(i-1);\r
-            }\r
-            _runs.clear();\r
-        }\r
-    }\r
-\r
-    @Override\r
-    public boolean isHeaderOrFooter() {\r
-        CTPlaceholder ph = _shape.getCTPlaceholder();\r
-        int phId = (ph == null ? -1 : ph.getType().intValue());\r
-        switch (phId) {\r
-            case STPlaceholderType.INT_SLD_NUM:\r
-            case STPlaceholderType.INT_DT:\r
-            case STPlaceholderType.INT_FTR:\r
-            case STPlaceholderType.INT_HDR:\r
-                return true;\r
-            default:\r
-                return false;\r
-        }\r
-    }\r
-\r
-    /**\r
-     * Helper method to allow subclasses to provide their own text run\r
-     *\r
-     * @param r the xml reference\r
-     * \r
-     * @return a new text paragraph\r
-     * \r
-     * @since POI 3.15-beta2\r
-     */\r
-    protected XSLFTextRun newTextRun(CTRegularTextRun r) {\r
-        return new XSLFTextRun(r, this);\r
-    }\r
-}\r
+/* ====================================================================
+   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.xslf.usermodel;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.poi.sl.draw.DrawPaint;
+import org.apache.poi.sl.usermodel.AutoNumberingScheme;
+import org.apache.poi.sl.usermodel.PaintStyle;
+import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
+import org.apache.poi.sl.usermodel.TextParagraph;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+import org.apache.poi.xslf.model.ParagraphPropertyFetcher;
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStopList;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextFontAlignType;
+import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
+import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
+
+/**
+ * Represents a paragraph of text within the containing text body.
+ * The paragraph is the highest level text separation mechanism.
+ *
+ * @since POI-3.8
+ */
+@Beta
+public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagraph,XSLFTextRun> {
+    private final CTTextParagraph _p;
+    private final List<XSLFTextRun> _runs;
+    private final XSLFTextShape _shape;
+
+    XSLFTextParagraph(CTTextParagraph p, XSLFTextShape shape){
+        _p = p;
+        _runs = new ArrayList<XSLFTextRun>();
+        _shape = shape;
+
+        for(XmlObject ch : _p.selectPath("*")){
+            if(ch instanceof CTRegularTextRun){
+                CTRegularTextRun r = (CTRegularTextRun)ch;
+                _runs.add(newTextRun(r));
+            } else if (ch instanceof CTTextLineBreak){
+                CTTextLineBreak br = (CTTextLineBreak)ch;
+                CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
+                r.setRPr(br.getRPr());
+                r.setT("\n");
+                _runs.add(newTextRun(r));
+            } else if (ch instanceof CTTextField){
+                CTTextField f = (CTTextField)ch;
+                CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
+                r.setRPr(f.getRPr());
+                r.setT(f.getT());
+                _runs.add(newTextRun(r));
+            }
+        }
+    }
+
+    public String getText(){
+        StringBuilder out = new StringBuilder();
+        for (XSLFTextRun r : _runs) {
+            out.append(r.getRawText());
+        }
+        return out.toString();
+    }
+
+    String getRenderableText(){
+        StringBuilder out = new StringBuilder();
+        for (XSLFTextRun r : _runs) {
+            out.append(r.getRenderableText());
+        }
+        return out.toString();
+    }
+
+    @Internal
+    public CTTextParagraph getXmlObject(){
+        return _p;
+    }
+
+    public XSLFTextShape getParentShape() {
+        return _shape;
+
+    }
+
+    @Override
+    public List<XSLFTextRun> getTextRuns(){
+        return _runs;
+    }
+
+    public Iterator<XSLFTextRun> iterator(){
+        return _runs.iterator();
+    }
+
+    /**
+     * Add a new run of text
+     *
+     * @return a new run of text
+     */
+    public XSLFTextRun addNewTextRun(){
+        CTRegularTextRun r = _p.addNewR();
+        CTTextCharacterProperties rPr = r.addNewRPr();
+        rPr.setLang("en-US");
+        XSLFTextRun run = newTextRun(r);
+        _runs.add(run);
+        return run;
+    }
+
+    /**
+     * Insert a line break
+     *
+     * @return text run representing this line break ('\n')
+     */
+    public XSLFTextRun addLineBreak(){
+        CTTextLineBreak br = _p.addNewBr();
+        CTTextCharacterProperties brProps = br.addNewRPr();
+        if(_runs.size() > 0){
+            // by default line break has the font size of the last text run
+            CTTextCharacterProperties prevRun = _runs.get(_runs.size() - 1).getRPr(true);
+            brProps.set(prevRun);
+        }
+        CTRegularTextRun r = CTRegularTextRun.Factory.newInstance();
+        r.setRPr(brProps);
+        r.setT("\n");
+        XSLFTextRun run = new XSLFLineBreak(r, this, brProps);
+        _runs.add(run);
+        return run;
+    }
+
+    @Override
+    public TextAlign getTextAlign(){
+        ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetAlgn()){
+                    TextAlign val = TextAlign.values()[props.getAlgn().intValue() - 1];
+                    setValue(val);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    @Override
+    public void setTextAlign(TextAlign align) {
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if(align == null) {
+            if(pr.isSetAlgn()) pr.unsetAlgn();
+        } else {
+            pr.setAlgn(STTextAlignType.Enum.forInt(align.ordinal() + 1));
+        }
+    }
+
+    @Override
+    public FontAlign getFontAlign(){
+        ParagraphPropertyFetcher<FontAlign> fetcher = new ParagraphPropertyFetcher<FontAlign>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetFontAlgn()){
+                    FontAlign val = FontAlign.values()[props.getFontAlgn().intValue() - 1];
+                    setValue(val);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    /**
+     * Specifies the font alignment that is to be applied to the paragraph.
+     * Possible values for this include auto, top, center, baseline and bottom.
+     * see {@link org.apache.poi.sl.usermodel.TextParagraph.FontAlign}.
+     *
+     * @param align font align
+     */
+    public void setFontAlign(FontAlign align){
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if(align == null) {
+            if(pr.isSetFontAlgn()) pr.unsetFontAlgn();
+        } else {
+            pr.setFontAlgn(STTextFontAlignType.Enum.forInt(align.ordinal() + 1));
+        }
+    }
+
+    
+
+    /**
+     * @return the font to be used on bullet characters within a given paragraph
+     */
+    public String getBulletFont(){
+        ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetBuFont()){
+                    setValue(props.getBuFont().getTypeface());
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    public void setBulletFont(String typeface){
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTTextFont font = pr.isSetBuFont() ? pr.getBuFont() : pr.addNewBuFont();
+        font.setTypeface(typeface);
+    }
+
+    /**
+     * @return the character to be used in place of the standard bullet point
+     */
+    public String getBulletCharacter(){
+        ParagraphPropertyFetcher<String> fetcher = new ParagraphPropertyFetcher<String>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetBuChar()){
+                    setValue(props.getBuChar().getChar());
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    public void setBulletCharacter(String str){
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTTextCharBullet c = pr.isSetBuChar() ? pr.getBuChar() : pr.addNewBuChar();
+        c.setChar(str);
+    }
+
+    /**
+     *
+     * @return the color of bullet characters within a given paragraph.
+     * A <code>null</code> value means to use the text font color.
+     */
+    public PaintStyle getBulletFontColor(){
+        final XSLFTheme theme = getParentShape().getSheet().getTheme();
+        ParagraphPropertyFetcher<Color> fetcher = new ParagraphPropertyFetcher<Color>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetBuClr()){
+                    XSLFColor c = new XSLFColor(props.getBuClr(), theme, null);
+                    setValue(c.getColor());
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        Color col = fetcher.getValue();
+        return (col == null) ? null : DrawPaint.createSolidPaint(col);
+    }
+
+    public void setBulletFontColor(Color color) {
+        setBulletFontColor(DrawPaint.createSolidPaint(color));
+    }
+    
+    
+    /**
+     * Set the color to be used on bullet characters within a given paragraph.
+     *
+     * @param color the bullet color
+     */
+    public void setBulletFontColor(PaintStyle color) {
+        if (!(color instanceof SolidPaint)) {
+            throw new IllegalArgumentException("Currently XSLF only supports SolidPaint");
+        }
+
+        // TODO: implement setting bullet color to null
+        SolidPaint sp = (SolidPaint)color;
+        Color col = DrawPaint.applyColorTransform(sp.getSolidColor());
+        
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTColor c = pr.isSetBuClr() ? pr.getBuClr() : pr.addNewBuClr();
+        CTSRgbColor clr = c.isSetSrgbClr() ? c.getSrgbClr() : c.addNewSrgbClr();
+        clr.setVal(new byte[]{(byte) col.getRed(), (byte) col.getGreen(), (byte) col.getBlue()});
+    }
+
+    /**
+     * Returns the bullet size that is to be used within a paragraph.
+     * This may be specified in two different ways, percentage spacing and font point spacing:
+     * <p>
+     * If bulletSize >= 0, then bulletSize is a percentage of the font size.
+     * If bulletSize < 0, then it specifies the size in points
+     * </p>
+     *
+     * @return the bullet size
+     */
+    public Double getBulletFontSize(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetBuSzPct()){
+                    setValue(props.getBuSzPct().getVal() * 0.001);
+                    return true;
+                }
+                if(props.isSetBuSzPts()){
+                    setValue( - props.getBuSzPts().getVal() * 0.01);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    /**
+     * Sets the bullet size that is to be used within a paragraph.
+     * This may be specified in two different ways, percentage spacing and font point spacing:
+     * <p>
+     * If bulletSize >= 0, then bulletSize is a percentage of the font size.
+     * If bulletSize < 0, then it specifies the size in points
+     * </p>
+     */
+    public void setBulletFontSize(double bulletSize){
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+
+        if(bulletSize >= 0) {
+            CTTextBulletSizePercent pt = pr.isSetBuSzPct() ? pr.getBuSzPct() : pr.addNewBuSzPct();
+            pt.setVal((int)(bulletSize*1000));
+            if(pr.isSetBuSzPts()) pr.unsetBuSzPts();
+        } else {
+            CTTextBulletSizePoint pt = pr.isSetBuSzPts() ? pr.getBuSzPts() : pr.addNewBuSzPts();
+            pt.setVal((int)(-bulletSize*100));
+            if(pr.isSetBuSzPct()) pr.unsetBuSzPct();
+        }
+   }
+
+    /**
+     * @return the auto numbering scheme, or null if not defined
+     */
+    public AutoNumberingScheme getAutoNumberingScheme() {
+        ParagraphPropertyFetcher<AutoNumberingScheme> fetcher = new ParagraphPropertyFetcher<AutoNumberingScheme>(getIndentLevel()) {
+            public boolean fetch(CTTextParagraphProperties props) {
+                if (props.isSetBuAutoNum()) {
+                    AutoNumberingScheme ans = AutoNumberingScheme.forOoxmlID(props.getBuAutoNum().getType().intValue());
+                    if (ans != null) {
+                        setValue(ans);
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    /**
+     * @return the auto numbering starting number, or null if not defined
+     */
+    public Integer getAutoNumberingStartAt() {
+        ParagraphPropertyFetcher<Integer> fetcher = new ParagraphPropertyFetcher<Integer>(getIndentLevel()) {
+            public boolean fetch(CTTextParagraphProperties props) {
+                if (props.isSetBuAutoNum()) {
+                    if (props.getBuAutoNum().isSetStartAt()) {
+                        setValue(props.getBuAutoNum().getStartAt());
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+    
+    
+    @Override
+    public void setIndent(Double indent){
+        if ((indent == null) && !_p.isSetPPr()) return;
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if(indent == null) {
+            if(pr.isSetIndent()) pr.unsetIndent();
+        } else {
+            pr.setIndent(Units.toEMU(indent));
+        }
+    }
+
+    @Override
+    public Double getIndent() {
+
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetIndent()){
+                    setValue(Units.toPoints(props.getIndent()));
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+
+        return fetcher.getValue();
+    }
+
+    @Override
+    public void setLeftMargin(Double leftMargin){
+        if (leftMargin == null && !_p.isSetPPr()) return;
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if (leftMargin == null) {
+            if(pr.isSetMarL()) pr.unsetMarL();
+        } else {
+            pr.setMarL(Units.toEMU(leftMargin));
+        }
+
+    }
+
+    /**
+     * @return the left margin (in points) of the paragraph, null if unset
+     */
+    @Override
+    public Double getLeftMargin(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetMarL()){
+                    double val = Units.toPoints(props.getMarL());
+                    setValue(val);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        // if the marL attribute is omitted, then a value of 347663 is implied
+        return fetcher.getValue();
+    }
+
+    @Override
+    public void setRightMargin(Double rightMargin){
+        if (rightMargin == null && !_p.isSetPPr()) return;
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if(rightMargin == null) {
+            if(pr.isSetMarR()) pr.unsetMarR();
+        } else {
+            pr.setMarR(Units.toEMU(rightMargin));
+        }
+    }
+
+    /**
+     *
+     * @return the right margin of the paragraph, null if unset
+     */
+    @Override
+    public Double getRightMargin(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetMarR()){
+                    double val = Units.toPoints(props.getMarR());
+                    setValue(val);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    @Override
+    public Double getDefaultTabSize(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetDefTabSz()){
+                    double val = Units.toPoints(props.getDefTabSz());
+                    setValue(val);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    public double getTabStop(final int idx){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetTabLst()){
+                    CTTextTabStopList tabStops = props.getTabLst();
+                    if(idx < tabStops.sizeOfTabArray() ) {
+                        CTTextTabStop ts = tabStops.getTabArray(idx);
+                        double val = Units.toPoints(ts.getPos());
+                        setValue(val);
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue() == null ? 0. : fetcher.getValue();
+    }
+
+    public void addTabStop(double value){
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTTextTabStopList tabStops = pr.isSetTabLst() ? pr.getTabLst() : pr.addNewTabLst();
+        tabStops.addNewTab().setPos(Units.toEMU(value));
+    }
+
+    @Override
+    public void setLineSpacing(Double lineSpacing){
+        if (lineSpacing == null && !_p.isSetPPr()) return;
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if(lineSpacing == null) {
+            if (pr.isSetLnSpc()) pr.unsetLnSpc();
+        } else {
+            CTTextSpacing spc = (pr.isSetLnSpc()) ? pr.getLnSpc() : pr.addNewLnSpc();
+            if (lineSpacing >= 0) {
+                (spc.isSetSpcPct() ? spc.getSpcPct() : spc.addNewSpcPct()).setVal((int)(lineSpacing*1000));
+                if (spc.isSetSpcPts()) spc.unsetSpcPts();
+            } else {
+                (spc.isSetSpcPts() ? spc.getSpcPts() : spc.addNewSpcPts()).setVal((int)(-lineSpacing*100));
+                if (spc.isSetSpcPct()) spc.unsetSpcPct();
+            }
+        }
+    }
+
+    @Override
+    public Double getLineSpacing(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetLnSpc()){
+                    CTTextSpacing spc = props.getLnSpc();
+
+                    if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );
+                    else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+
+        Double lnSpc = fetcher.getValue();
+        if (lnSpc != null && lnSpc > 0) {
+            // check if the percentage value is scaled
+            CTTextNormalAutofit normAutofit = getParentShape().getTextBodyPr().getNormAutofit();
+            if(normAutofit != null) {
+                double scale = 1 - (double)normAutofit.getLnSpcReduction() / 100000;
+                lnSpc *= scale;
+            }
+        }
+        
+        return lnSpc;
+    }
+
+    @Override
+    public void setSpaceBefore(Double spaceBefore){
+        if (spaceBefore == null && !_p.isSetPPr()) {
+            return;
+        }
+
+        // unset the space before on null input
+        if (spaceBefore == null) {
+            if(_p.getPPr().isSetSpcBef()) {
+                _p.getPPr().unsetSpcBef();
+            }
+            return;
+        }
+
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
+
+        if(spaceBefore >= 0) {
+            spc.addNewSpcPct().setVal((int)(spaceBefore*1000));
+        } else {
+            spc.addNewSpcPts().setVal((int)(-spaceBefore*100));
+        }
+        pr.setSpcBef(spc);
+    }
+
+    @Override
+    public Double getSpaceBefore(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetSpcBef()){
+                    CTTextSpacing spc = props.getSpcBef();
+
+                    if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );
+                    else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+
+        return fetcher.getValue();
+    }
+
+    @Override
+    public void setSpaceAfter(Double spaceAfter){
+        if (spaceAfter == null && !_p.isSetPPr()) {
+            return;
+        }
+
+        // unset the space before on null input
+        if (spaceAfter == null) {
+            if(_p.getPPr().isSetSpcAft()) {
+                _p.getPPr().unsetSpcAft();
+            }
+            return;
+        }
+
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTTextSpacing spc = CTTextSpacing.Factory.newInstance();
+
+        if(spaceAfter >= 0) {
+            spc.addNewSpcPct().setVal((int)(spaceAfter*1000));
+        } else {
+            spc.addNewSpcPts().setVal((int)(-spaceAfter*100));
+        }
+        pr.setSpcAft(spc);
+    }
+
+    @Override
+    public Double getSpaceAfter(){
+        ParagraphPropertyFetcher<Double> fetcher = new ParagraphPropertyFetcher<Double>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetSpcAft()){
+                    CTTextSpacing spc = props.getSpcAft();
+
+                    if(spc.isSetSpcPct()) setValue( spc.getSpcPct().getVal()*0.001 );
+                    else if (spc.isSetSpcPts()) setValue( -spc.getSpcPts().getVal()*0.01 );
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue();
+    }
+
+    @Override
+    public void setIndentLevel(int level){
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        pr.setLvl(level);
+    }
+
+    @Override
+    public int getIndentLevel() {
+        CTTextParagraphProperties pr = _p.getPPr();
+        return (pr == null || !pr.isSetLvl()) ? 0 : pr.getLvl();
+    }
+
+    /**
+     * Returns whether this paragraph has bullets
+     */
+    public boolean isBullet() {
+        ParagraphPropertyFetcher<Boolean> fetcher = new ParagraphPropertyFetcher<Boolean>(getIndentLevel()){
+            public boolean fetch(CTTextParagraphProperties props){
+                if(props.isSetBuNone()) {
+                    setValue(false);
+                    return true;
+                }
+                if(props.isSetBuFont() || props.isSetBuChar()){
+                    setValue(true);
+                    return true;
+                }
+                return false;
+            }
+        };
+        fetchParagraphProperty(fetcher);
+        return fetcher.getValue() == null ? false : fetcher.getValue();
+    }
+
+    /**
+     *
+     * @param flag whether text in this paragraph has bullets
+     */
+    public void setBullet(boolean flag) {
+        if(isBullet() == flag) return;
+
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        if(flag) {
+            pr.addNewBuFont().setTypeface("Arial");
+            pr.addNewBuChar().setChar("\u2022");
+        } else {
+            if (pr.isSetBuFont()) pr.unsetBuFont();
+            if (pr.isSetBuChar()) pr.unsetBuChar();
+            if (pr.isSetBuAutoNum()) pr.unsetBuAutoNum();
+            if (pr.isSetBuBlip()) pr.unsetBuBlip();
+            if (pr.isSetBuClr()) pr.unsetBuClr();
+            if (pr.isSetBuClrTx()) pr.unsetBuClrTx();
+            if (pr.isSetBuFont()) pr.unsetBuFont();
+            if (pr.isSetBuFontTx()) pr.unsetBuFontTx();
+            if (pr.isSetBuSzPct()) pr.unsetBuSzPct();
+            if (pr.isSetBuSzPts()) pr.unsetBuSzPts();
+            if (pr.isSetBuSzTx()) pr.unsetBuSzTx();
+            pr.addNewBuNone();
+        }
+    }
+
+    /**
+     * Specifies that automatic numbered bullet points should be applied to this paragraph
+     *
+     * @param scheme type of auto-numbering
+     * @param startAt the number that will start number for a given sequence of automatically
+    numbered bullets (1-based).
+     */
+    public void setBulletAutoNumber(AutoNumberingScheme scheme, int startAt) {
+        if(startAt < 1) throw new IllegalArgumentException("Start Number must be greater or equal that 1") ;
+        CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
+        CTTextAutonumberBullet lst = pr.isSetBuAutoNum() ? pr.getBuAutoNum() : pr.addNewBuAutoNum();
+        lst.setType(STTextAutonumberScheme.Enum.forInt(scheme.ooxmlId));
+        lst.setStartAt(startAt);
+    }
+
+    @Override
+    public String toString(){
+        return "[" + getClass() + "]" + getText();
+    }
+
+
+    /**
+     * @return master style text paragraph properties, or <code>null</code> if 
+     * there are no master slides or the master slides do not contain a text paragraph
+     */
+    /* package */ CTTextParagraphProperties getDefaultMasterStyle(){
+        CTPlaceholder ph = _shape.getCTPlaceholder();
+        String defaultStyleSelector;  
+        switch(ph == null ? -1 : ph.getType().intValue()) {
+            case STPlaceholderType.INT_TITLE:
+            case STPlaceholderType.INT_CTR_TITLE:
+                defaultStyleSelector = "titleStyle";
+                break;
+            case -1: // no placeholder means plain text box
+            case STPlaceholderType.INT_FTR:
+            case STPlaceholderType.INT_SLD_NUM:
+            case STPlaceholderType.INT_DT:
+                defaultStyleSelector = "otherStyle";
+                break;
+            default:
+                defaultStyleSelector = "bodyStyle";
+                break;
+        }
+        int level = getIndentLevel();
+
+        // wind up and find the root master sheet which must be slide master
+        final String nsPML = "http://schemas.openxmlformats.org/presentationml/2006/main";
+        final String nsDML = "http://schemas.openxmlformats.org/drawingml/2006/main";
+        XSLFSheet masterSheet = _shape.getSheet();
+        for (XSLFSheet m = masterSheet; m != null; m = (XSLFSheet)m.getMasterSheet()) {
+            masterSheet = m;
+            XmlObject xo = masterSheet.getXmlObject();
+            XmlCursor cur = xo.newCursor();
+            try {
+                cur.push();
+                if ((cur.toChild(nsPML, "txStyles") && cur.toChild(nsPML, defaultStyleSelector)) ||
+                       (cur.pop() && cur.toChild(nsPML, "notesStyle"))) {
+                    while (level >= 0) {
+                        cur.push();
+                       if (cur.toChild(nsDML, "lvl" +(level+1)+ "pPr")) {
+                               return (CTTextParagraphProperties)cur.getObject();
+                       }
+                       cur.pop();
+                       level--;
+                    }
+                }
+            } finally {
+               cur.dispose();
+            }
+        }
+        
+        return null;
+    }
+
+    private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
+        boolean ok = false;
+        XSLFTextShape shape = getParentShape();
+        XSLFSheet sheet = shape.getSheet();
+        
+        if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
+        if (ok) return true;
+
+        ok = shape.fetchShapeProperty(visitor);
+        if (ok) return true;
+                
+        
+        CTPlaceholder ph = shape.getCTPlaceholder();
+        if(ph == null){
+            // if it is a plain text box then take defaults from presentation.xml
+            @SuppressWarnings("resource")
+            XMLSlideShow ppt = sheet.getSlideShow();
+            CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel());
+            if (themeProps != null) ok = visitor.fetch(themeProps);
+        }
+        if (ok) return true;
+
+        // defaults for placeholders are defined in the slide master
+        CTTextParagraphProperties defaultProps = getDefaultMasterStyle();
+        // TODO: determine master shape
+        if(defaultProps != null) ok = visitor.fetch(defaultProps);
+        if (ok) return true;
+
+        return false;
+    }
+
+    void copy(XSLFTextParagraph other){
+        if (other == this) return;
+        
+        CTTextParagraph thisP = getXmlObject();
+        CTTextParagraph otherP = other.getXmlObject();
+        
+        if (thisP.isSetPPr()) thisP.unsetPPr();
+        if (thisP.isSetEndParaRPr()) thisP.unsetEndParaRPr();
+        
+        _runs.clear();
+        for (int i=thisP.sizeOfBrArray(); i>0; i--) {
+            thisP.removeBr(i-1);
+        }
+        for (int i=thisP.sizeOfRArray(); i>0; i--) {
+            thisP.removeR(i-1);
+        }
+        for (int i=thisP.sizeOfFldArray(); i>0; i--) {
+            thisP.removeFld(i-1);
+        }
+
+        XmlCursor thisC = thisP.newCursor();
+        thisC.toEndToken();
+        XmlCursor otherC = otherP.newCursor();
+        otherC.copyXmlContents(thisC);
+        otherC.dispose();
+        thisC.dispose();
+        
+        List<XSLFTextRun> otherRs = other.getTextRuns();
+        int i=0;
+        for(CTRegularTextRun rtr : thisP.getRArray()) {
+            XSLFTextRun run = newTextRun(rtr);
+            run.copy(otherRs.get(i++));
+            _runs.add(run);
+        }
+        
+        
+        // set properties again, in case we are based on a different
+        // template
+        TextAlign srcAlign = other.getTextAlign();
+        if(srcAlign != getTextAlign()){
+            setTextAlign(srcAlign);
+        }
+
+        boolean isBullet = other.isBullet();
+        if(isBullet != isBullet()){
+            setBullet(isBullet);
+            if(isBullet) {
+                String buFont = other.getBulletFont();
+                if(buFont != null && !buFont.equals(getBulletFont())){
+                    setBulletFont(buFont);
+                }
+                String buChar = other.getBulletCharacter();
+                if(buChar != null && !buChar.equals(getBulletCharacter())){
+                    setBulletCharacter(buChar);
+                }
+                PaintStyle buColor = other.getBulletFontColor();
+                if(buColor != null && !buColor.equals(getBulletFontColor())){
+                    setBulletFontColor(buColor);
+                }
+                Double buSize = other.getBulletFontSize();
+                if(!doubleEquals(buSize, getBulletFontSize())){
+                    setBulletFontSize(buSize);
+                }
+            }
+        }
+
+        Double leftMargin = other.getLeftMargin();
+        if (!doubleEquals(leftMargin, getLeftMargin())){
+            setLeftMargin(leftMargin);
+        }
+
+        Double indent = other.getIndent();
+        if (!doubleEquals(indent, getIndent())) {
+            setIndent(indent);
+        }
+
+        Double spaceAfter = other.getSpaceAfter();
+        if (!doubleEquals(spaceAfter, getSpaceAfter())) {
+            setSpaceAfter(spaceAfter);
+        }
+        
+        Double spaceBefore = other.getSpaceBefore();
+        if (!doubleEquals(spaceBefore, getSpaceBefore())) {
+            setSpaceBefore(spaceBefore);
+        }
+        
+        Double lineSpacing = other.getLineSpacing();
+        if (!doubleEquals(lineSpacing, getLineSpacing())) {
+            setLineSpacing(lineSpacing);
+        }
+    }
+
+    private static boolean doubleEquals(Double d1, Double d2) {
+        return (d1 == d2 || (d1 != null && d1.equals(d2)));
+    }
+    
+    @Override
+    public Double getDefaultFontSize() {
+        CTTextCharacterProperties endPr = _p.getEndParaRPr();
+        if (endPr == null || !endPr.isSetSz()) {
+            // inherit the font size from the master style
+            CTTextParagraphProperties masterStyle = getDefaultMasterStyle();
+            if (masterStyle != null) {
+                endPr = masterStyle.getDefRPr();
+            }
+        }
+        return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100.);
+    }
+
+    @Override
+    public String getDefaultFontFamily() {
+        return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily());
+    }
+
+    @Override
+    public BulletStyle getBulletStyle() {
+        if (!isBullet()) return null;
+        return new BulletStyle(){
+            @Override
+            public String getBulletCharacter() {
+                return XSLFTextParagraph.this.getBulletCharacter();
+            }
+
+            @Override
+            public String getBulletFont() {
+                return XSLFTextParagraph.this.getBulletFont();
+            }
+
+            @Override
+            public Double getBulletFontSize() {
+                return XSLFTextParagraph.this.getBulletFontSize();
+            }
+
+            @Override
+            public PaintStyle getBulletFontColor() {
+                return XSLFTextParagraph.this.getBulletFontColor();
+            }
+            
+            @Override
+            public void setBulletFontColor(Color color) {
+                setBulletFontColor(DrawPaint.createSolidPaint(color));
+            }
+
+            @Override
+            public void setBulletFontColor(PaintStyle color) {
+                XSLFTextParagraph.this.setBulletFontColor(color);
+            }
+            
+            @Override
+            public AutoNumberingScheme getAutoNumberingScheme() {
+                return XSLFTextParagraph.this.getAutoNumberingScheme();
+            }
+
+            @Override
+            public Integer getAutoNumberingStartAt() {
+                return XSLFTextParagraph.this.getAutoNumberingStartAt();
+            }
+
+        };
+    }
+
+    @Override
+    public void setBulletStyle(Object... styles) {
+        if (styles.length == 0) {
+            setBullet(false);
+        } else {
+            setBullet(true);
+            for (Object ostyle : styles) {
+                if (ostyle instanceof Number) {
+                    setBulletFontSize(((Number)ostyle).doubleValue());
+                } else if (ostyle instanceof Color) {
+                    setBulletFontColor((Color)ostyle);
+                } else if (ostyle instanceof Character) {
+                    setBulletCharacter(ostyle.toString());
+                } else if (ostyle instanceof String) {
+                    setBulletFont((String)ostyle);
+                } else if (ostyle instanceof AutoNumberingScheme) {
+                    setBulletAutoNumber((AutoNumberingScheme)ostyle, 0);
+                }
+            }
+        }
+    }
+    
+    /**
+     * Helper method for appending text and keeping paragraph and character properties.
+     * The character properties are moved to the end paragraph marker
+     */
+    /* package */ void clearButKeepProperties() {
+        CTTextParagraph thisP = getXmlObject();
+        for (int i=thisP.sizeOfBrArray(); i>0; i--) {
+            thisP.removeBr(i-1);
+        }
+        for (int i=thisP.sizeOfFldArray(); i>0; i--) {
+            thisP.removeFld(i-1);
+        }
+        if (!_runs.isEmpty()) {
+            int size = _runs.size();
+            XSLFTextRun lastRun = _runs.get(size-1);
+            CTTextCharacterProperties cpOther = lastRun.getRPr(false);
+            if (cpOther != null) {
+                if (thisP.isSetEndParaRPr()) {
+                    thisP.unsetEndParaRPr();
+                }
+                CTTextCharacterProperties cp = thisP.addNewEndParaRPr();
+                cp.set(cpOther);
+            }
+            for (int i=size; i>0; i--) {
+                thisP.removeR(i-1);
+            }
+            _runs.clear();
+        }
+    }
+
+    @Override
+    public boolean isHeaderOrFooter() {
+        CTPlaceholder ph = _shape.getCTPlaceholder();
+        int phId = (ph == null ? -1 : ph.getType().intValue());
+        switch (phId) {
+            case STPlaceholderType.INT_SLD_NUM:
+            case STPlaceholderType.INT_DT:
+            case STPlaceholderType.INT_FTR:
+            case STPlaceholderType.INT_HDR:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Helper method to allow subclasses to provide their own text run
+     *
+     * @param r the xml reference
+     * 
+     * @return a new text paragraph
+     * 
+     * @since POI 3.15-beta2
+     */
+    protected XSLFTextRun newTextRun(CTRegularTextRun r) {
+        return new XSLFTextRun(r, this);
+    }
+}