]> source.dussan.org Git - poi.git/commitdiff
fill in the text body, its paragraphs and text runs
authorAlain Béarez <abearez@apache.org>
Sun, 26 Aug 2018 21:18:54 +0000 (21:18 +0000)
committerAlain Béarez <abearez@apache.org>
Sun, 26 Aug 2018 21:18:54 +0000 (21:18 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1839255 13f79535-47bb-0310-9956-ffa450edef68

48 files changed:
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFColor.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFEffectContainer.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFEffectList.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFExtensionList.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFGradientFillProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFGroupFillProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFLineProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFNoFillProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFPatternFillProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFPicture.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFPictureFillProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFSolidFillProperties.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFChartLegend.java
src/ooxml/java/org/apache/poi/xddf/usermodel/chart/XDDFLegendEntry.java
src/ooxml/java/org/apache/poi/xddf/usermodel/text/AutonumberScheme.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/CapsType.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/FontAlignment.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/StrikeType.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/TabAlignment.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/TextAlignment.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/TextContainer.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/UnderlineType.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFAutoFit.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBodyProperties.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSize.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizeFollowText.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizePercent.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizePoints.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyle.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleAutoNumbered.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleCharacter.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleNone.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStylePicture.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFFont.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFHyperlink.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFNoAutoFit.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFNormalAutoFit.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFParagraphBulletProperties.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFParagraphProperties.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFRunProperties.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFShapeAutoFit.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacing.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacingPercent.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacingPoints.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTabStop.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextBody.java
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextParagraph.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextRun.java [new file with mode: 0644]

index 4e07f46c7ac3f4f77ee369197d44d816e179deba..4c71b77cdc7f511b86cf50909dd514784a9ce945 100644 (file)
@@ -52,7 +52,7 @@ public abstract class XDDFColor {
     }
 
     @Internal
-    protected static XDDFColor forColorContainer(CTColor container) {
+    public static XDDFColor forColorContainer(CTColor container) {
         if (container.isSetHslClr()) {
             return new XDDFColorHsl(container.getHslClr(), container);
         } else if (container.isSetPrstClr()) {
@@ -70,7 +70,7 @@ public abstract class XDDFColor {
     }
 
     @Internal
-    protected CTColor getColorContainer() {
+    public CTColor getColorContainer() {
         return container;
     }
 
index 16fb0415f5e5b9d3de39a0069bd75eee99c80817..97e09b963c786109116d24788734745894e9972e 100644 (file)
@@ -26,7 +26,7 @@ public class XDDFEffectContainer {
     private CTEffectContainer container;
 
     @Internal
-    protected XDDFEffectContainer(CTEffectContainer container) {
+    public XDDFEffectContainer(CTEffectContainer container) {
         this.container = container;
     }
 
index 46e72002d087fbaa63457c146a95eff5fff01406..884dc91c2566e5dbb4cbfd1a3562cd66bad894c2 100644 (file)
@@ -26,7 +26,7 @@ public class XDDFEffectList {
     private CTEffectList list;
 
     @Internal
-    protected XDDFEffectList(CTEffectList list) {
+    public XDDFEffectList(CTEffectList list) {
         this.list = list;
     }
 
index 973dab6e2065c1cb8dce8d8fb194cb6e8b7cc691..c74ab07b30e34d84d7ada3fe634490c983207954 100644 (file)
@@ -26,7 +26,7 @@ public class XDDFExtensionList {
     private CTOfficeArtExtensionList list;
 
     @Internal
-    protected XDDFExtensionList(CTOfficeArtExtensionList list) {
+    public XDDFExtensionList(CTOfficeArtExtensionList list) {
         this.list = list;
     }
 
index fd97f3d3732d9b9674e29cb78aa6ab0e1889d7ec..c46a58bb29dbae1f0a13c99e28d620de3c04be90 100644 (file)
@@ -38,7 +38,7 @@ public class XDDFGradientFillProperties implements XDDFFillProperties {
     }
 
     @Internal
-    protected CTGradientFillProperties getXmlObject() {
+    public CTGradientFillProperties getXmlObject() {
         return props;
     }
 
index 0a1f55805725c06b1e0431e4ad4abd5721f7980e..52edb95c84d4f1ac7cbc6a59361d42b00b334594 100644 (file)
@@ -34,7 +34,7 @@ public class XDDFGroupFillProperties implements XDDFFillProperties {
     }
 
     @Internal
-    protected CTGroupFillProperties getXmlObject() {
+    public CTGroupFillProperties getXmlObject() {
         return props;
     }
 }
index 794a751cbc5501a0ff6caaa18c02d95913485bcb..6f8242e44d7c64fd6d36198f3376fc81d97281f8 100644 (file)
@@ -34,12 +34,12 @@ public class XDDFLineProperties {
     }
 
     @Internal
-    protected XDDFLineProperties(CTLineProperties properties) {
+    public XDDFLineProperties(CTLineProperties properties) {
         this.props = properties;
     }
 
     @Internal
-    protected CTLineProperties getXmlObject() {
+    public CTLineProperties getXmlObject() {
         return props;
     }
 
index ae15aa8c9a50cd6d153d9b42aee384b58aaec625..a379399b55b7c46f334e1236301e6179c5c63b98 100644 (file)
@@ -34,7 +34,7 @@ public class XDDFNoFillProperties implements XDDFFillProperties {
     }
 
     @Internal
-    protected CTNoFillProperties getXmlObject() {
+    public CTNoFillProperties getXmlObject() {
         return props;
     }
 }
index b0daca96b8f17db3545484432c36eef2cebdfc18..bf34c7a893d12a200a157487ed2ef248fff2d2fb 100644 (file)
@@ -34,7 +34,7 @@ public class XDDFPatternFillProperties implements XDDFFillProperties {
     }
 
     @Internal
-    protected CTPatternFillProperties getXmlObject() {
+    public CTPatternFillProperties getXmlObject() {
         return props;
     }
 
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFPicture.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/XDDFPicture.java
new file mode 100644 (file)
index 0000000..873107a
--- /dev/null
@@ -0,0 +1,37 @@
+/* ====================================================================
+   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;
+
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
+
+@Beta
+public class XDDFPicture {
+    private CTBlip blip;
+
+    @Internal
+    public XDDFPicture(CTBlip blip) {
+        this.blip = blip;
+    }
+
+    @Internal
+    public CTBlip getXmlObject() {
+        return blip;
+    }
+}
index 0064f14c8f5474c6a337069644653fa275665d5d..2999d51e26634d86fc6cf5274b8f4f683ece599c 100644 (file)
@@ -19,7 +19,6 @@ package org.apache.poi.xddf.usermodel;
 
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
-import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTBlipFillProperties;
 
 @Beta
@@ -35,27 +34,23 @@ public class XDDFPictureFillProperties implements XDDFFillProperties {
     }
 
     @Internal
-    protected CTBlipFillProperties getXmlObject() {
+    public CTBlipFillProperties getXmlObject() {
         return props;
     }
 
-    @Internal
-    public CTBlip getCTBlip() {
+    public XDDFPicture getPicture() {
         if (props.isSetBlip()) {
-            return props.getBlip();
+            return new XDDFPicture(props.getBlip());
         } else {
             return null;
         }
     }
 
-    @Internal
-    public void setBlip(CTBlip blip) {
-        if (blip == null) {
-            if (props.isSetBlip()) {
-                props.unsetBlip();
-            }
+    public void setPicture(XDDFPicture picture) {
+        if (picture == null) {
+            props.unsetBlip();
         } else {
-            props.setBlip(blip);
+            props.setBlip(picture.getXmlObject());
         }
     }
 
index 22b8d19802386a49d1615a4f10e27cdcb8765990..1272cb50c441ffec129230498f35467cb8e9732a 100644 (file)
@@ -40,12 +40,13 @@ public class XDDFSolidFillProperties implements XDDFFillProperties {
         setColor(color);
     }
 
-    protected XDDFSolidFillProperties(CTSolidColorFillProperties properties) {
+    @Internal
+    public XDDFSolidFillProperties(CTSolidColorFillProperties properties) {
         this.props = properties;
     }
 
     @Internal
-    protected CTSolidColorFillProperties getXmlObject() {
+    public CTSolidColorFillProperties getXmlObject() {
         return props;
     }
 
index 2c5794e6f1c1510a5425e40fc1af5627edc61276..003e613e2298b943dce792ddefb2e095d3684508 100644 (file)
 package org.apache.poi.xddf.usermodel.chart;
 
 import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.text.TextContainer;
 import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
 import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
 import org.openxmlformats.schemas.drawingml.x2006.chart.CTLegend;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
 
 /**
  * Represents a DrawingML chart legend
  */
 @Beta
-public final class XDDFChartLegend {
+public final class XDDFChartLegend implements TextContainer {
 
     /**
      * Underlying CTLegend bean
@@ -89,7 +94,7 @@ public final class XDDFChartLegend {
 
     public XDDFTextBody getTextBody() {
         if (legend.isSetTxPr()) {
-            return new XDDFTextBody(legend.getTxPr());
+            return new XDDFTextBody(this, legend.getTxPr());
         } else {
             return null;
         }
@@ -189,4 +194,16 @@ public final class XDDFChartLegend {
     public void setOverlay(boolean value) {
         legend.getOverlay().setVal(value);
     }
+
+    public <R> Optional<R> findDefinedParagraphProperty(
+            Function<CTTextParagraphProperties, Boolean> isSet,
+            Function<CTTextParagraphProperties, R> getter) {
+        return Optional.empty(); // chart legend has no (indirect) paragraph properties
+    }
+
+    public <R> Optional<R> findDefinedRunProperty(
+            Function<CTTextCharacterProperties, Boolean> isSet,
+            Function<CTTextCharacterProperties, R> getter) {
+        return Optional.empty(); // chart legend has no (indirect) paragraph properties
+    }
 }
index bedc95466244394254a0c852aae9a54da4a9c7b0..cf985f8d6dce8e40d1c0240842350c5a6e6e22e1 100644 (file)
 
 package org.apache.poi.xddf.usermodel.chart;
 
+import java.util.Optional;
+import java.util.function.Function;
+
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.text.TextContainer;
 import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
 import org.openxmlformats.schemas.drawingml.x2006.chart.CTLegendEntry;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
 
 @Beta
-public class XDDFLegendEntry {
+public class XDDFLegendEntry implements TextContainer {
     private CTLegendEntry entry;
 
     @Internal
@@ -38,7 +44,7 @@ public class XDDFLegendEntry {
 
     public XDDFTextBody getTextBody() {
         if (entry.isSetTxPr()) {
-            return new XDDFTextBody(entry.getTxPr());
+            return new XDDFTextBody(this, entry.getTxPr());
         } else {
             return null;
         }
@@ -101,4 +107,16 @@ public class XDDFLegendEntry {
             return null;
         }
     }
+
+    public <R> Optional<R> findDefinedParagraphProperty(
+            Function<CTTextParagraphProperties, Boolean> isSet,
+            Function<CTTextParagraphProperties, R> getter) {
+        return Optional.empty(); // legend entry has no (indirect) paragraph properties
+    }
+
+    public <R> Optional<R> findDefinedRunProperty(
+            Function<CTTextCharacterProperties, Boolean> isSet,
+            Function<CTTextCharacterProperties, R> getter) {
+        return Optional.empty(); // legend entry has no (indirect) paragraph properties
+    }
 }
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/AutonumberScheme.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/AutonumberScheme.java
new file mode 100644 (file)
index 0000000..86afc30
--- /dev/null
@@ -0,0 +1,83 @@
+/* ====================================================================
+   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 java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;
+
+public enum AutonumberScheme {
+    ALPHABETIC_LOWERCASE_PARENTHESES_BOTH(STTextAutonumberScheme.ALPHA_LC_PAREN_BOTH),
+    ALPHABETIC_LOWERCASE_PARENTHESIS_RIGHT(STTextAutonumberScheme.ALPHA_LC_PAREN_R),
+    ALPHABETIC_LOWERCASE_PERIOD(STTextAutonumberScheme.ALPHA_LC_PERIOD),
+    ALPHABETIC_UPPERCASE_PARENTHESES_BOTH(STTextAutonumberScheme.ALPHA_UC_PAREN_BOTH),
+    ALPHABETIC_UPPERCASE_PARENTHESIS_RIGHT(STTextAutonumberScheme.ALPHA_UC_PAREN_R),
+    ALPHABETIC_UPPERCASE_PERIOD(STTextAutonumberScheme.ALPHA_UC_PERIOD),
+    ARABIC_1_MINUS(STTextAutonumberScheme.ARABIC_1_MINUS),
+    ARABIC_2_MINUS(STTextAutonumberScheme.ARABIC_2_MINUS),
+    ARABIC_DOUBLE_BYTE_PERIOD(STTextAutonumberScheme.ARABIC_DB_PERIOD),
+    ARABIC_DOUBLE_BYTE_PLAIN(STTextAutonumberScheme.ARABIC_DB_PLAIN),
+    ARABIC_PARENTHESES_BOTH(STTextAutonumberScheme.ARABIC_PAREN_BOTH),
+    ARABIC_PARENTHESIS_RIGHT(STTextAutonumberScheme.ARABIC_PAREN_R),
+    ARABIC_PERIOD(STTextAutonumberScheme.ARABIC_PERIOD),
+    ARABIC_PLAIN(STTextAutonumberScheme.ARABIC_PLAIN),
+    CIRCLE_NUMBER_DOUBLE_BYTE_PLAIN(STTextAutonumberScheme.CIRCLE_NUM_DB_PLAIN),
+    CIRCLE_NUMBER_WINGDINGS_BLACK_PLAIN(STTextAutonumberScheme.CIRCLE_NUM_WD_BLACK_PLAIN),
+    CIRCLE_NUMBER_WINGDINGS_WHITE_PLAIN(STTextAutonumberScheme.CIRCLE_NUM_WD_WHITE_PLAIN),
+    EAST_ASIAN_CHINESE_SIMPLIFIED_PERIOD(STTextAutonumberScheme.EA_1_CHS_PERIOD),
+    EAST_ASIAN_CHINESE_SIMPLIFIED_PLAIN(STTextAutonumberScheme.EA_1_CHS_PLAIN),
+    EAST_ASIAN_CHINESE_TRADITIONAL_PERIOD(STTextAutonumberScheme.EA_1_CHT_PERIOD),
+    EAST_ASIAN_CHINESE_TRADITIONAL_PLAIN(STTextAutonumberScheme.EA_1_CHT_PLAIN),
+    EAST_ASIAN_JAPANESE_DOUBLE_BYTE_PERIOD(STTextAutonumberScheme.EA_1_JPN_CHS_DB_PERIOD),
+    EAST_ASIAN_JAPANESE_KOREAN_PERIOD(STTextAutonumberScheme.EA_1_JPN_KOR_PERIOD),
+    EAST_ASIAN_JAPANESE_KOREAN_PLAIN(STTextAutonumberScheme.EA_1_JPN_KOR_PLAIN),
+    HEBREW_2_MINUS(STTextAutonumberScheme.HEBREW_2_MINUS),
+    HINDI_ALPHA_1_PERIOD(STTextAutonumberScheme.HINDI_ALPHA_1_PERIOD),
+    HINDI_ALPHA_PERIOD(STTextAutonumberScheme.HINDI_ALPHA_PERIOD),
+    HINDI_NUMBER_PARENTHESIS_RIGHT(STTextAutonumberScheme.HINDI_NUM_PAREN_R),
+    HINDI_NUMBER_PERIOD(STTextAutonumberScheme.HINDI_NUM_PERIOD),
+    ROMAN_LOWERCASE_PARENTHESES_BOTH(STTextAutonumberScheme.ROMAN_LC_PAREN_BOTH),
+    ROMAN_LOWERCASE_PARENTHESIS_RIGHT(STTextAutonumberScheme.ROMAN_LC_PAREN_R),
+    ROMAN_LOWERCASE_PERIOD(STTextAutonumberScheme.ROMAN_LC_PERIOD),
+    ROMAN_UPPERCASE_PARENTHESES_BOTH(STTextAutonumberScheme.ROMAN_UC_PAREN_BOTH),
+    ROMAN_UPPERCASE_PARENTHESIS_RIGHT(STTextAutonumberScheme.ROMAN_UC_PAREN_R),
+    ROMAN_UPPERCASE_PERIOD(STTextAutonumberScheme.ROMAN_UC_PERIOD),
+    THAI_ALPHABETIC_PARENTHESES_BOTH(STTextAutonumberScheme.THAI_ALPHA_PAREN_BOTH),
+    THAI_ALPHABETIC_PARENTHESIS_RIGHT(STTextAutonumberScheme.THAI_ALPHA_PAREN_R),
+    THAI_ALPHABETIC_PERIOD(STTextAutonumberScheme.THAI_ALPHA_PERIOD),
+    THAI_NUMBER_PARENTHESES_BOTH(STTextAutonumberScheme.THAI_NUM_PAREN_BOTH),
+    THAI_NUMBER_PARENTHESIS_RIGHT(STTextAutonumberScheme.THAI_NUM_PAREN_R),
+    THAI_NUMBER_PERIOD(STTextAutonumberScheme.THAI_NUM_PERIOD);
+
+    final STTextAutonumberScheme.Enum underlying;
+
+    AutonumberScheme(STTextAutonumberScheme.Enum scheme) {
+        this.underlying = scheme;
+    }
+
+    private final static HashMap<STTextAutonumberScheme.Enum, AutonumberScheme> reverse = new HashMap<STTextAutonumberScheme.Enum, AutonumberScheme>();
+    static {
+        for (AutonumberScheme value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static AutonumberScheme valueOf(STTextAutonumberScheme.Enum scheme) {
+        return reverse.get(scheme);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/CapsType.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/CapsType.java
new file mode 100644 (file)
index 0000000..ecf942c
--- /dev/null
@@ -0,0 +1,45 @@
+/* ====================================================================
+   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 java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextCapsType;
+
+public enum CapsType {
+    ALL(STTextCapsType.ALL),
+    NONE(STTextCapsType.NONE),
+    SMALL(STTextCapsType.SMALL);
+
+    final STTextCapsType.Enum underlying;
+
+    CapsType(STTextCapsType.Enum caps) {
+        this.underlying = caps;
+    }
+
+    private final static HashMap<STTextCapsType.Enum, CapsType> reverse = new HashMap<STTextCapsType.Enum, CapsType>();
+    static {
+        for (CapsType value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static CapsType valueOf(STTextCapsType.Enum caps) {
+        return reverse.get(caps);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/FontAlignment.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/FontAlignment.java
new file mode 100644 (file)
index 0000000..655d2ea
--- /dev/null
@@ -0,0 +1,47 @@
+/* ====================================================================
+   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 java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextFontAlignType;
+
+public enum FontAlignment {
+    AUTOMATIC(STTextFontAlignType.AUTO),
+    BOTTOM(STTextFontAlignType.B),
+    BASELINE(STTextFontAlignType.BASE),
+    CENTER(STTextFontAlignType.CTR),
+    TOP(STTextFontAlignType.T);
+
+    final STTextFontAlignType.Enum underlying;
+
+    FontAlignment(STTextFontAlignType.Enum align) {
+        this.underlying = align;
+    }
+
+    private final static HashMap<STTextFontAlignType.Enum, FontAlignment> reverse = new HashMap<STTextFontAlignType.Enum, FontAlignment>();
+    static {
+        for (FontAlignment value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static FontAlignment valueOf(STTextFontAlignType.Enum align) {
+        return reverse.get(align);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/StrikeType.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/StrikeType.java
new file mode 100644 (file)
index 0000000..c28dbbc
--- /dev/null
@@ -0,0 +1,45 @@
+/* ====================================================================
+   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 java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
+
+public enum StrikeType {
+    DOUBLE_STRIKE(STTextStrikeType.DBL_STRIKE),
+    NO_STRIKE(STTextStrikeType.NO_STRIKE),
+    SINGLE_STRIKE(STTextStrikeType.SNG_STRIKE);
+
+    final STTextStrikeType.Enum underlying;
+
+    StrikeType(STTextStrikeType.Enum strike) {
+        this.underlying = strike;
+    }
+
+    private final static HashMap<STTextStrikeType.Enum, StrikeType> reverse = new HashMap<STTextStrikeType.Enum, StrikeType>();
+    static {
+        for (StrikeType value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static StrikeType valueOf(STTextStrikeType.Enum strike) {
+        return reverse.get(strike);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/TabAlignment.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/TabAlignment.java
new file mode 100644 (file)
index 0000000..32a873a
--- /dev/null
@@ -0,0 +1,46 @@
+/* ====================================================================
+   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 java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextTabAlignType;
+
+public enum TabAlignment {
+    CENTER(STTextTabAlignType.CTR),
+    DECIMAL(STTextTabAlignType.DEC),
+    LEFT(STTextTabAlignType.L),
+    RIGHT(STTextTabAlignType.R);
+
+    final STTextTabAlignType.Enum underlying;
+
+    TabAlignment(STTextTabAlignType.Enum align) {
+        this.underlying = align;
+    }
+
+    private final static HashMap<STTextTabAlignType.Enum, TabAlignment> reverse = new HashMap<STTextTabAlignType.Enum, TabAlignment>();
+    static {
+        for (TabAlignment value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static TabAlignment valueOf(STTextTabAlignType.Enum align) {
+        return reverse.get(align);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/TextAlignment.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/TextAlignment.java
new file mode 100644 (file)
index 0000000..c2ef4ea
--- /dev/null
@@ -0,0 +1,49 @@
+/* ====================================================================
+   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 java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
+
+public enum TextAlignment {
+    CENTER(STTextAlignType.CTR),
+    DISTRIBUTED(STTextAlignType.DIST),
+    JUSTIFIED(STTextAlignType.JUST),
+    JUSTIFIED_LOW(STTextAlignType.JUST_LOW),
+    LEFT(STTextAlignType.L),
+    RIGHT(STTextAlignType.R),
+    THAI_DISTRIBUTED(STTextAlignType.THAI_DIST);
+
+    final STTextAlignType.Enum underlying;
+
+    TextAlignment(STTextAlignType.Enum align) {
+        this.underlying = align;
+    }
+
+    private final static HashMap<STTextAlignType.Enum, TextAlignment> reverse = new HashMap<STTextAlignType.Enum, TextAlignment>();
+    static {
+        for (TextAlignment value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static TextAlignment valueOf(STTextAlignType.Enum align) {
+        return reverse.get(align);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/TextContainer.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/TextContainer.java
new file mode 100644 (file)
index 0000000..9e11d21
--- /dev/null
@@ -0,0 +1,36 @@
+/* ====================================================================
+   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 java.util.Optional;
+import java.util.function.Function;
+
+import org.apache.poi.util.Beta;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+
+@Beta
+public interface TextContainer {
+
+    <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
+        Function<CTTextParagraphProperties, R> getter);
+
+    <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
+        Function<CTTextCharacterProperties, R> getter);
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/UnderlineType.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/UnderlineType.java
new file mode 100644 (file)
index 0000000..6a6fae0
--- /dev/null
@@ -0,0 +1,60 @@
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
+package org.apache.poi.xddf.usermodel.text;
+
+import java.util.HashMap;
+
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
+
+public enum UnderlineType {
+    DASH(STTextUnderlineType.DASH),
+    DASH_HEAVY(STTextUnderlineType.DASH_HEAVY),
+    DASH_LONG(STTextUnderlineType.DASH_LONG),
+    DASH_LONG_HEAVY(STTextUnderlineType.DASH_LONG_HEAVY),
+    DOUBLE(STTextUnderlineType.DBL),
+    DOT_DASH(STTextUnderlineType.DOT_DASH),
+    DOT_DASH_HEAVY(STTextUnderlineType.DOT_DASH_HEAVY),
+    DOT_DOT_DASH(STTextUnderlineType.DOT_DOT_DASH),
+    DOT_DOT_DASH_HEAVY(STTextUnderlineType.DOT_DOT_DASH_HEAVY),
+    DOTTED(STTextUnderlineType.DOTTED),
+    DOTTED_HEAVY(STTextUnderlineType.DOTTED_HEAVY),
+    HEAVY(STTextUnderlineType.HEAVY),
+    NONE(STTextUnderlineType.NONE),
+    SINGLE(STTextUnderlineType.SNG),
+    WAVY(STTextUnderlineType.WAVY),
+    WAVY_DOUBLE(STTextUnderlineType.WAVY_DBL),
+    WAVY_HEAVY(STTextUnderlineType.WAVY_HEAVY),
+    WORDS(STTextUnderlineType.WORDS);
+
+    final STTextUnderlineType.Enum underlying;
+
+    UnderlineType(STTextUnderlineType.Enum underline) {
+        this.underlying = underline;
+    }
+
+    private final static HashMap<STTextUnderlineType.Enum, UnderlineType> reverse = new HashMap<STTextUnderlineType.Enum, UnderlineType>();
+    static {
+        for (UnderlineType value : values()) {
+            reverse.put(value.underlying, value);
+        }
+    }
+
+    static UnderlineType valueOf(STTextUnderlineType.Enum underline) {
+        return reverse.get(underline);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFAutoFit.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFAutoFit.java
new file mode 100644 (file)
index 0000000..e9be970
--- /dev/null
@@ -0,0 +1,26 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+
+@Beta
+public interface XDDFAutoFit {
+    int getFontScale();
+    int getLineSpaceReduction();
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBodyProperties.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBodyProperties.java
new file mode 100644 (file)
index 0000000..d21a76c
--- /dev/null
@@ -0,0 +1,78 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.XDDFExtensionList;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
+
+@Beta
+public class XDDFBodyProperties {
+    private CTTextBodyProperties props;
+
+    @Internal
+    protected XDDFBodyProperties(CTTextBodyProperties properties) {
+        this.props = properties;
+    }
+
+    @Internal
+    protected CTTextBodyProperties getXmlObject() {
+        return props;
+    }
+
+    public XDDFAutoFit getAutoFit() {
+        if (props.isSetNoAutofit()) {
+            return new XDDFNoAutoFit(props.getNoAutofit());
+        } else if (props.isSetNormAutofit()) {
+            return new XDDFNormalAutoFit(props.getNormAutofit());
+        } else if (props.isSetSpAutoFit()) {
+            return new XDDFShapeAutoFit(props.getSpAutoFit());
+        }
+        return new XDDFNoAutoFit();
+    }
+
+    public void setAutoFit(XDDFAutoFit autofit) {
+        props.unsetNoAutofit();
+        props.unsetNormAutofit();
+        props.unsetSpAutoFit();
+        if (autofit instanceof XDDFNoAutoFit) {
+            props.setNoAutofit(((XDDFNoAutoFit) autofit).getXmlObject());
+        } else if (autofit instanceof XDDFNormalAutoFit) {
+            props.setNormAutofit(((XDDFNormalAutoFit) autofit).getXmlObject());
+        } else if (autofit instanceof XDDFShapeAutoFit) {
+            props.setSpAutoFit(((XDDFShapeAutoFit) autofit).getXmlObject());
+        }
+    }
+
+    public XDDFExtensionList getExtensionList() {
+        if (props.isSetExtLst()) {
+            return new XDDFExtensionList(props.getExtLst());
+        } else {
+            return null;
+        }
+    }
+
+    public void setExtensionList(XDDFExtensionList list) {
+        if (list == null) {
+            props.unsetExtLst();
+        } else {
+            props.setExtLst(list.getXmlObject());
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSize.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSize.java
new file mode 100644 (file)
index 0000000..6bdbd25
--- /dev/null
@@ -0,0 +1,36 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+
+@Beta
+public abstract class XDDFBulletSize {
+    public static enum Kind {
+        PERCENT,
+        POINTS,
+        TEXT;
+    }
+
+    @Internal
+    protected XDDFBulletSize() {
+    }
+
+    public abstract Kind getType();
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizeFollowText.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizeFollowText.java
new file mode 100644 (file)
index 0000000..39da4c2
--- /dev/null
@@ -0,0 +1,46 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizeFollowText;
+
+@Beta
+public class XDDFBulletSizeFollowText extends XDDFBulletSize {
+    private CTTextBulletSizeFollowText follow;
+
+    public XDDFBulletSizeFollowText() {
+        this(CTTextBulletSizeFollowText.Factory.newInstance());
+    }
+
+    @Internal
+    protected XDDFBulletSizeFollowText(CTTextBulletSizeFollowText follow) {
+        this.follow = follow;
+    }
+
+    @Internal
+    protected CTTextBulletSizeFollowText getXmlObject() {
+        return follow;
+    }
+
+    @Override
+    public Kind getType() {
+        return Kind.TEXT;
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizePercent.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizePercent.java
new file mode 100644 (file)
index 0000000..90f8de2
--- /dev/null
@@ -0,0 +1,57 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;
+
+@Beta
+public class XDDFBulletSizePercent extends XDDFBulletSize {
+    private CTTextBulletSizePercent percent;
+    private Double scale;
+
+    public XDDFBulletSizePercent(double value) {
+        this(CTTextBulletSizePercent.Factory.newInstance(), null);
+        setPercent(value);
+    }
+
+    @Internal
+    protected XDDFBulletSizePercent(CTTextBulletSizePercent percent, Double scale) {
+        this.percent = percent;
+        this.scale = (scale == null) ? 0.001 : scale * 0.001;
+    }
+
+    @Internal
+    protected CTTextBulletSizePercent getXmlObject() {
+        return percent;
+    }
+
+    @Override
+    public Kind getType() {
+        return Kind.PERCENT;
+    }
+
+    public double getPercent() {
+        return percent.getVal() * scale;
+    }
+
+    public void setPercent(double value) {
+        percent.setVal((int)(1000 * value));
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizePoints.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletSizePoints.java
new file mode 100644 (file)
index 0000000..dbabf3c
--- /dev/null
@@ -0,0 +1,55 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;
+
+@Beta
+public class XDDFBulletSizePoints extends XDDFBulletSize {
+    private CTTextBulletSizePoint points;
+
+    public XDDFBulletSizePoints(double value) {
+        this(CTTextBulletSizePoint.Factory.newInstance());
+        setPoints(value);
+    }
+
+    @Internal
+    protected XDDFBulletSizePoints(CTTextBulletSizePoint points) {
+        this.points = points;
+    }
+
+    @Internal
+    protected CTTextBulletSizePoint getXmlObject() {
+        return points;
+    }
+
+    @Override
+    public Kind getType() {
+        return Kind.POINTS;
+    }
+
+    public double getPoints() {
+        return points.getVal() * 0.01;
+    }
+
+    public void setPoints(double value) {
+        points.setVal((int)(100 * value));
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyle.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyle.java
new file mode 100644 (file)
index 0000000..93f2c98
--- /dev/null
@@ -0,0 +1,25 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+
+@Beta
+public abstract class XDDFBulletStyle {
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleAutoNumbered.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleAutoNumbered.java
new file mode 100644 (file)
index 0000000..086a1ce
--- /dev/null
@@ -0,0 +1,61 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;
+
+@Beta
+public class XDDFBulletStyleAutoNumbered extends XDDFBulletStyle {
+    private CTTextAutonumberBullet style;
+
+    @Internal
+    protected XDDFBulletStyleAutoNumbered(CTTextAutonumberBullet style) {
+        this.style =style;
+    }
+
+    @Internal
+    protected CTTextAutonumberBullet getXmlObject() {
+        return style;
+    }
+
+    public AutonumberScheme getType() {
+        return AutonumberScheme.valueOf(style.getType());
+    }
+
+    public void setType(AutonumberScheme scheme) {
+        style.setType(scheme.underlying);
+    }
+
+    public int getStartAt() {
+        if (style.isSetStartAt()) {
+            return style.getStartAt();
+        } else {
+            return 1;
+        }
+    }
+
+    public void setStartAt(Integer value) {
+        if (value == null) {
+            style.unsetStartAt();
+        } else {
+            style.setStartAt(value);
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleCharacter.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleCharacter.java
new file mode 100644 (file)
index 0000000..f8e21e5
--- /dev/null
@@ -0,0 +1,45 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;
+
+@Beta
+public class XDDFBulletStyleCharacter extends XDDFBulletStyle {
+    private CTTextCharBullet style;
+
+    @Internal
+    protected XDDFBulletStyleCharacter(CTTextCharBullet style) {
+        this.style = style;
+    }
+
+    @Internal
+    protected CTTextCharBullet getXmlObject() {
+        return style;
+    }
+
+    public String getCharacter() {
+        return style.getChar();
+    }
+
+    public void setCharacter(String value) {
+        style.setChar(value);
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleNone.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStyleNone.java
new file mode 100644 (file)
index 0000000..db9744c
--- /dev/null
@@ -0,0 +1,37 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNoBullet;
+
+@Beta
+public class XDDFBulletStyleNone extends XDDFBulletStyle {
+    private CTTextNoBullet style;
+
+    @Internal
+    protected XDDFBulletStyleNone(CTTextNoBullet style) {
+        this.style = style;
+    }
+
+    @Internal
+    protected CTTextNoBullet getXmlObject() {
+        return style;
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStylePicture.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFBulletStylePicture.java
new file mode 100644 (file)
index 0000000..2684b9d
--- /dev/null
@@ -0,0 +1,48 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.XDDFPicture;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBlipBullet;
+
+@Beta
+public class XDDFBulletStylePicture extends XDDFBulletStyle {
+    private CTTextBlipBullet style;
+
+    @Internal
+    protected XDDFBulletStylePicture(CTTextBlipBullet style) {
+        this.style = style;
+    }
+
+    @Internal
+    protected CTTextBlipBullet getXmlObject() {
+        return style;
+    }
+
+    public XDDFPicture getPicture() {
+        return new XDDFPicture(style.getBlip());
+    }
+
+    public void setPicture(XDDFPicture picture) {
+        if (picture != null) {
+            style.setBlip(picture.getXmlObject());
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFFont.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFFont.java
new file mode 100644 (file)
index 0000000..7b1bbba
--- /dev/null
@@ -0,0 +1,104 @@
+/* ====================================================================
+   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 org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
+
+@Beta
+public class XDDFFont {
+    private FontGroup group;
+    private CTTextFont font;
+
+    public static XDDFFont unsetFontForGroup(FontGroup group) {
+        return new XDDFFont(group, null);
+    }
+
+    public XDDFFont(FontGroup group, String typeface, Byte charset, Byte pitch, byte[] panose) {
+        this(group, CTTextFont.Factory.newInstance());
+        if (typeface == null) {
+            font.unsetTypeface();
+        } else {
+            font.setTypeface(typeface);
+        }
+        if (charset == null) {
+            font.unsetCharset();
+        } else {
+            font.setCharset(charset);
+        }
+        if (pitch == null) {
+            font.unsetPitchFamily();
+        } else {
+            font.setPitchFamily(pitch);
+        }
+        if (panose == null || panose.length == 0) {
+            font.unsetPanose();
+        } else {
+            font.setPanose(panose);
+        }
+    }
+
+    @Internal
+    protected XDDFFont(FontGroup group, CTTextFont font) {
+        this.group = group;
+        this.font = font;
+    }
+
+    @Internal
+    protected CTTextFont getXmlObject() {
+        return font;
+    }
+
+    public FontGroup getGroup() {
+        return group;
+    }
+
+    public String getTypeface() {
+        if (font.isSetTypeface()) {
+            return font.getTypeface();
+        } else {
+            return null;
+        }
+    }
+
+    public Byte getCharset() {
+        if (font.isSetCharset()) {
+            return font.getCharset();
+        } else {
+            return null;
+        }
+    }
+
+    public Byte getPitchFamily() {
+        if (font.isSetPitchFamily()) {
+            return font.getPitchFamily();
+        } else {
+            return null;
+        }
+    }
+
+    public byte[] getPanose() {
+        if (font.isSetPanose()) {
+            return font.getPanose();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFHyperlink.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFHyperlink.java
new file mode 100644 (file)
index 0000000..879e224
--- /dev/null
@@ -0,0 +1,176 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.XDDFExtensionList;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
+
+@Beta
+public class XDDFHyperlink {
+    private CTHyperlink link;
+
+    public XDDFHyperlink(String id) {
+        this(CTHyperlink.Factory.newInstance());
+        this.link.setId(id);;
+    }
+
+    public XDDFHyperlink(String id, String action) {
+        this(id);
+        this.link.setAction(action);
+    }
+
+    @Internal
+    protected XDDFHyperlink(CTHyperlink link) {
+        this.link = link;
+    }
+
+    @Internal
+    protected CTHyperlink getXmlObject() {
+        return link;
+    }
+
+    public String getAction() {
+        if (link.isSetAction()) {
+            return link.getAction();
+        } else {
+            return null;
+        }
+    }
+
+    public String getId() {
+        if (link.isSetId()) {
+            return link.getId();
+        } else {
+            return null;
+        }
+    }
+
+    public Boolean getEndSound() {
+        if (link.isSetEndSnd()) {
+            return link.getEndSnd();
+        } else {
+            return null;
+        }
+    }
+
+    public void setEndSound(Boolean ends) {
+        if (ends == null) {
+            link.unsetEndSnd();
+        } else {
+            link.setEndSnd(ends);
+        }
+    }
+
+    public Boolean getHighlightClick() {
+        if (link.isSetHighlightClick()) {
+            return link.getHighlightClick();
+        } else {
+            return null;
+        }
+    }
+
+    public void setHighlightClick(Boolean highlights) {
+        if (highlights == null) {
+            link.unsetHighlightClick();
+        } else {
+            link.setHighlightClick(highlights);
+        }
+    }
+    public Boolean getHistory() {
+        if (link.isSetHistory()) {
+            return link.getHistory();
+        } else {
+            return null;
+        }
+    }
+
+    public void setHistory(Boolean history) {
+        if (history == null) {
+            link.unsetHistory();
+        } else {
+            link.setHistory(history);
+        }
+    }
+
+
+    public String getInvalidURL() {
+        if (link.isSetInvalidUrl()) {
+            return link.getInvalidUrl();
+        } else {
+            return null;
+        }
+    }
+
+    public void setInvalidURL(String invalid) {
+        if (invalid == null) {
+            link.unsetInvalidUrl();
+        } else {
+            link.setInvalidUrl(invalid);
+        }
+    }
+
+    public String getTargetFrame() {
+        if (link.isSetTgtFrame()) {
+            return link.getTgtFrame();
+        } else {
+            return null;
+        }
+    }
+
+    public void setTargetFrame(String frame) {
+        if (frame == null) {
+            link.unsetTgtFrame();
+        } else {
+            link.setTgtFrame(frame);
+        }
+    }
+
+    public String getTooltip() {
+        if (link.isSetTooltip()) {
+            return link.getTooltip();
+        } else {
+            return null;
+        }
+    }
+
+    public void setTooltip(String tooltip) {
+        if (tooltip == null) {
+            link.unsetTooltip();
+        } else {
+            link.setTooltip(tooltip);
+        }
+    }
+
+    public XDDFExtensionList getExtensionList() {
+        if (link.isSetExtLst()) {
+            return new XDDFExtensionList(link.getExtLst());
+        } else {
+            return null;
+        }
+    }
+
+    public void setExtensionList(XDDFExtensionList list) {
+        if (list == null) {
+            link.unsetExtLst();
+        } else {
+            link.setExtLst(list.getXmlObject());
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFNoAutoFit.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFNoAutoFit.java
new file mode 100644 (file)
index 0000000..16070a4
--- /dev/null
@@ -0,0 +1,51 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNoAutofit;
+
+@Beta
+public class XDDFNoAutoFit implements XDDFAutoFit {
+    private CTTextNoAutofit autofit;
+
+    public XDDFNoAutoFit() {
+        this(CTTextNoAutofit.Factory.newInstance());
+    }
+
+    @Internal
+    protected XDDFNoAutoFit(CTTextNoAutofit autofit) {
+        this.autofit = autofit;
+    }
+
+    @Internal
+    protected CTTextNoAutofit getXmlObject() {
+        return autofit;
+    }
+
+    @Override
+    public int getFontScale() {
+        return 100_000;
+    }
+
+    @Override
+    public int getLineSpaceReduction() {
+        return 0;
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFNormalAutoFit.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFNormalAutoFit.java
new file mode 100644 (file)
index 0000000..d5266d7
--- /dev/null
@@ -0,0 +1,75 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
+
+@Beta
+public class XDDFNormalAutoFit implements XDDFAutoFit {
+    private CTTextNormalAutofit autofit;
+
+    public XDDFNormalAutoFit() {
+        this(CTTextNormalAutofit.Factory.newInstance());
+    }
+
+    @Internal
+    protected XDDFNormalAutoFit(CTTextNormalAutofit autofit) {
+        this.autofit = autofit;
+    }
+
+    @Internal
+    protected CTTextNormalAutofit getXmlObject() {
+        return autofit;
+    }
+
+    @Override
+    public int getFontScale() {
+        if (autofit.isSetFontScale()) {
+            return autofit.getFontScale();
+        } else {
+            return 100_000;
+        }
+    }
+
+    public void setFontScale(Integer value) {
+        if (value == null) {
+            autofit.unsetFontScale();
+        } else {
+            autofit.setFontScale(value);
+        }
+    }
+
+    @Override
+    public int getLineSpaceReduction() {
+        if (autofit.isSetLnSpcReduction()) {
+            return autofit.getLnSpcReduction();
+        } else {
+            return 0;
+        }
+    }
+
+    public void setLineSpaceReduction(Integer value) {
+        if (value == null) {
+            autofit.unsetLnSpcReduction();
+        } else {
+            autofit.setLnSpcReduction(value);
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFParagraphBulletProperties.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFParagraphBulletProperties.java
new file mode 100644 (file)
index 0000000..36849c4
--- /dev/null
@@ -0,0 +1,159 @@
+/* ====================================================================
+   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 org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+
+@Beta
+public class XDDFParagraphBulletProperties {
+    private CTTextParagraphProperties props;
+
+    @Internal
+    protected XDDFParagraphBulletProperties(CTTextParagraphProperties properties) {
+        this.props = properties;
+    }
+
+    public XDDFBulletStyle getBulletStyle() {
+      if (props.isSetBuAutoNum()) {
+          return new XDDFBulletStyleAutoNumbered(props.getBuAutoNum());
+      } else if (props.isSetBuBlip()) {
+          return new XDDFBulletStylePicture(props.getBuBlip());
+      } else if (props.isSetBuChar()) {
+          return new XDDFBulletStyleCharacter(props.getBuChar());
+      } else if (props.isSetBuNone()) {
+          return new XDDFBulletStyleNone(props.getBuNone());
+      } else {
+          return null;
+      }
+    }
+
+    public void setBulletStyle(XDDFBulletStyle style) {
+        props.unsetBuAutoNum();
+        props.unsetBuBlip();
+        props.unsetBuChar();
+        props.unsetBuNone();
+        if (style != null) {
+            if (style instanceof XDDFBulletStyleAutoNumbered) {
+                props.setBuAutoNum(((XDDFBulletStyleAutoNumbered) style).getXmlObject());
+            } else if (style instanceof XDDFBulletStyleCharacter) {
+                props.setBuChar(((XDDFBulletStyleCharacter) style).getXmlObject());
+            } else if (style instanceof XDDFBulletStyleNone) {
+                props.setBuNone(((XDDFBulletStyleNone) style).getXmlObject());
+            } else if (style instanceof XDDFBulletStylePicture) {
+                props.setBuBlip(((XDDFBulletStylePicture) style).getXmlObject());
+            }
+        }
+    }
+
+    public XDDFColor getBulletColor() {
+        if (props.isSetBuClr()) {
+            return XDDFColor.forColorContainer(props.getBuClr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setBulletColor(XDDFColor color) {
+        props.unsetBuClrTx();
+        if (color == null) {
+            props.unsetBuClr();
+        } else {
+            props.setBuClr(color.getColorContainer());
+        }
+    }
+
+    public void setBulletColorFollowText() {
+        props.unsetBuClr();
+        if (props.isSetBuClrTx()) {
+            // nothing to do: already set
+        } else {
+            props.addNewBuClrTx();
+        }
+    }
+
+    public XDDFFont getBulletFont() {
+        if (props.isSetBuFont()) {
+            return new XDDFFont(FontGroup.SYMBOL, props.getBuFont());
+        } else {
+            return null;
+        }
+    }
+
+    public void setBulletFont(XDDFFont font) {
+        props.unsetBuFontTx();
+        if (font == null) {
+            props.unsetBuFont();
+        } else {
+            props.setBuFont(font.getXmlObject());
+        }
+    }
+
+    public void setBulletFontFollowText() {
+        props.unsetBuFont();
+        if (props.isSetBuFontTx()) {
+            // nothing to do: already set
+        } else {
+            props.addNewBuFontTx();
+        }
+    }
+
+    public XDDFBulletSize getBulletSize() {
+      if (props.isSetBuSzPct()) {
+          return new XDDFBulletSizePercent(props.getBuSzPct(), null);
+      } else if (props.isSetBuSzPts()) {
+          return new XDDFBulletSizePoints(props.getBuSzPts());
+      } else if (props.isSetBuSzTx()) {
+          return new XDDFBulletSizeFollowText(props.getBuSzTx());
+      } else {
+          return null;
+      }
+    }
+
+    public void setBulletSize(XDDFBulletSize size) {
+        props.unsetBuSzPct();
+        props.unsetBuSzPts();
+        props.unsetBuSzTx();
+        if (size != null) {
+            if (size instanceof XDDFBulletSizeFollowText) {
+                props.setBuSzTx(((XDDFBulletSizeFollowText) size).getXmlObject());
+            } else if (size instanceof XDDFBulletSizePercent) {
+                props.setBuSzPct(((XDDFBulletSizePercent) size).getXmlObject());
+            } else if (size instanceof XDDFBulletSizePoints) {
+                props.setBuSzPts(((XDDFBulletSizePoints) size).getXmlObject());
+            }
+        }
+    }
+
+    public void clearAll() {
+        props.unsetBuAutoNum();
+        props.unsetBuBlip();
+        props.unsetBuChar();
+        props.unsetBuNone();
+        props.unsetBuClr();
+        props.unsetBuClrTx();
+        props.unsetBuFont();
+        props.unsetBuFontTx();
+        props.unsetBuSzPct();
+        props.unsetBuSzPts();
+        props.unsetBuSzTx();
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFParagraphProperties.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFParagraphProperties.java
new file mode 100644 (file)
index 0000000..7038b35
--- /dev/null
@@ -0,0 +1,258 @@
+/* ====================================================================
+   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 java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.XDDFExtensionList;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+
+@Beta
+public class XDDFParagraphProperties {
+    private CTTextParagraphProperties props;
+    private XDDFParagraphBulletProperties bullet;
+
+    @Internal
+    protected XDDFParagraphProperties(CTTextParagraphProperties properties) {
+        this.props = properties;
+        this.bullet = new XDDFParagraphBulletProperties(properties);
+    }
+
+    @Internal
+    protected CTTextParagraphProperties getXmlObject() {
+        return props;
+    }
+
+    public XDDFParagraphBulletProperties getBulletProperties() {
+        return bullet;
+    }
+
+    public int getLevel() {
+        if (props.isSetLvl()) {
+            return 1 + props.getLvl();
+        } else {
+            return 0;
+        }
+    }
+
+    public void setLevel(Integer level) {
+        if (level == null) {
+            props.unsetLvl();
+        } else if (level < 1 || 9 < level) {
+            throw new IllegalArgumentException("Minimum inclusive: 1. Maximum inclusive: 9.");
+        } else {
+            props.setLvl(level - 1);
+        }
+    }
+
+    public XDDFRunProperties getDefaultRunProperties() {
+        if (props.isSetDefRPr()) {
+            return new XDDFRunProperties(props.getDefRPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setDefaultRunProperties(XDDFRunProperties properties) {
+        if (properties == null) {
+            props.unsetDefRPr();
+        } else {
+            props.setDefRPr(properties.getXmlObject());
+        }
+    }
+
+    public void setEastAsianLineBreak(Boolean value) {
+        if (value == null) {
+            props.unsetEaLnBrk();
+        } else {
+            props.setEaLnBrk(value);
+        }
+    }
+
+    public void setLatinLineBreak(Boolean value) {
+        if (value == null) {
+            props.unsetLatinLnBrk();
+        } else {
+            props.setLatinLnBrk(value);
+        }
+    }
+
+    public void setHangingPunctuation(Boolean value) {
+        if (value == null) {
+            props.unsetHangingPunct();
+        } else {
+            props.setHangingPunct(value);
+        }
+    }
+
+    public void setRightToLeft(Boolean value) {
+        if (value == null) {
+            props.unsetRtl();
+        } else {
+            props.setRtl(value);
+        }
+    }
+
+    public void setFontAlignment(FontAlignment align) {
+        if (align == null) {
+            props.unsetFontAlgn();
+        } else {
+            props.setFontAlgn(align.underlying);
+        }
+    }
+
+    public void setTextAlignment(TextAlignment align) {
+        if (align == null) {
+            props.unsetAlgn();
+        } else {
+            props.setAlgn(align.underlying);
+        }
+    }
+
+    public void setDefaultTabSize(Double points) {
+        if (points == null) {
+            props.unsetDefTabSz();
+        } else {
+            props.setDefTabSz(Units.toEMU(points));
+        }
+    }
+
+    public void setIndentation(Double points) {
+        if (points == null) {
+            props.unsetIndent();
+        } else if (points < -4032 || 4032 < points) {
+            throw new IllegalArgumentException("Minimum inclusive = -4032. Maximum inclusive = 4032.");
+        } else {
+            props.setIndent(Units.toEMU(points));
+        }
+    }
+
+    public void setMarginLeft(Double points) {
+        if (points == null) {
+            props.unsetMarL();
+        } else if (points < 0 || 4032 < points) {
+            throw new IllegalArgumentException("Minimum inclusive = 0. Maximum inclusive = 4032.");
+        } else {
+            props.setMarL(Units.toEMU(points));
+        }
+    }
+
+    public void setMarginRight(Double points) {
+        if (points == null) {
+            props.unsetMarR();
+        } else if (points < 0 || 4032 < points) {
+            throw new IllegalArgumentException("Minimum inclusive = 0. Maximum inclusive = 4032.");
+        } else {
+            props.setMarR(Units.toEMU(points));
+        }
+    }
+
+    public void setLineSpacing(XDDFSpacing spacing) {
+        if (spacing == null) {
+            props.unsetLnSpc();
+        } else {
+            props.setLnSpc(spacing.getXmlObject());
+        }
+    }
+
+    public void setSpaceAfter(XDDFSpacing spacing) {
+        if (spacing == null) {
+            props.unsetSpcAft();
+        } else {
+            props.setSpcAft(spacing.getXmlObject());
+        }
+    }
+
+    public void setSpaceBefore(XDDFSpacing spacing) {
+        if (spacing == null) {
+            props.unsetSpcBef();
+        } else {
+            props.setSpcBef(spacing.getXmlObject());
+        }
+    }
+
+    public XDDFTabStop addTabStop() {
+        if (!props.isSetTabLst()) {
+            props.addNewTabLst();
+        }
+        return new XDDFTabStop(props.getTabLst().addNewTab());
+    }
+
+    public XDDFTabStop insertTabStop(int index) {
+        if (!props.isSetTabLst()) {
+            props.addNewTabLst();
+        }
+        return new XDDFTabStop(props.getTabLst().insertNewTab(index));
+    }
+
+    public void removeTabStop(int index) {
+        if (props.isSetTabLst()) {
+            props.getTabLst().removeTab(index);
+        }
+    }
+
+    public XDDFTabStop getTabStop(int index) {
+        if (props.isSetTabLst()) {
+            return new XDDFTabStop(props.getTabLst().getTabArray(index));
+        } else {
+            return null;
+        }
+    }
+
+    public List<XDDFTabStop> getTabStops() {
+        if (props.isSetTabLst()) {
+            return Collections.unmodifiableList(props
+                .getTabLst()
+                .getTabList()
+                .stream()
+                .map(gs -> new XDDFTabStop(gs))
+                .collect(Collectors.toList()));
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    public int countTabStops() {
+        if (props.isSetTabLst()) {
+            return props.getTabLst().sizeOfTabArray();
+        } else {
+            return 0;
+        }
+    }
+
+    public XDDFExtensionList getExtensionList() {
+        if (props.isSetExtLst()) {
+            return new XDDFExtensionList(props.getExtLst());
+        } else {
+            return null;
+        }
+    }
+
+    public void setExtensionList(XDDFExtensionList list) {
+        if (list == null) {
+            props.unsetExtLst();
+        } else {
+            props.setExtLst(list.getXmlObject());
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFRunProperties.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFRunProperties.java
new file mode 100644 (file)
index 0000000..6b1c952
--- /dev/null
@@ -0,0 +1,335 @@
+/* ====================================================================
+   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 java.util.Locale;
+
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFEffectContainer;
+import org.apache.poi.xddf.usermodel.XDDFEffectList;
+import org.apache.poi.xddf.usermodel.XDDFExtensionList;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFGradientFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFGroupFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFNoFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFPatternFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFPictureFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
+
+@Beta
+public class XDDFRunProperties {
+    private CTTextCharacterProperties props;
+
+    public XDDFRunProperties() {
+        this(CTTextCharacterProperties.Factory.newInstance());
+    }
+
+    @Internal
+    protected XDDFRunProperties(CTTextCharacterProperties properties) {
+        this.props = properties;
+    }
+
+    @Internal
+    protected CTTextCharacterProperties getXmlObject() {
+        return props;
+    }
+
+    public void setBaseline(Integer value) {
+        if (value == null) {
+            props.unsetBaseline();
+        } else {
+            props.setBaseline(value);
+        }
+    }
+
+    public void setDirty(Boolean dirty) {
+        if (dirty == null) {
+            props.unsetDirty();
+        } else {
+            props.setDirty(dirty);
+        }
+    }
+
+    public void setSpellError(Boolean error) {
+        if (error == null) {
+            props.unsetErr();
+        } else {
+            props.setErr(error);
+        }
+    }
+
+    public void setNoProof(Boolean noproof) {
+        if (noproof == null) {
+            props.unsetNoProof();
+        } else {
+            props.setNoProof(noproof);
+        }
+    }
+
+    public void setNormalizeHeights(Boolean normalize) {
+        if (normalize == null) {
+            props.unsetNormalizeH();
+        } else {
+            props.setNormalizeH(normalize);
+        }
+    }
+
+    public void setKumimoji(Boolean kumimoji) {
+        if (kumimoji == null) {
+            props.unsetKumimoji();
+        } else {
+            props.setKumimoji(kumimoji);
+        }
+    }
+
+    public void setBold(Boolean bold) {
+        if (bold == null) {
+            props.unsetB();
+        } else {
+            props.setB(bold);
+        }
+    }
+
+    public void setItalic(Boolean italic) {
+        if (italic == null) {
+            props.unsetI();
+        } else {
+            props.setI(italic);
+        }
+    }
+
+    public void setFontSize(Double size) {
+        if (size == null) {
+            props.unsetSz();
+        } else if (size < 1 || 400 < size) {
+            throw new IllegalArgumentException("Minimum inclusive = 1. Maximum inclusive = 400.");
+        } else {
+            props.setSz((int)(100 * size));
+        }
+    }
+
+    public void setFillProperties(XDDFFillProperties properties) {
+        props.unsetBlipFill();
+        props.unsetGradFill();
+        props.unsetGrpFill();
+        props.unsetNoFill();
+        props.unsetPattFill();
+        props.unsetSolidFill();
+        if (properties == null) {
+            return;
+        }
+        if (properties instanceof XDDFGradientFillProperties) {
+            props.setGradFill(((XDDFGradientFillProperties) properties).getXmlObject());
+        } else if (properties instanceof XDDFGroupFillProperties) {
+            props.setGrpFill(((XDDFGroupFillProperties) properties).getXmlObject());
+        } else if (properties instanceof XDDFNoFillProperties) {
+            props.setNoFill(((XDDFNoFillProperties) properties).getXmlObject());
+        } else if (properties instanceof XDDFPatternFillProperties) {
+            props.setPattFill(((XDDFPatternFillProperties) properties).getXmlObject());
+        } else if (properties instanceof XDDFPictureFillProperties) {
+            props.setBlipFill(((XDDFPictureFillProperties) properties).getXmlObject());
+        } else if (properties instanceof XDDFSolidFillProperties) {
+            props.setSolidFill(((XDDFSolidFillProperties) properties).getXmlObject());
+        }
+    }
+
+    public void setCharacterKerning(Double kerning) {
+        if (kerning == null) {
+            props.unsetKern();
+        } else if (kerning < 0 || 4000 < kerning) {
+            throw new IllegalArgumentException("Minimum inclusive = 0. Maximum inclusive = 4000.");
+        } else {
+            props.setKern((int)(100*kerning));
+        }
+    }
+
+    public void setCharacterSpacing(Double spacing) {
+        if (spacing == null) {
+            props.unsetSpc();
+        } else if (spacing < -4000 || 4000 < spacing) {
+            throw new IllegalArgumentException("Minimum inclusive = -4000. Maximum inclusive = 4000.");
+        } else {
+            props.setSpc((int)(100*spacing));
+        }
+    }
+
+    public void setFonts(XDDFFont[] fonts) {
+        for (XDDFFont font: fonts) {
+            CTTextFont xml = font.getXmlObject();
+            switch (font.getGroup()) {
+            case COMPLEX_SCRIPT:
+                if (xml == null) {
+                    props.unsetCs();
+                } else {
+                    props.setCs(xml);
+                }
+            case EAST_ASIAN:
+                if (xml == null) {
+                    props.unsetEa();
+                } else {
+                    props.setEa(xml);
+                }
+            case LATIN:
+                if (xml == null) {
+                    props.unsetLatin();
+                } else {
+                    props.setLatin(xml);
+                }
+            case SYMBOL:
+                if (xml == null) {
+                    props.unsetSym();
+                } else {
+                    props.setSym(xml);
+                }
+            }
+        }
+    }
+
+    public void setUnderline(UnderlineType underline) {
+        if (underline == null) {
+            props.unsetU();
+        } else {
+            props.setU(underline.underlying);
+        }
+    }
+
+    public void setStrikeThrough(StrikeType strike) {
+        if (strike == null) {
+            props.unsetStrike();
+        } else {
+            props.setStrike(strike.underlying);
+        }
+    }
+
+    public void setCapitals(CapsType caps) {
+        if (caps == null) {
+            props.unsetCap();
+        } else {
+            props.setCap(caps.underlying);
+        }
+    }
+
+    public void setHyperlink(XDDFHyperlink link) {
+        if (link == null) {
+            props.unsetHlinkClick();
+        } else {
+            props.setHlinkClick(link.getXmlObject());
+        }
+    }
+
+    public void setMouseOver(XDDFHyperlink link) {
+        if (link == null) {
+            props.unsetHlinkMouseOver();
+        } else {
+            props.setHlinkMouseOver(link.getXmlObject());
+        }
+    }
+
+    public void setLanguage(Locale lang) {
+        if (lang == null) {
+            props.unsetLang();
+        } else {
+            props.setLang(lang.toLanguageTag());
+        }
+    }
+
+    public void setAlternativeLanguage(Locale lang) {
+        if (lang == null) {
+            props.unsetAltLang();
+        } else {
+            props.setAltLang(lang.toLanguageTag());
+        }
+    }
+
+    public void setHighlight(XDDFColor color) {
+        if (color == null) {
+            props.unsetHighlight();
+        } else {
+            props.setHighlight(color.getColorContainer());
+        }
+    }
+
+    public void setLineProperties(XDDFLineProperties properties) {
+        if (properties == null) {
+            props.unsetLn();
+        } else {
+            props.setLn(properties.getXmlObject());
+        }
+    }
+
+    public void setBookmark(String bookmark) {
+        if (bookmark == null) {
+            props.unsetBmk();
+        } else {
+            props.setBmk(bookmark);
+        }
+    }
+
+    public XDDFExtensionList getExtensionList() {
+        if (props.isSetExtLst()) {
+            return new XDDFExtensionList(props.getExtLst());
+        } else {
+            return null;
+        }
+    }
+
+    public void setExtensionList(XDDFExtensionList list) {
+        if (list == null) {
+            props.unsetExtLst();
+        } else {
+            props.setExtLst(list.getXmlObject());
+        }
+    }
+
+    public XDDFEffectContainer getEffectContainer() {
+        if (props.isSetEffectDag()) {
+            return new XDDFEffectContainer(props.getEffectDag());
+        } else {
+            return null;
+        }
+    }
+
+    public void setEffectContainer(XDDFEffectContainer container) {
+        if (container == null) {
+            props.unsetEffectDag();
+        } else {
+            props.setEffectDag(container.getXmlObject());
+        }
+    }
+
+    public XDDFEffectList getEffectList() {
+        if (props.isSetEffectLst()) {
+            return new XDDFEffectList(props.getEffectLst());
+        } else {
+            return null;
+        }
+    }
+
+    public void setEffectList(XDDFEffectList list) {
+        if (list == null) {
+            props.unsetEffectLst();
+        } else {
+            props.setEffectLst(list.getXmlObject());
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFShapeAutoFit.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFShapeAutoFit.java
new file mode 100644 (file)
index 0000000..0721313
--- /dev/null
@@ -0,0 +1,51 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextShapeAutofit;
+
+@Beta
+public class XDDFShapeAutoFit implements XDDFAutoFit {
+    private CTTextShapeAutofit autofit;
+
+    public XDDFShapeAutoFit() {
+        this(CTTextShapeAutofit.Factory.newInstance());
+    }
+
+    @Internal
+    protected XDDFShapeAutoFit(CTTextShapeAutofit autofit) {
+        this.autofit = autofit;
+    }
+
+    @Internal
+    protected CTTextShapeAutofit getXmlObject() {
+        return autofit;
+    }
+
+    @Override
+    public int getFontScale() {
+        return 100_000;
+    }
+
+    @Override
+    public int getLineSpaceReduction() {
+        return 0;
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacing.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacing.java
new file mode 100644 (file)
index 0000000..5697038
--- /dev/null
@@ -0,0 +1,44 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
+
+@Beta
+public abstract class XDDFSpacing {
+    public static enum Kind {
+        PERCENT,
+        POINTS;
+    }
+
+    protected CTTextSpacing spacing;
+
+    @Internal
+    protected XDDFSpacing(CTTextSpacing spacing) {
+        this.spacing = spacing;
+    }
+
+    public abstract Kind getType();
+
+    @Internal
+    protected CTTextSpacing getXmlObject() {
+        return spacing;
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacingPercent.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacingPercent.java
new file mode 100644 (file)
index 0000000..82594f0
--- /dev/null
@@ -0,0 +1,56 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacingPercent;
+
+@Beta
+public class XDDFSpacingPercent extends XDDFSpacing {
+    private CTTextSpacingPercent percent;
+    private Double scale;
+
+    public XDDFSpacingPercent(double value) {
+        this(CTTextSpacing.Factory.newInstance(), CTTextSpacingPercent.Factory.newInstance(), null);
+        spacing.unsetSpcPts();
+        spacing.setSpcPct(percent);
+        setPercent(value);
+    }
+
+    @Internal
+    protected XDDFSpacingPercent(CTTextSpacing parent, CTTextSpacingPercent percent, Double scale) {
+        super(parent);
+        this.percent = percent;
+        this.scale = (scale == null) ? 0.001 : scale * 0.001;
+    }
+
+    @Override
+    public Kind getType() {
+        return Kind.PERCENT;
+    }
+
+    public double getPercent() {
+        return percent.getVal() * scale;
+    }
+
+    public void setPercent(double value) {
+        percent.setVal((int)(1000 * value));
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacingPoints.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFSpacingPoints.java
new file mode 100644 (file)
index 0000000..6b4fcc7
--- /dev/null
@@ -0,0 +1,54 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacingPoint;
+
+@Beta
+public class XDDFSpacingPoints extends XDDFSpacing {
+    private CTTextSpacingPoint points;
+
+    public XDDFSpacingPoints(double value) {
+        this(CTTextSpacing.Factory.newInstance(), CTTextSpacingPoint.Factory.newInstance());
+        spacing.unsetSpcPct();
+        spacing.setSpcPts(points);
+        setPoints(value);
+    }
+
+    @Internal
+    protected XDDFSpacingPoints(CTTextSpacing parent, CTTextSpacingPoint points) {
+        super(parent);
+        this.points = points;
+    }
+
+    @Override
+    public Kind getType() {
+        return Kind.POINTS;
+    }
+
+    public double getPoints() {
+        return points.getVal() * 0.01;
+    }
+
+    public void setPoints(double value) {
+        points.setVal((int)(100 * value));
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTabStop.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTabStop.java
new file mode 100644 (file)
index 0000000..8b8701e
--- /dev/null
@@ -0,0 +1,70 @@
+/* ====================================================================
+   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 org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Units;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;
+
+@Beta
+public class XDDFTabStop {
+    private CTTextTabStop stop;
+
+    @Internal
+    protected XDDFTabStop(CTTextTabStop stop) {
+        this.stop = stop;
+    }
+
+    @Internal
+    protected CTTextTabStop getXmlObject() {
+        return stop;
+    }
+
+    public TabAlignment getAlignment() {
+        if (stop.isSetAlgn()) {
+            return TabAlignment.valueOf(stop.getAlgn());
+        } else {
+            return null;
+        }
+    }
+
+    public void setAlignment(TabAlignment align) {
+        if (align == null) {
+            stop.unsetAlgn();
+        } else {
+            stop.setAlgn(align.underlying);
+        }
+    }
+
+    public Double getPosition() {
+        if (stop.isSetPos()) {
+            return Units.toPoints(stop.getPos());
+        } else {
+            return null;
+        }
+    }
+
+    public void setPosition(Double position) {
+        if (position == null) {
+            stop.unsetPos();
+        } else {
+            stop.setPos(Units.toEMU(position));
+        }
+    }
+}
index fdd0e500c073ad20483aad95b926f9fb4a9935de..f2b8103dae5fb47e5836472a781ea55b2a48b8ba 100644 (file)
 
 package org.apache.poi.xddf.usermodel.text;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
 import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
 
 @Beta
 public class XDDFTextBody {
-    private CTTextBody body;
+    private CTTextBody _body;
+    private TextContainer _parent;
 
-    public XDDFTextBody() {
-        this(CTTextBody.Factory.newInstance());
+    public XDDFTextBody(TextContainer parent) {
+        this(parent, CTTextBody.Factory.newInstance());
+        this._body.addNewBodyPr();
     }
 
     @Internal
-    public XDDFTextBody(CTTextBody body) {
-        this.body = body;
+    public XDDFTextBody(TextContainer parent, CTTextBody body) {
+        this._parent = parent;
+        this._body = body;
     }
 
     @Internal
     public CTTextBody getXmlObject() {
-        return body;
+        return _body;
+    }
+
+    public TextContainer getParentShape() {
+        return _parent;
+    }
+
+    public XDDFTextParagraph addNewParagraph() {
+        return new XDDFTextParagraph(_body.addNewP(), this);
+    }
+
+    public XDDFTextParagraph insertNewParagraph(int index) {
+        return new XDDFTextParagraph(_body.insertNewP(index), this);
+    }
+
+    public void removeParagraph(int index) {
+        _body.removeP(index);
+    }
+
+    public XDDFTextParagraph getParagraph(int index) {
+        return new XDDFTextParagraph(_body.getPArray(index), this);
+    }
+
+    public List<XDDFTextParagraph> getParagraphs() {
+        return Collections.unmodifiableList(_body
+            .getPList()
+            .stream()
+            .map(ds -> new XDDFTextParagraph(ds, this))
+            .collect(Collectors.toList()));
+    }
+
+    public XDDFBodyProperties getBodyProperties() {
+        return new XDDFBodyProperties(_body.getBodyPr());
+    }
+
+    public void setBodyProperties(XDDFBodyProperties properties) {
+        if (properties == null) {
+            _body.addNewBodyPr();
+        } else {
+            _body.setBodyPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getDefaultProperties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetDefPPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getDefPPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setDefaultProperties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetDefPPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setDefPPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel1Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl1PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl1PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel1Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl1PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl1PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel2Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl2PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl2PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel2Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl2PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl2PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel3Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl3PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl3PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel3Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl3PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl3PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel4Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl4PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl4PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel4Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl4PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl4PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel5Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl5PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl5PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel5Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl5PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl5PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel6Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl6PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl6PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel6Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl6PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl6PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel7Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl7PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl7PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel7Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl7PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl7PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel8Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl8PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl8PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel8Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl8PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl8PPr(properties.getXmlObject());
+        }
+    }
+
+    public XDDFParagraphProperties getLevel9Properties() {
+        if (_body.isSetLstStyle() && _body.getLstStyle().isSetLvl9PPr()) {
+            return new XDDFParagraphProperties(_body.getLstStyle().getLvl9PPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setLevel9Properties(XDDFParagraphProperties properties) {
+        if (properties == null) {
+            if (_body.isSetLstStyle()) {
+                _body.getLstStyle().unsetLvl9PPr();
+            }
+        } else {
+            CTTextListStyle style = _body.isSetLstStyle() ? _body.getLstStyle() : _body.addNewLstStyle();
+            style.setLvl9PPr(properties.getXmlObject());
+        }
+    }
+
+    @Internal
+    protected <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
+        Function<CTTextParagraphProperties, R> getter, int level) {
+        if (_body.isSetLstStyle() && level >= 0) {
+            CTTextListStyle list = _body.getLstStyle();
+            CTTextParagraphProperties props = level == 0 ? list.getDefPPr() : retrieveProperties(list, level);
+            if (props != null && isSet.apply(props)) {
+                return Optional.of(getter.apply(props));
+            } else {
+                return findDefinedParagraphProperty(isSet, getter, level - 1);
+            }
+        } else {
+            return _parent.findDefinedParagraphProperty(isSet, getter);
+        }
+    }
+
+    @Internal
+    protected <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
+        Function<CTTextCharacterProperties, R> getter, int level) {
+        if (_body.isSetLstStyle() && level >= 0) {
+            CTTextListStyle list = _body.getLstStyle();
+            CTTextParagraphProperties props = level == 0 ? list.getDefPPr() : retrieveProperties(list, level);
+            if (props != null && props.isSetDefRPr() && isSet.apply(props.getDefRPr())) {
+                return Optional.of(getter.apply(props.getDefRPr()));
+            } else {
+                return findDefinedRunProperty(isSet, getter, level - 1);
+            }
+        } else {
+            return _parent.findDefinedRunProperty(isSet, getter);
+        }
+    }
+
+    private CTTextParagraphProperties retrieveProperties(CTTextListStyle list, int level) {
+        switch(level) {
+        case 1: if (list.isSetLvl1PPr()) {
+            return list.getLvl1PPr();
+        } else {
+            return null;
+        }
+        case 2: if (list.isSetLvl2PPr()) {
+            return list.getLvl2PPr();
+        } else {
+            return null;
+        }
+        case 3: if (list.isSetLvl3PPr()) {
+            return list.getLvl3PPr();
+        } else {
+            return null;
+        }
+        case 4: if (list.isSetLvl4PPr()) {
+            return list.getLvl4PPr();
+        } else {
+            return null;
+        }
+        case 5: if (list.isSetLvl5PPr()) {
+            return list.getLvl5PPr();
+        } else {
+            return null;
+        }
+        case 6: if (list.isSetLvl6PPr()) {
+            return list.getLvl6PPr();
+        } else {
+            return null;
+        }
+        case 7: if (list.isSetLvl7PPr()) {
+            return list.getLvl7PPr();
+        } else {
+            return null;
+        }
+        case 8: if (list.isSetLvl8PPr()) {
+            return list.getLvl8PPr();
+        } else {
+            return null;
+        }
+        case 9: if (list.isSetLvl9PPr()) {
+            return list.getLvl9PPr();
+        } else {
+            return null;
+        }
+        default: return null;
+        }
     }
 }
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextParagraph.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextParagraph.java
new file mode 100644 (file)
index 0000000..a87de6e
--- /dev/null
@@ -0,0 +1,723 @@
+/* ====================================================================
+   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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.LocaleUtil;
+import org.apache.poi.util.Units;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.xmlbeans.QNameSet;
+import org.apache.xmlbeans.XmlObject;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
+
+/**
+ * Represents a paragraph of text within the containing text body.
+ * The paragraph is the highest level text separation mechanism.
+ */
+@Beta
+public class XDDFTextParagraph {
+    private XDDFTextBody _parent;
+    private XDDFParagraphProperties _properties;
+    private final CTTextParagraph _p;
+    private final ArrayList<XDDFTextRun> _runs;
+
+    @Internal
+    protected XDDFTextParagraph(CTTextParagraph paragraph, XDDFTextBody parent) {
+        this._p = paragraph;
+        this._parent = parent;
+
+        final int count = paragraph.sizeOfBrArray()
+            + paragraph.sizeOfFldArray()
+            + paragraph.sizeOfRArray();
+        this._runs = new ArrayList<>(count);
+
+        for (XmlObject xo : _p.selectChildren(QNameSet.ALL)) {
+            if (xo instanceof CTTextLineBreak) {
+                _runs.add(new XDDFTextRun((CTTextLineBreak) xo, this));
+            } else if (xo instanceof CTTextField) {
+                _runs.add(new XDDFTextRun((CTTextField) xo, this));
+            } else if (xo instanceof CTRegularTextRun) {
+                _runs.add(new XDDFTextRun((CTRegularTextRun) xo, this));
+            }
+        }
+    }
+
+    public String getText() {
+        StringBuilder out = new StringBuilder();
+        for (XDDFTextRun r : _runs) {
+            out.append(r.getText());
+        }
+        return out.toString();
+    }
+
+    public XDDFTextBody getParentBody() {
+        return _parent;
+    }
+
+    public List<XDDFTextRun> getTextRuns(){
+        return _runs;
+    }
+
+    public Iterator<XDDFTextRun> iterator(){
+        return _runs.iterator();
+    }
+
+    /**
+     * Append a line break.
+     *
+     * @return text run representing this line break ('\n').
+     */
+    public XDDFTextRun appendLineBreak(){
+        CTTextLineBreak br = _p.addNewBr();
+        // by default, line break has the font properties of the last text run
+        for (int i = _runs.size() - 1; i <= 0; i--){
+            CTTextCharacterProperties prevProps = _runs.get(i).getProperties();
+            // let's find one that is not undefined
+            if (prevProps != null) {
+                br.setRPr((CTTextCharacterProperties) prevProps.copy());
+                break;
+            }
+        }
+        XDDFTextRun run = new XDDFTextRun(br, this);
+        _runs.add(run);
+        return run;
+    }
+
+    /**
+     * Append a new text field.
+     *
+     * @return the new text field.
+     */
+    public XDDFTextRun appendField(String id, String type, String text){
+        CTTextField f = _p.addNewFld();
+        f.setId(id);
+        f.setType(type);
+        f.setT(text);
+        CTTextCharacterProperties rPr = f.addNewRPr();
+        rPr.setLang(LocaleUtil.getUserLocale().toLanguageTag());
+        XDDFTextRun run = new XDDFTextRun(f, this);
+        _runs.add(run);
+        return run;
+    }
+
+    /**
+     * Append a new run of text.
+     *
+     * @return the new run of text.
+     */
+    public XDDFTextRun appendRegularRun(String text){
+        CTRegularTextRun r = _p.addNewR();
+        r.setT(text);
+        CTTextCharacterProperties rPr = r.addNewRPr();
+        rPr.setLang(LocaleUtil.getUserLocale().toLanguageTag());
+        XDDFTextRun run = new XDDFTextRun(r, this);
+        _runs.add(run);
+        return run;
+    }
+
+    /**
+     * Returns the alignment that is applied to the paragraph.
+     *
+     * If this attribute is omitted, then a value of left is implied.
+     * @return alignment that is applied to the paragraph
+     */
+    public TextAlignment getTextAlignment() {
+        return findDefinedParagraphProperty(props -> props.isSetAlgn(), props -> props.getAlgn())
+            .map(align -> TextAlignment.valueOf(align))
+            .orElse(null);
+    }
+
+    /**
+     * Specifies the alignment that is to be applied to the paragraph.
+     * Possible values for this include left, right, centered, justified and distributed,
+     *
+     * @param align text alignment
+     */
+    public void setTextAlignment(TextAlignment align) {
+        if (align != null || _p.isSetPPr()) {
+            getOrCreateProperties().setTextAlignment(align);
+        }
+    }
+
+    /**
+     * Returns where vertically on a line of text the actual words are positioned. This deals
+     * with vertical placement of the characters with respect to the baselines.
+     *
+     * If this attribute is omitted, then a value of baseline is implied.
+     * @return alignment that is applied to the paragraph
+     */
+    public FontAlignment getFontAlignment() {
+        return findDefinedParagraphProperty(props -> props.isSetFontAlgn(), props -> props.getFontAlgn())
+            .map(align -> FontAlignment.valueOf(align))
+            .orElse(null);
+    }
+
+    /**
+     * Determines where vertically on a line of text the actual words are positioned. This deals
+     * with vertical placement of the characters with respect to the baselines. For instance
+     * having text anchored to the top baseline, anchored to the bottom baseline, centered in
+     * between, etc.
+     *
+     * @param align text font alignment
+     */
+    public void setFontAlignment(FontAlignment align) {
+        if (align != null || _p.isSetPPr()) {
+            getOrCreateProperties().setFontAlignment(align);
+        }
+    }
+
+    /**
+     *
+     * @return the indentation, in points, applied to the first line of text in the paragraph.
+     */
+    public Double getIndentation() {
+        return findDefinedParagraphProperty(props -> props.isSetIndent(), props -> props.getIndent())
+            .map(emu -> Units.toPoints(emu))
+            .orElse(null);
+    }
+
+    /**
+     * Specifies the indentation size that will be applied to the first line of text in the paragraph.
+     *
+     * @param points the indentation in points.
+     * The value <code>null</code> unsets the indentation for this paragraph.
+     * <dl>
+     * <dt>Minimum inclusive =</dt><dd>-4032</dd>
+     * <dt>Maximum inclusive =</dt><dd>4032</dd>
+     * </dt>
+     */
+    public void setIndentation(Double points) {
+        if (points != null || _p.isSetPPr()) {
+            getOrCreateProperties().setIndentation(points);;
+        }
+    }
+
+    /**
+     *
+     * @return the left margin, in points, of the paragraph.
+     */
+    public Double getMarginLeft() {
+        return findDefinedParagraphProperty(props -> props.isSetMarL(), props -> props.getMarL())
+            .map(emu -> Units.toPoints(emu))
+            .orElse(null);
+    }
+
+    /**
+     * Specifies the left margin of the paragraph. This is specified in addition to the text body
+     * inset and applies only to this text paragraph. That is the text body inset and the LeftMargin
+     * attributes are additive with respect to the text position.
+     *
+     * @param points the margin in points.
+     * The value <code>null</code> unsets the left margin for this paragraph.
+     * <dl>
+     * <dt>Minimum inclusive =</dt><dd>0</dd>
+     * <dt>Maximum inclusive =</dt><dd>4032</dd>
+     * </dt>
+     */
+    public void setMarginLeft(Double points) {
+        if (points != null || _p.isSetPPr()) {
+            getOrCreateProperties().setMarginLeft(points);
+        }
+    }
+
+    /**
+     *
+     * @return the right margin, in points, of the paragraph.
+     */
+    public Double getMarginRight() {
+        return findDefinedParagraphProperty(props -> props.isSetMarR(), props -> props.getMarR())
+            .map(emu -> Units.toPoints(emu))
+            .orElse(null);
+    }
+
+    /**
+     * Specifies the right margin of the paragraph. This is specified in addition to the text body
+     * inset and applies only to this text paragraph. That is the text body inset and the RightMargin
+     * attributes are additive with respect to the text position.
+     *
+     * @param points the margin in points.
+     * The value <code>null</code> unsets the right margin for this paragraph.
+     * <dl>
+     * <dt>Minimum inclusive =</dt><dd>0</dd>
+     * <dt>Maximum inclusive =</dt><dd>4032</dd>
+     * </dt>
+     */
+    public void setMarginRight(Double points) {
+        if (points != null || _p.isSetPPr()) {
+            getOrCreateProperties().setMarginRight(points);
+        }
+    }
+
+    /**
+     *
+     * @return the default size for a tab character within this paragraph in points.
+     */
+    public Double getDefaultTabSize() {
+        return findDefinedParagraphProperty(props -> props.isSetDefTabSz(), props -> props.getDefTabSz())
+            .map(emu -> Units.toPoints(emu))
+            .orElse(null);
+    }
+
+    /**
+     * Specifies the default size for a tab character within this paragraph.
+     *
+     * @param points the default tab size in points.
+     * The value <code>null</code> unsets the default tab size for this paragraph.
+     */
+    public void setDefaultTabSize(Double points) {
+        if (points != null || _p.isSetPPr()) {
+            getOrCreateProperties().setDefaultTabSize(points);
+        }
+    }
+
+    /**
+     * Returns the vertical line spacing that is to be used within a paragraph.
+     * This may be specified in two different ways, percentage spacing or font points spacing:
+     * <p>
+     * If line spacing is a percentage of normal line height, result is instance of XDDFSpacingPercent.
+     * If line spacing is expressed in points, result is instance of XDDFSpacingPoints.
+     * </p>
+     *
+     * @return the vertical line spacing.
+     */
+    public XDDFSpacing getLineSpacing() {
+        return findDefinedParagraphProperty(props -> props.isSetLnSpc(), props -> props.getLnSpc())
+            .map(spacing -> extractSpacing(spacing))
+            .orElse(null);
+
+    }
+
+    /**
+     * This element specifies the vertical line spacing that is to be used within a paragraph.
+     * This may be specified in two different ways, percentage spacing or font points spacing:
+     * <p>
+     * If spacing is instance of XDDFSpacingPercent, then line spacing is a percentage of normal line height.
+     * If spacing is instance of XDDFSpacingPoints, then line spacing is expressed in points.
+     * </p>
+     * Examples:
+     * <pre><code>
+     *      // spacing will be 120% of the size of the largest text on each line
+     *      paragraph.setLineSpacing(new XDDFSpacingPercent(120));
+     *
+     *      // spacing will be 200% of the size of the largest text on each line
+     *      paragraph.setLineSpacing(new XDDFSpacingPercent(200));
+     *
+     *      // spacing will be 48 points
+     *      paragraph.setLineSpacing(new XDDFSpacingPoints(48.0));
+     * </code></pre>
+     *
+     * @param linespacing the vertical line spacing
+     */
+    public void setLineSpacing(XDDFSpacing linespacing) {
+        if (linespacing != null || _p.isSetPPr()) {
+            getOrCreateProperties().setLineSpacing(linespacing);
+        }
+    }
+
+    /**
+     * The amount of vertical white space before the paragraph.
+     * This may be specified in two different ways, percentage spacing or font points spacing:
+     * <p>
+     * If spacing is a percentage of normal line height, result is instance of XDDFSpacingPercent.
+     * If spacing is expressed in points, result is instance of XDDFSpacingPoints.
+     * </p>
+     *
+     * @return the vertical white space before the paragraph.
+     */
+    public XDDFSpacing getSpaceBefore() {
+        return findDefinedParagraphProperty(props -> props.isSetSpcBef(), props -> props.getSpcBef())
+            .map(spacing -> extractSpacing(spacing))
+            .orElse(null);
+    }
+
+    /**
+     * Set the amount of vertical white space that will be present before the paragraph.
+     * This may be specified in two different ways, percentage spacing or font points spacing:
+     * <p>
+     * If spacing is instance of XDDFSpacingPercent, then spacing is a percentage of normal line height.
+     * If spacing is instance of XDDFSpacingPoints, then spacing is expressed in points.
+     * </p>
+     * Examples:
+     * <pre><code>
+     *      // The paragraph will be formatted to have a spacing before the paragraph text.
+     *      // The spacing will be 200% of the size of the largest text on each line
+     *      paragraph.setSpaceBefore(new XDDFSpacingPercent(200));
+     *
+     *      // The spacing will be a size of 48 points
+     *      paragraph.setSpaceBefore(new XDDFSpacingPoints(48.0));
+     * </code></pre>
+     *
+     * @param spaceBefore the vertical white space before the paragraph.
+     */
+    public void setSpaceBefore(XDDFSpacing spaceBefore) {
+        if (spaceBefore != null || _p.isSetPPr()) {
+            getOrCreateProperties().setSpaceBefore(spaceBefore);
+        }
+    }
+
+    /**
+     * The amount of vertical white space after the paragraph.
+     * This may be specified in two different ways, percentage spacing or font points spacing:
+     * <p>
+     * If spacing is a percentage of normal line height, result is instance of XDDFSpacingPercent.
+     * If spacing is expressed in points, result is instance of XDDFSpacingPoints.
+     * </p>
+     *
+     * @return the vertical white space after the paragraph.
+     */
+    public XDDFSpacing getSpaceAfter() {
+        return findDefinedParagraphProperty(props -> props.isSetSpcAft(), props -> props.getSpcAft())
+            .map(spacing -> extractSpacing(spacing))
+            .orElse(null);
+    }
+
+    /**
+     * Set the amount of vertical white space that will be present after the paragraph.
+     * This may be specified in two different ways, percentage spacing or font points spacing:
+     * <p>
+     * If spacing is instance of XDDFSpacingPercent, then spacing is a percentage of normal line height.
+     * If spacing is instance of XDDFSpacingPoints, then spacing is expressed in points.
+     * </p>
+     * Examples:
+     * <pre><code>
+     *      // The paragraph will be formatted to have a spacing after the paragraph text.
+     *      // The spacing will be 200% of the size of the largest text on each line
+     *      paragraph.setSpaceAfter(new XDDFSpacingPercent(200));
+     *
+     *      // The spacing will be a size of 48 points
+     *      paragraph.setSpaceAfter(new XDDFSpacingPoints(48.0));
+     * </code></pre>
+     *
+     * @param spaceAfter the vertical white space after the paragraph.
+     */
+    public void setSpaceAfter(XDDFSpacing spaceAfter) {
+        if (spaceAfter != null || _p.isSetPPr()) {
+            getOrCreateProperties().setSpaceAfter(spaceAfter);
+        }
+    }
+
+    /**
+     *
+     * @return the color of bullet characters within a given paragraph.
+     * A <code>null</code> value means to use the text font color.
+     */
+    public XDDFColor getBulletColor(){
+        return findDefinedParagraphProperty(
+                props -> props.isSetBuClr() || props.isSetBuClrTx(),
+                props -> new XDDFParagraphBulletProperties(props).getBulletColor()
+            ).orElse(null);
+    }
+
+    /**
+     * Set the color to be used on bullet characters within a given paragraph.
+     *
+     * @param color the bullet color
+     */
+    public void setBulletColor(XDDFColor color) {
+        if (color != null || _p.isSetPPr()) {
+            getOrCreateBulletProperties().setBulletColor(color);
+        }
+    }
+
+    /**
+     * Specifies the color to be used on bullet characters has to follow text color within a given paragraph.
+     */
+    public void setBulletColorFollowText() {
+        getOrCreateBulletProperties().setBulletColorFollowText();
+    }
+
+    /**
+     *
+     * @return the font of bullet characters within a given paragraph.
+     * A <code>null</code> value means to use the text font font.
+     */
+    public XDDFFont getBulletFont(){
+        return findDefinedParagraphProperty(
+                props -> props.isSetBuFont() || props.isSetBuFontTx(),
+                props -> new XDDFParagraphBulletProperties(props).getBulletFont()
+            ).orElse(null);
+    }
+
+    /**
+     * Set the font to be used on bullet characters within a given paragraph.
+     *
+     * @param font the bullet font
+     */
+    public void setBulletFont(XDDFFont font) {
+        if (font != null || _p.isSetPPr()) {
+            getOrCreateBulletProperties().setBulletFont(font);
+        }
+    }
+
+    /**
+     * Specifies the font to be used on bullet characters has to follow text font within a given paragraph.
+     */
+    public void setBulletFontFollowText() {
+        getOrCreateBulletProperties().setBulletFontFollowText();
+    }
+
+    /**
+     * Returns the bullet size that is to be used within a paragraph.
+     * This may be specified in three different ways, follows text size, percentage size and font points size:
+     * <p>
+     * If returned value is instance of XDDFBulletSizeFollowText, then bullet size is text size;
+     * If returned value is instance of XDDFBulletSizePercent, then bullet size is a percentage of the font size;
+     * If returned value is instance of XDDFBulletSizePoints, then bullet size is specified in points.
+     * </p>
+     *
+     * @return the bullet size
+     */
+    public XDDFBulletSize getBulletSize(){
+        return findDefinedParagraphProperty(
+                props -> props.isSetBuSzPct() || props.isSetBuSzPts() || props.isSetBuSzTx(),
+                props -> new XDDFParagraphBulletProperties(props).getBulletSize()
+            ).orElse(null);
+    }
+
+    /**
+     * Sets the bullet size that is to be used within a paragraph.
+     * This may be specified in three different ways, follows text size, percentage size and font points size:
+     * <p>
+     * If given value is instance of XDDFBulletSizeFollowText, then bullet size is text size;
+     * If given value is instance of XDDFBulletSizePercent, then bullet size is a percentage of the font size;
+     * If given value is instance of XDDFBulletSizePoints, then bullet size is specified in points.
+     * </p>
+     *
+     * @param size the bullet size specification
+     */
+    public void setBulletSize(XDDFBulletSize size) {
+        if (size != null || _p.isSetPPr()) {
+            getOrCreateBulletProperties().setBulletSize(size);
+        }
+    }
+
+    public XDDFBulletStyle getBulletStyle(){
+        return findDefinedParagraphProperty(
+                props -> props.isSetBuAutoNum() || props.isSetBuBlip() || props.isSetBuChar() || props.isSetBuNone(),
+                props -> new XDDFParagraphBulletProperties(props).getBulletStyle()
+            ).orElse(null);
+    }
+
+    public void setBulletStyle(XDDFBulletStyle style) {
+        if (style != null || _p.isSetPPr()) {
+            getOrCreateBulletProperties().setBulletStyle(style);
+        }
+    }
+
+    public boolean hasEastAsianLineBreak() {
+        return findDefinedParagraphProperty(props -> props.isSetEaLnBrk(), props -> props.getEaLnBrk())
+            .orElse(false);
+    }
+
+    public void setEastAsianLineBreak(Boolean value) {
+        if (value != null || _p.isSetPPr()) {
+            getOrCreateProperties().setEastAsianLineBreak(value);
+        }
+    }
+
+    public boolean hasLatinLineBreak() {
+        return findDefinedParagraphProperty(props -> props.isSetLatinLnBrk(), props -> props.getLatinLnBrk())
+            .orElse(false);
+    }
+
+    public void setLatinLineBreak(Boolean value) {
+        if (value != null || _p.isSetPPr()) {
+            getOrCreateProperties().setLatinLineBreak(value);
+        }
+    }
+
+    public boolean hasHangingPunctuation() {
+        return findDefinedParagraphProperty(props -> props.isSetHangingPunct(), props -> props.getHangingPunct())
+            .orElse(false);
+    }
+
+    public void setHangingPunctuation(Boolean value) {
+        if (value != null || _p.isSetPPr()) {
+            getOrCreateProperties().setHangingPunctuation(value);
+        }
+    }
+
+    public boolean isRightToLeft() {
+        return findDefinedParagraphProperty(props -> props.isSetRtl(), props -> props.getRtl())
+            .orElse(false);
+    }
+
+    public void setRightToLeft(Boolean value) {
+        if (value != null || _p.isSetPPr()) {
+            getOrCreateProperties().setRightToLeft(value);
+        }
+    }
+
+    public XDDFTabStop addTabStop() {
+        return getOrCreateProperties().addTabStop();
+    }
+
+    public XDDFTabStop insertTabStop(int index) {
+        return getOrCreateProperties().insertTabStop(index);
+    }
+
+    public void removeTabStop(int index) {
+        if (_p.isSetPPr()) {
+            getProperties().removeTabStop(index);
+        }
+    }
+
+    public XDDFTabStop getTabStop(int index) {
+        if (_p.isSetPPr()) {
+            return getProperties().getTabStop(index);
+        } else {
+            return null;
+        }
+    }
+
+    public List<XDDFTabStop> getTabStops() {
+        if (_p.isSetPPr()) {
+            return getProperties().getTabStops();
+        } else {
+            return Collections.emptyList();
+        }
+    }
+
+    public int countTabStops() {
+        if (_p.isSetPPr()) {
+            return getProperties().countTabStops();
+        } else {
+            return 0;
+        }
+    }
+
+    public XDDFParagraphBulletProperties getOrCreateBulletProperties() {
+        return getOrCreateProperties().getBulletProperties();
+    }
+
+    public XDDFParagraphBulletProperties getBulletProperties() {
+        if (_p.isSetPPr()) {
+            return getProperties().getBulletProperties();
+        } else {
+            return null;
+        }
+    }
+
+    public XDDFRunProperties getDefaultRunProperties() {
+        if (_p.isSetPPr()) {
+            return getProperties().getDefaultRunProperties();
+        } else {
+            return null;
+        }
+    }
+
+    public void setDefaultRunProperties(XDDFRunProperties properties) {
+        if (properties != null || _p.isSetPPr()) {
+            getOrCreateProperties().setDefaultRunProperties(properties);
+        }
+    }
+
+    public XDDFRunProperties getAfterLastRunProperties() {
+        if (_p.isSetEndParaRPr()) {
+            return new XDDFRunProperties(_p.getEndParaRPr());
+        } else {
+            return null;
+        }
+    }
+
+    public void setAfterLastRunProperties(XDDFRunProperties properties) {
+        if (properties == null) {
+            _p.unsetEndParaRPr();
+        } else {
+            _p.setEndParaRPr(properties.getXmlObject());
+        }
+    }
+
+    private XDDFSpacing extractSpacing(CTTextSpacing spacing) {
+        if (spacing.isSetSpcPct()) {
+            double scale = 1 - _parent.getBodyProperties().getAutoFit().getLineSpaceReduction() / 100_000.0;
+            return new XDDFSpacingPercent(spacing, spacing.getSpcPct(), scale);
+        } else if (spacing.isSetSpcPts()) {
+            return new XDDFSpacingPoints(spacing, spacing.getSpcPts());
+        }
+        return null;
+    }
+
+    private XDDFParagraphProperties getProperties() {
+        if (_properties == null) {
+            _properties = new XDDFParagraphProperties(_p.getPPr());
+        }
+        return _properties;
+    }
+
+    private XDDFParagraphProperties getOrCreateProperties() {
+        if (!_p.isSetPPr()) {
+            _properties = new XDDFParagraphProperties(_p.addNewPPr());
+        }
+        return getProperties();
+    }
+
+    protected <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
+        Function<CTTextParagraphProperties, R> getter) {
+        if (_p.isSetPPr()) {
+            int level = _p.getPPr().isSetLvl() ? 1 + _p.getPPr().getLvl() : 0;
+            return findDefinedParagraphProperty(isSet, getter, level);
+        } else {
+            return _parent.findDefinedParagraphProperty(isSet, getter, 0);
+        }
+    }
+
+    private <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
+        Function<CTTextParagraphProperties, R> getter, int level) {
+        final CTTextParagraphProperties props = _p.getPPr();
+        if (props != null && isSet.apply(props)) {
+            return Optional.ofNullable(getter.apply(props));
+        } else {
+            return _parent.findDefinedParagraphProperty(isSet, getter, level);
+        }
+    }
+
+    protected <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
+        Function<CTTextCharacterProperties, R> getter) {
+        if (_p.isSetPPr()) {
+            int level = _p.getPPr().isSetLvl() ? 1 + _p.getPPr().getLvl() : 0;
+            return findDefinedRunProperty(isSet, getter, level);
+        } else {
+            return _parent.findDefinedRunProperty(isSet, getter, 0);
+        }
+    }
+
+    private <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
+        Function<CTTextCharacterProperties, R> getter, int level) {
+        final CTTextCharacterProperties props = _p.getPPr().isSetDefRPr() ? _p.getPPr().getDefRPr() : null;
+        if (props != null && isSet.apply(props)) {
+            return Optional.ofNullable(getter.apply(props));
+        } else {
+            return _parent.findDefinedRunProperty(isSet, getter, level);
+        }
+    }
+}
diff --git a/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextRun.java b/src/ooxml/java/org/apache/poi/xddf/usermodel/text/XDDFTextRun.java
new file mode 100644 (file)
index 0000000..608eb34
--- /dev/null
@@ -0,0 +1,557 @@
+/* ====================================================================
+   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 java.util.LinkedList;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.apache.poi.POIXMLRelation;
+import org.apache.poi.common.usermodel.fonts.FontGroup;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackageRelationship;
+import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.util.Beta;
+import org.apache.poi.util.Internal;
+import org.apache.poi.xddf.usermodel.XDDFColor;
+import org.apache.poi.xddf.usermodel.XDDFFillProperties;
+import org.apache.poi.xddf.usermodel.XDDFLineProperties;
+import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
+import org.apache.poi.xssf.usermodel.XSSFFont;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextCapsType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType;
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
+
+@Beta
+public class XDDFTextRun {
+    private XDDFTextParagraph _parent;
+    private XDDFRunProperties _properties;
+    private CTTextLineBreak _tlb;
+    private CTTextField _tf;
+    private CTRegularTextRun _rtr;
+
+    @Internal
+    protected XDDFTextRun(CTTextLineBreak run, XDDFTextParagraph parent) {
+        this._tlb = run;
+        this._parent = parent;
+    }
+
+    @Internal
+    protected XDDFTextRun(CTTextField run, XDDFTextParagraph parent) {
+        this._tf = run;
+        this._parent = parent;
+    }
+
+    @Internal
+    protected XDDFTextRun(CTRegularTextRun run, XDDFTextParagraph parent) {
+        this._rtr = run;
+        this._parent = parent;
+    }
+
+    public XDDFTextParagraph getParentParagraph() {
+        return _parent;
+    }
+
+    public boolean isLineBreak() {
+        return _tlb != null;
+    }
+
+    public boolean isField() {
+        return _tf != null;
+    }
+
+    public boolean isRegularRun() {
+        return _rtr != null;
+    }
+
+    public String getText() {
+        if (isLineBreak()) {
+            return "\n";
+        } else  if (isField()) {
+            return _tf.getT();
+        } else  {
+            return _rtr.getT();
+        }
+    }
+
+    public void setText(String text) {
+        if (isField()) {
+            _tf.setT(text);
+        } else if (isRegularRun()) {
+            _rtr.setT(text);
+        }
+    }
+
+    public void setDirty(Boolean dirty) {
+        getOrCreateProperties().setDirty(dirty);
+    }
+
+    public Boolean getDirty() {
+        return findDefinedProperty(props -> props.isSetDirty(), props -> props.getDirty())
+            .orElse(null);
+    }
+
+    public void setSpellError(Boolean error) {
+        getOrCreateProperties().setSpellError(error);
+    }
+
+    public Boolean getSpellError() {
+        return findDefinedProperty(props -> props.isSetErr(), props -> props.getErr())
+            .orElse(null);
+    }
+
+    public void setNoProof(Boolean noproof) {
+        getOrCreateProperties().setNoProof(noproof);
+    }
+
+    public Boolean getNoProof() {
+        return findDefinedProperty(props -> props.isSetNoProof(), props -> props.getNoProof())
+            .orElse(null);
+    }
+
+    public void setNormalizeHeights(Boolean normalize) {
+        getOrCreateProperties().setNormalizeHeights(normalize);
+    }
+
+    public Boolean getNormalizeHeights() {
+        return findDefinedProperty(props -> props.isSetNormalizeH(), props -> props.getNormalizeH())
+            .orElse(null);
+    }
+
+    public void setKumimoji(Boolean kumimoji) {
+        getOrCreateProperties().setKumimoji(kumimoji);
+    }
+
+    public boolean isKumimoji() {
+        return findDefinedProperty(props -> props.isSetKumimoji(), props -> props.getKumimoji())
+            .orElse(false);
+    }
+
+    /**
+     * Specifies whether this run of text will be formatted as bold text.
+     *
+     * @param bold whether this run of text will be formatted as bold text.
+     */
+    public void setBold(Boolean bold) {
+        getOrCreateProperties().setBold(bold);
+    }
+
+    /**
+     * @return whether this run of text is formatted as bold text.
+     */
+    public boolean isBold() {
+        return findDefinedProperty(props -> props.isSetB(), props -> props.getB())
+            .orElse(false);
+    }
+
+    /**
+     * @param italic whether this run of text is formatted as italic text.
+     */
+    public void setItalic(Boolean italic) {
+        getOrCreateProperties().setItalic(italic);
+    }
+
+    /**
+     * @return whether this run of text is formatted as italic text.
+     */
+    public boolean isItalic() {
+        return findDefinedProperty(props -> props.isSetI(), props -> props.getI())
+            .orElse(false);
+    }
+
+    /**
+     * @param strike which strike style this run of text is formatted with.
+     */
+    public void setStrikeThrough(StrikeType strike) {
+        getOrCreateProperties().setStrikeThrough(strike);
+    }
+
+    /**
+     * @return whether this run of text is formatted as striked text.
+     */
+    public boolean isStrikeThrough() {
+        return findDefinedProperty(props -> props.isSetStrike(), props -> props.getStrike())
+            .map(strike -> strike != STTextStrikeType.NO_STRIKE)
+            .orElse(false);
+    }
+
+    /**
+     * @return which strike style this run of text is formatted with.
+     */
+    public StrikeType getStrikeThrough() {
+        return findDefinedProperty(props -> props.isSetStrike(), props -> props.getStrike())
+            .map(strike -> StrikeType.valueOf(strike))
+            .orElse(null);
+    }
+
+    /**
+     * @param underline which underline style this run of text is formatted with.
+     */
+    public void setUnderline(UnderlineType underline) {
+        getOrCreateProperties().setUnderline(underline);
+    }
+
+    /**
+     * @return whether this run of text is formatted as underlined text.
+     */
+    public boolean isUnderline() {
+        return findDefinedProperty(props -> props.isSetU(), props -> props.getU())
+            .map(underline -> underline != STTextUnderlineType.NONE)
+            .orElse(false);
+    }
+
+    /**
+     * @return which underline style this run of text is formatted with.
+     */
+    public UnderlineType getUnderline() {
+        return findDefinedProperty(props -> props.isSetU(), props -> props.getU())
+            .map(underline -> UnderlineType.valueOf(underline))
+            .orElse(null);
+    }
+
+    /**
+     * @param caps which caps style this run of text is formatted with.
+     */
+    public void setCapitals(CapsType caps) {
+        getOrCreateProperties().setCapitals(caps);
+    }
+
+    /**
+     * @return whether this run of text is formatted as capitalized text.
+     */
+    public boolean isCapitals() {
+        return findDefinedProperty(props -> props.isSetCap(), props -> props.getCap())
+            .map(caps -> caps != STTextCapsType.NONE)
+            .orElse(false);
+    }
+
+    /**
+     * @return which caps style this run of text is formatted with.
+     */
+    public CapsType getCapitals() {
+        return findDefinedProperty(props -> props.isSetCap(), props -> props.getCap())
+            .map(caps -> CapsType.valueOf(caps))
+            .orElse(null);
+    }
+
+    /**
+     * @return whether a run of text will be formatted as a subscript text. Default is false.
+     */
+    public boolean isSubscript() {
+        return findDefinedProperty(props -> props.isSetBaseline(), props -> props.getBaseline())
+            .map(baseline -> baseline < 0)
+            .orElse(false);
+    }
+
+    /**
+     * @return whether a run of text will be formatted as a superscript text. Default is false.
+     */
+    public boolean isSuperscript() {
+        return findDefinedProperty(props -> props.isSetBaseline(), props -> props.getBaseline())
+            .map(baseline -> baseline > 0)
+            .orElse(false);
+    }
+
+    /**
+     *  Set the baseline for both the superscript and subscript fonts.
+     *  <p>
+     *     The size is specified using a percentage.
+     *     Positive values indicate superscript, negative values indicate subscript.
+     *  </p>
+     *
+     * @param offset
+     */
+    public void setBaseline(Double offset){
+        getOrCreateProperties().setBaseline((int)(offset * 1000));
+    }
+
+    /**
+     * Set whether the text in this run is formatted as superscript.
+     *  <p>
+     *     The size is specified using a percentage.
+     *  </p>
+     *
+     * @param offset
+     */
+    public void setSuperscript(Double offset){
+        setBaseline(offset == null ? null : Math.abs(offset));
+    }
+
+    /**
+     * Set whether the text in this run is formatted as subscript.
+     *  <p>
+     *     The size is specified using a percentage.
+     *  </p>
+     *
+     * @param offset
+     */
+    public void setSubscript(Double offset){
+        setBaseline(offset == null ? null : -Math.abs(offset));
+    }
+
+    public void setFillProperties(XDDFFillProperties properties) {
+        getOrCreateProperties().setFillProperties(properties);
+    }
+
+    public void setFontColor(XDDFColor color) {
+        XDDFSolidFillProperties props = new XDDFSolidFillProperties();
+        props.setColor(color);
+        setFillProperties(props);
+    }
+
+    public XDDFColor getFontColor() {
+        XDDFSolidFillProperties solid = findDefinedProperty(props -> props.isSetSolidFill(), props -> props.getSolidFill())
+            .map(props -> new XDDFSolidFillProperties(props))
+            .orElse(new XDDFSolidFillProperties());
+        return solid.getColor();
+    }
+
+    /**
+     * <em>Note</em>: In order to get fonts to unset the property for a given font family use
+     * {@link XDDFFont#unsetFontForGroup(FontGroup)}
+     *
+     * @param fonts to set or unset on the run.
+     */
+    public void setFonts(XDDFFont[] fonts) {
+        getOrCreateProperties().setFonts(fonts);
+    }
+
+    public XDDFFont[] getFonts() {
+        LinkedList<XDDFFont> list = new LinkedList<>();
+
+        findDefinedProperty(props -> props.isSetCs(), props -> props.getCs())
+            .map(font -> new XDDFFont(FontGroup.COMPLEX_SCRIPT, font))
+            .ifPresent(font -> list.add(font));
+        findDefinedProperty(props -> props.isSetEa(), props -> props.getEa())
+            .map(font -> new XDDFFont(FontGroup.EAST_ASIAN, font))
+            .ifPresent(font -> list.add(font));
+        findDefinedProperty(props -> props.isSetLatin(), props -> props.getLatin())
+            .map(font -> new XDDFFont(FontGroup.LATIN, font))
+            .ifPresent(font -> list.add(font));
+        findDefinedProperty(props -> props.isSetSym(), props -> props.getSym())
+            .map(font -> new XDDFFont(FontGroup.SYMBOL, font))
+            .ifPresent(font -> list.add(font));
+
+        return list.toArray(new XDDFFont[list.size()]);
+    }
+
+    /**
+     * @param size  font size in points.
+     * The value <code>null</code> unsets the size for this run.
+     * <dl>
+     * <dt>Minimum inclusive =</dt><dd>1</dd>
+     * <dt>Maximum inclusive =</dt><dd>400</dd>
+     * </dt>
+     *
+     */
+    public void setFontSize(Double size) {
+        getOrCreateProperties().setFontSize(size);
+    }
+
+    public Double getFontSize() {
+        Integer size = findDefinedProperty(props -> props.isSetSz(), props -> props.getSz())
+            .orElse(100 * XSSFFont.DEFAULT_FONT_SIZE);   // default font size
+        double scale = _parent.getParentBody().getBodyProperties().getAutoFit().getFontScale() / 10_000_000.0;
+        return size * scale;
+    }
+
+    /**
+     * Set the kerning of characters within a text run.
+     * <p>
+     * The value <code>null</code> unsets the kerning for this run.
+     * </p>
+     *
+     * @param kerning  character kerning in points.
+     * <dl>
+     * <dt>Minimum inclusive =</dt><dd>0</dd>
+     * <dt>Maximum inclusive =</dt><dd>4000</dd>
+     * </dt>
+     */
+    public void setCharacterKerning(Double kerning){
+        getOrCreateProperties().setCharacterKerning(kerning);
+    }
+
+    /**
+     *
+     * @return the kerning of characters within a text run,
+     * If this attribute is omitted then returns <code>null</code>.
+     */
+    public Double getCharacterKerning() {
+        return findDefinedProperty(props -> props.isSetKern(), props -> props.getKern())
+            .map(kerning -> 0.01 * kerning)
+            .orElse(null);
+    }
+
+    /**
+     * Set the spacing between characters within a text run.
+     * <p>
+     * The spacing is specified in points. Positive values will cause the text to expand,
+     * negative values to condense.
+     * </p>
+     * <p>
+     * The value <code>null</code> unsets the spacing for this run.
+     * </p>
+     *
+     * @param spacing  character spacing in points.
+     * <dl>
+     * <dt>Minimum inclusive =</dt><dd>-4000</dd>
+     * <dt>Maximum inclusive =</dt><dd>4000</dd>
+     * </dt>
+     */
+    public void setCharacterSpacing(Double spacing){
+        getOrCreateProperties().setCharacterSpacing(spacing);
+    }
+
+    /**
+     *
+     * @return the spacing between characters within a text run,
+     * If this attribute is omitted then returns <code>null</code>.
+     */
+    public Double getCharacterSpacing() {
+        return findDefinedProperty(props -> props.isSetSpc(), props -> props.getSpc())
+            .map(spacing -> 0.01 * spacing)
+            .orElse(null);
+    }
+
+    public void setBookmark(String bookmark) {
+        getOrCreateProperties().setBookmark(bookmark);
+    }
+
+    public String getBookmark() {
+        return findDefinedProperty(props -> props.isSetBmk(), props -> props.getBmk())
+            .orElse(null);
+    }
+
+    public XDDFHyperlink linkToExternal(String url, PackagePart localPart, POIXMLRelation relation) {
+        PackageRelationship rel = localPart.addExternalRelationship(url, relation.getRelation());
+        XDDFHyperlink link = new XDDFHyperlink(rel.getId());
+        getOrCreateProperties().setHyperlink(link);
+        return link;
+    }
+
+    public XDDFHyperlink linkToAction(String action) {
+        XDDFHyperlink link = new XDDFHyperlink("", action);
+        getOrCreateProperties().setHyperlink(link);
+        return link;
+    }
+
+    public XDDFHyperlink linkToInternal(String action, PackagePart localPart, POIXMLRelation relation, PackagePartName target) {
+        PackageRelationship rel = localPart.addRelationship(target, TargetMode.INTERNAL, relation.getRelation());
+        XDDFHyperlink link = new XDDFHyperlink(rel.getId(), action);
+        getOrCreateProperties().setHyperlink(link);
+        return link;
+    }
+
+    public XDDFHyperlink getHyperlink() {
+        return findDefinedProperty(props -> props.isSetHlinkClick(), props -> props.getHlinkClick())
+            .map(link -> new XDDFHyperlink(link))
+            .orElse(null);
+    }
+
+    public XDDFHyperlink createMouseOver(String action) {
+        XDDFHyperlink link = new XDDFHyperlink("", action);
+        getOrCreateProperties().setMouseOver(link);
+        return link;
+    }
+
+    public XDDFHyperlink getMouseOver() {
+        return findDefinedProperty(props -> props.isSetHlinkMouseOver(), props -> props.getHlinkMouseOver())
+            .map(link -> new XDDFHyperlink(link))
+            .orElse(null);
+    }
+
+    public void setLanguage(Locale lang) {
+        getOrCreateProperties().setLanguage(lang);
+    }
+
+    public Locale getLanguage() {
+        return findDefinedProperty(props -> props.isSetLang(), props -> props.getLang())
+            .map(lang -> Locale.forLanguageTag(lang))
+            .orElse(null);
+    }
+
+    public void setAlternativeLanguage(Locale lang) {
+        getOrCreateProperties().setAlternativeLanguage(lang);
+    }
+
+    public Locale getAlternativeLanguage() {
+        return findDefinedProperty(props -> props.isSetAltLang(), props -> props.getAltLang())
+            .map(lang -> Locale.forLanguageTag(lang))
+            .orElse(null);
+    }
+
+    public void setHighlight(XDDFColor color) {
+        getOrCreateProperties().setHighlight(color);
+    }
+
+    public XDDFColor getHighlight() {
+        return findDefinedProperty(props -> props.isSetHighlight(), props -> props.getHighlight())
+            .map(color -> XDDFColor.forColorContainer(color))
+            .orElse(null);
+    }
+
+    public void setLineProperties(XDDFLineProperties properties) {
+        getOrCreateProperties().setLineProperties(properties);
+    }
+
+    public XDDFLineProperties getLineProperties() {
+        return findDefinedProperty(props -> props.isSetLn(), props -> props.getLn())
+            .map(props -> new XDDFLineProperties(props))
+            .orElse(null);
+    }
+
+    private <R> Optional<R> findDefinedProperty(Function<CTTextCharacterProperties, Boolean> isSet, Function<CTTextCharacterProperties, R> getter) {
+        CTTextCharacterProperties props = getProperties();
+        if (props != null && isSet.apply(props)) {
+            return Optional.ofNullable(getter.apply(props));
+        } else {
+            return _parent.findDefinedRunProperty(isSet, getter);
+        }
+    }
+
+    @Internal
+    protected CTTextCharacterProperties getProperties() {
+        if (isLineBreak() && _tlb.isSetRPr()) {
+            return _tlb.getRPr();
+        } else if (isField() && _tf.isSetRPr()) {
+            return _tf.getRPr();
+        } else if (isRegularRun() && _rtr.isSetRPr()) {
+            return _rtr.getRPr();
+        }
+        return null;
+    }
+
+    private XDDFRunProperties getOrCreateProperties() {
+        if (_properties == null) {
+            if (isLineBreak()) {
+                _properties = new XDDFRunProperties(_tlb.isSetRPr() ? _tlb.getRPr() : _tlb.addNewRPr());
+            } else if (isField()) {
+                _properties = new XDDFRunProperties(_tf.isSetRPr() ? _tf.getRPr() : _tf.addNewRPr());
+            } else if (isRegularRun()) {
+                _properties = new XDDFRunProperties(_rtr.isSetRPr() ? _rtr.getRPr() : _rtr.addNewRPr());
+            }
+        }
+        return _properties;
+    }
+}