test integration of XDDF text entities

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1839259 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alain Béarez 2018-08-26 21:33:16 +00:00
parent 0f9247a088
commit 85e2e8616d
12 changed files with 1205 additions and 720 deletions

View File

@ -1152,10 +1152,8 @@ under the License.
<target name="retest-ooxml" depends="jar"> <target name="retest-ooxml" depends="jar">
<delete dir="${ooxml.reports.test}"/> <delete dir="${ooxml.reports.test}"/>
<delete dir="${ooxml.output.test}"/>
<delete dir="${ooxml.output.test.dir}"/> <delete dir="${ooxml.output.test.dir}"/>
<mkdir dir="${ooxml.reports.test}"/> <mkdir dir="${ooxml.reports.test}"/>
<mkdir dir="${ooxml.output.test}"/>
<mkdir dir="${ooxml.output.test.dir}"/> <mkdir dir="${ooxml.output.test.dir}"/>
<!-- compile the sources --> <!-- compile the sources -->
<javac target="${jdk.version.class}" <javac target="${jdk.version.class}"

View File

@ -21,28 +21,22 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.sl.usermodel.AutoShape; import org.apache.poi.sl.usermodel.AutoShape;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual; import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;
/** /**
* Represents a shape with a preset geometry. * Represents a shape with a preset geometry.
* *
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
@Beta @Beta
public class XSLFAutoShape extends XSLFTextShape public class XSLFAutoShape extends XSLFTextShape implements AutoShape<XSLFShape, XSLFTextParagraph> {
implements AutoShape<XSLFShape,XSLFTextParagraph> {
/* package */ XSLFAutoShape(CTShape shape, XSLFSheet sheet) { /* package */ XSLFAutoShape(CTShape shape, XSLFSheet sheet) {
super(shape, sheet); super(shape, sheet);
@ -60,7 +54,8 @@ public class XSLFAutoShape extends XSLFTextShape
} }
/** /**
* @param shapeId 1-based shapeId * @param shapeId
* 1-based shapeId
*/ */
static CTShape prototype(int shapeId) { static CTShape prototype(int shapeId) {
CTShape ct = CTShape.Factory.newInstance(); CTShape ct = CTShape.Factory.newInstance();
@ -77,19 +72,7 @@ public class XSLFAutoShape extends XSLFTextShape
return ct; return ct;
} }
protected static void initTextBody(CTTextBody txBody) { @Override
CTTextBodyProperties bodypr = txBody.addNewBodyPr();
bodypr.setAnchor(STTextAnchoringType.T);
bodypr.setRtlCol(false);
CTTextParagraph p = txBody.addNewP();
p.addNewPPr().setAlgn(STTextAlignType.L);
CTTextCharacterProperties endPr = p.addNewEndParaRPr();
endPr.setLang("en-US");
endPr.setSz(1100);
p.addNewR().setT("");
txBody.addNewLstStyle();
}
protected CTTextBody getTextBody(boolean create) { protected CTTextBody getTextBody(boolean create) {
CTShape shape = (CTShape) getXmlObject(); CTShape shape = (CTShape) getXmlObject();
CTTextBody txBody = shape.getTxBody(); CTTextBody txBody = shape.getTxBody();

View File

@ -33,6 +33,7 @@ import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;
import org.apache.poi.sl.usermodel.TableCell; import org.apache.poi.sl.usermodel.TableCell;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties;
import org.apache.poi.xslf.usermodel.XSLFTableStyle.TablePartStyle; import org.apache.poi.xslf.usermodel.XSLFTableStyle.TablePartStyle;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
@ -87,8 +88,10 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
CTTableCell cell = getCell(); CTTableCell cell = getCell();
CTTextBody txBody = cell.getTxBody(); CTTextBody txBody = cell.getTxBody();
if (txBody == null && create) { if (txBody == null && create) {
txBody = cell.addNewTxBody(); XDDFTextBody body = new XDDFTextBody(this);
XSLFAutoShape.initTextBody(txBody); initTextBody(body);
cell.setTxBody(body.getXmlObject());
txBody = cell.getTxBody();
} }
return txBody; return txBody;
} }
@ -396,13 +399,13 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
ln.setCap(STLineCap.Enum.forInt(cap.ooxmlId)); ln.setCap(STLineCap.Enum.forInt(cap.ooxmlId));
} }
/** /**
* Specifies a solid color fill. The shape is filled entirely with the specified color. * Specifies a solid color fill. The shape is filled entirely with the
* specified color.
* *
* @param color the solid color fill. * @param color
* The value of <code>null</code> unsets the solidFIll attribute from the underlying xml * the solid color fill. The value of <code>null</code> unsets
* the solidFIll attribute from the underlying xml
*/ */
@Override @Override
public void setFillColor(Color color) { public void setFillColor(Color color) {
@ -480,8 +483,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
/** /**
* Retrieves the part style depending on the location of this cell * Retrieves the part style depending on the location of this cell
* *
* @param tablePartStyle the part to be returned, usually this is null * @param tablePartStyle
* and only set when used as a helper method * the part to be returned, usually this is null and only set
* when used as a helper method
* @return the table part style * @return the table part style
*/ */
private CTTablePartStyle getTablePartStyle(TablePartStyle tablePartStyle) { private CTTablePartStyle getTablePartStyle(TablePartStyle tablePartStyle) {
@ -669,8 +673,9 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
} }
/** /**
* There's no real anchor for table cells - this method is used to temporarily store the location * There's no real anchor for table cells - this method is used to
* of the cell for a later retrieval, e.g. for rendering * temporarily store the location of the cell for a later retrieval, e.g.
* for rendering
* *
* @since POI 3.15-beta2 * @since POI 3.15-beta2
*/ */

View File

@ -21,17 +21,19 @@ package org.apache.poi.xslf.usermodel;
import org.apache.poi.sl.usermodel.TextBox; import org.apache.poi.sl.usermodel.TextBox;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual; import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;
/** /**
* @author Yegor Kozlov * @author Yegor Kozlov
*/ */
@Beta @Beta
public class XSLFTextBox extends XSLFAutoShape public class XSLFTextBox extends XSLFAutoShape implements TextBox<XSLFShape, XSLFTextParagraph> {
implements TextBox<XSLFShape,XSLFTextParagraph> {
/* package */ XSLFTextBox(CTShape shape, XSLFSheet sheet) { /* package */ XSLFTextBox(CTShape shape, XSLFSheet sheet) {
super(shape, sheet); super(shape, sheet);
@ -39,7 +41,8 @@ public class XSLFTextBox extends XSLFAutoShape
/** /**
* *
* @param shapeId 1-based shapeId * @param shapeId
* 1-based shapeId
*/ */
static CTShape prototype(int shapeId) { static CTShape prototype(int shapeId) {
CTShape ct = CTShape.Factory.newInstance(); CTShape ct = CTShape.Factory.newInstance();
@ -53,8 +56,9 @@ public class XSLFTextBox extends XSLFAutoShape
CTPresetGeometry2D prst = spPr.addNewPrstGeom(); CTPresetGeometry2D prst = spPr.addNewPrstGeom();
prst.setPrst(STShapeType.RECT); prst.setPrst(STShapeType.RECT);
prst.addNewAvLst(); prst.addNewAvLst();
CTTextBody txBody = ct.addNewTxBody(); XDDFTextBody body = new XDDFTextBody(null);
XSLFAutoShape.initTextBody(txBody); initTextBody(body);
ct.setTxBody(body.getXmlObject());
return ct; return ct;
} }

View File

@ -24,6 +24,8 @@ import java.awt.geom.Rectangle2D;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import org.apache.poi.ooxml.POIXMLException; import org.apache.poi.ooxml.POIXMLException;
import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawFactory;
@ -34,6 +36,9 @@ import org.apache.poi.sl.usermodel.TextShape;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.util.Beta; import org.apache.poi.util.Beta;
import org.apache.poi.util.Units; import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.text.TextContainer;
import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
import org.apache.poi.xslf.model.PropertyFetcher; import org.apache.poi.xslf.model.PropertyFetcher;
import org.apache.poi.xslf.model.TextBodyPropertyFetcher; import org.apache.poi.xslf.model.TextBodyPropertyFetcher;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
@ -52,7 +57,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
*/ */
@Beta @Beta
public abstract class XSLFTextShape extends XSLFSimpleShape public abstract class XSLFTextShape extends XSLFSimpleShape
implements TextShape<XSLFShape,XSLFTextParagraph> { implements TextContainer, TextShape<XSLFShape, XSLFTextParagraph> {
private final List<XSLFTextParagraph> _paragraphs; private final List<XSLFTextParagraph> _paragraphs;
/* package */ XSLFTextShape(XmlObject shape, XSLFSheet sheet) { /* package */ XSLFTextShape(XmlObject shape, XSLFSheet sheet) {
@ -67,6 +72,20 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
} }
} }
protected static void initTextBody(XDDFTextBody body) {
XDDFTextParagraph p = body.getParagraph(0);
p.appendRegularRun("");
}
@Beta
public XDDFTextBody getTextBody() {
CTTextBody txBody = getTextBody(false);
if (txBody == null) {
return null;
}
return new XDDFTextBody(this, txBody);
}
@Override @Override
public Iterator<XSLFTextParagraph> iterator() { public Iterator<XSLFTextParagraph> iterator() {
return getTextParagraphs().iterator(); return getTextParagraphs().iterator();
@ -95,7 +114,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
@Override @Override
public XSLFTextRun setText(String text) { public XSLFTextRun setText(String text) {
// calling clearText or setting to a new Array leads to a XmlValueDisconnectedException // calling clearText or setting to a new Array leads to a
// XmlValueDisconnectedException
if (!_paragraphs.isEmpty()) { if (!_paragraphs.isEmpty()) {
CTTextBody txBody = getTextBody(false); CTTextBody txBody = getTextBody(false);
int cntPs = txBody.sizeOfPArray(); int cntPs = txBody.sizeOfPArray();
@ -138,7 +158,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
otherRPr = ctp.getEndParaRPr(); otherRPr = ctp.getEndParaRPr();
} }
} }
// don't copy endParaRPr to the run in case there aren't any other runs // don't copy endParaRPr to the run in case there aren't any other
// runs
// this is the case when setText() was called initially // this is the case when setText() was called initially
// otherwise the master style will be overridden/ignored // otherwise the master style will be overridden/ignored
} }
@ -319,10 +340,10 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
} }
} }
/** /**
* Returns the distance (in points) between the bottom of the text frame * Returns the distance (in points) between the bottom of the text frame and
* and the bottom of the inscribed rectangle of the shape that contains the text. * the bottom of the inscribed rectangle of the shape that contains the
* text.
* *
* @return the bottom inset in points * @return the bottom inset in points
*/ */
@ -368,9 +389,9 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
} }
/** /**
* Returns the distance (in points) between the right edge of the * Returns the distance (in points) between the right edge of the text frame
* text frame and the right edge of the inscribed rectangle of the shape * and the right edge of the inscribed rectangle of the shape that contains
* that contains the text. * the text.
* *
* @return the right inset in points * @return the right inset in points
*/ */
@ -392,8 +413,8 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
} }
/** /**
* Returns the distance (in points) between the top of the text frame * Returns the distance (in points) between the top of the text frame and
* and the top of the inscribed rectangle of the shape that contains the text. * the top of the inscribed rectangle of the shape that contains the text.
* *
* @return the top inset in points * @return the top inset in points
*/ */
@ -416,9 +437,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
/** /**
* Sets the bottom margin. * Sets the bottom margin.
*
* @see #getBottomInset() * @see #getBottomInset()
* *
* @param margin the bottom margin * @param margin
* the bottom margin
*/ */
public void setBottomInset(double margin) { public void setBottomInset(double margin) {
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
@ -433,9 +456,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
/** /**
* Sets the left margin. * Sets the left margin.
*
* @see #getLeftInset() * @see #getLeftInset()
* *
* @param margin the left margin * @param margin
* the left margin
*/ */
public void setLeftInset(double margin) { public void setLeftInset(double margin) {
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
@ -450,9 +475,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
/** /**
* Sets the right margin. * Sets the right margin.
*
* @see #getRightInset() * @see #getRightInset()
* *
* @param margin the right margin * @param margin
* the right margin
*/ */
public void setRightInset(double margin) { public void setRightInset(double margin) {
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
@ -467,9 +494,11 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
/** /**
* Sets the top margin. * Sets the top margin.
*
* @see #getTopInset() * @see #getTopInset()
* *
* @param margin the top margin * @param margin
* the top margin
*/ */
public void setTopInset(double margin) { public void setTopInset(double margin) {
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
@ -521,10 +550,12 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
/** /**
* *
* Specifies that a shape should be auto-fit to fully contain the text described within it. * Specifies that a shape should be auto-fit to fully contain the text
* Auto-fitting is when text within a shape is scaled in order to contain all the text inside * described within it. Auto-fitting is when text within a shape is scaled
* in order to contain all the text inside
* *
* @param value type of autofit * @param value
* type of autofit
*/ */
public void setTextAutofit(TextAutofit value) { public void setTextAutofit(TextAutofit value) {
CTTextBodyProperties bodyPr = getTextBodyPr(true); CTTextBodyProperties bodyPr = getTextBodyPr(true);
@ -540,9 +571,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
} }
switch (value) { switch (value) {
case NONE: bodyPr.addNewNoAutofit(); break; case NONE:
case NORMAL: bodyPr.addNewNormAutofit(); break; bodyPr.addNewNoAutofit();
case SHAPE: bodyPr.addNewSpAutoFit(); break; break;
case NORMAL:
bodyPr.addNewNormAutofit();
break;
case SHAPE:
bodyPr.addNewSpAutoFit();
break;
} }
} }
} }
@ -626,7 +663,6 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
return anchor; return anchor;
} }
@Override @Override
void copy(XSLFShape other) { void copy(XSLFShape other) {
super.copy(other); super.copy(other);
@ -715,18 +751,23 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
return TextPlaceholder.BODY; return TextPlaceholder.BODY;
} }
switch (ph) { switch (ph) {
case BODY: return TextPlaceholder.BODY; case BODY:
case TITLE: return TextPlaceholder.TITLE; return TextPlaceholder.BODY;
case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE; case TITLE:
return TextPlaceholder.TITLE;
case CENTERED_TITLE:
return TextPlaceholder.CENTER_TITLE;
default: default:
case CONTENT: return TextPlaceholder.OTHER; case CONTENT:
return TextPlaceholder.OTHER;
} }
} }
/** /**
* Helper method to allow subclasses to provide their own text paragraph * Helper method to allow subclasses to provide their own text paragraph
* *
* @param p the xml reference * @param p
* the xml reference
* *
* @return a new text paragraph * @return a new text paragraph
* *
@ -735,4 +776,19 @@ public abstract class XSLFTextShape extends XSLFSimpleShape
protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) { protected XSLFTextParagraph newTextParagraph(CTTextParagraph p) {
return new XSLFTextParagraph(p, this); return new XSLFTextParagraph(p, this);
} }
@Override
public <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
Function<CTTextParagraphProperties, R> getter) {
// TODO Auto-generated method stub
return Optional.empty();
}
@Override
public <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
Function<CTTextCharacterProperties, R> getter) {
// TODO Auto-generated method stub
return Optional.empty();
}
} }

View File

@ -89,7 +89,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
* Construct a SpreadsheetML chart from a package part. * Construct a SpreadsheetML chart from a package part.
* *
* @param part * @param part
* the package part holding the chart data, the content type must be * the package part holding the chart data, the content type must
* be
* <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code> * <code>application/vnd.openxmlformats-officedocument.drawingml.chart+xml</code>
* *
* @since POI 3.14-Beta1 * @since POI 3.14-Beta1
@ -114,7 +115,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
} }
/** /**
* Construct a new CTChartSpace bean. By default, it's just an empty placeholder for chart objects. * Construct a new CTChartSpace bean. By default, it's just an empty
* placeholder for chart objects.
*/ */
private void createChart() { private void createChart() {
CTPlotArea plotArea = getCTPlotArea(); CTPlotArea plotArea = getCTPlotArea();
@ -140,12 +142,15 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
/* /*
* Saved chart space must have the following namespaces set: <c:chartSpace * Saved chart space must have the following namespaces set:
* <c:chartSpace
* xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" * xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart"
* xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:r= * xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
* xmlns:r=
* "http://schemas.openxmlformats.org/officeDocument/2006/relationships"> * "http://schemas.openxmlformats.org/officeDocument/2006/relationships">
*/ */
xmlOptions.setSaveSyntheticDocumentElement(new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c")); xmlOptions.setSaveSyntheticDocumentElement(
new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
PackagePart part = getPackagePart(); PackagePart part = getPackagePart();
try (OutputStream out = part.getOutputStream()) { try (OutputStream out = part.getOutputStream()) {
@ -256,8 +261,9 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
} }
/** /**
* Returns the title static text, or null if none is set. * Returns the title static text, or null if none is set. Note that a title
* Note that a title formula may be set instead. * formula may be set instead.
*
* @return static title text, if set * @return static title text, if set
* @deprecated POI 3.16, use {@link #getTitleText()} instead. * @deprecated POI 3.16, use {@link #getTitleText()} instead.
*/ */
@ -268,13 +274,14 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
} }
/** /**
* Returns the title static text, or null if none is set. * Returns the title static text, or null if none is set. Note that a title
* Note that a title formula may be set instead. * formula may be set instead. Empty text result is for backward
* Empty text result is for backward compatibility, and could mean the title text is empty or there is a formula instead. * compatibility, and could mean the title text is empty or there is a
* Check for a formula first, falling back on text for cleaner logic. * formula instead. Check for a formula first, falling back on text for
* @return static title text if set, * cleaner logic.
* null if there is no title, *
* empty string if the title text is empty or the title uses a formula instead * @return static title text if set, null if there is no title, empty string
* if the title text is empty or the title uses a formula instead
*/ */
public XSSFRichTextString getTitleText() { public XSSFRichTextString getTitleText() {
if (!chart.isSetTitle()) { if (!chart.isSetTitle()) {
@ -285,8 +292,7 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
CTTitle title = chart.getTitle(); CTTitle title = chart.getTitle();
StringBuilder text = new StringBuilder(64); StringBuilder text = new StringBuilder(64);
XmlObject[] t = title XmlObject[] t = title.selectPath("declare namespace a='" + XSSFDrawing.NAMESPACE_A + "' .//a:t");
.selectPath("declare namespace a='"+XSSFDrawing.NAMESPACE_A+"' .//a:t");
for (XmlObject element : t) { for (XmlObject element : t) {
NodeList kids = element.getDomNode().getChildNodes(); NodeList kids = element.getDomNode().getChildNodes();
final int count = kids.getLength(); final int count = kids.getLength();
@ -331,7 +337,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
rich = tx.getRich(); rich = tx.getRich();
} else { } else {
rich = tx.addNewRich(); rich = tx.addNewRich();
rich.addNewBodyPr(); // body properties must exist (but can be empty) rich.addNewBodyPr(); // body properties must exist (but can be
// empty)
} }
CTTextParagraph para; CTTextParagraph para;
@ -423,7 +430,8 @@ public final class XSSFChart extends XDDFChart implements Chart, ChartAxisFactor
@Removal(version = "4.2") @Removal(version = "4.2")
private boolean hasAxis() { private boolean hasAxis() {
CTPlotArea ctPlotArea = chart.getPlotArea(); CTPlotArea ctPlotArea = chart.getPlotArea();
int totalAxisCount = ctPlotArea.sizeOfValAxArray() + ctPlotArea.sizeOfCatAxArray() + ctPlotArea.sizeOfDateAxArray() + ctPlotArea.sizeOfSerAxArray(); int totalAxisCount = ctPlotArea.sizeOfValAxArray() + ctPlotArea.sizeOfCatAxArray() + ctPlotArea
.sizeOfDateAxArray() + ctPlotArea.sizeOfSerAxArray();
return totalAxisCount > 0; return totalAxisCount > 0;
} }

View File

@ -103,7 +103,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
XSSFTextBox shape = new XSSFTextBox(getDrawing(), ctShape); XSSFTextBox shape = new XSSFTextBox(getDrawing(), ctShape);
shape.parent = this; shape.parent = this;
shape.anchor = anchor; shape.anchor = anchor;
shape.getCTShape().getSpPr().setXfrm(anchor.getCTTransform2D()); shape.setXfrm(anchor.getCTTransform2D());
return shape; return shape;
} }
@ -122,7 +122,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
XSSFSimpleShape shape = new XSSFSimpleShape(getDrawing(), ctShape); XSSFSimpleShape shape = new XSSFSimpleShape(getDrawing(), ctShape);
shape.parent = this; shape.parent = this;
shape.anchor = anchor; shape.anchor = anchor;
shape.getCTShape().getSpPr().setXfrm(anchor.getCTTransform2D()); shape.setXfrm(anchor.getCTTransform2D());
return shape; return shape;
} }
@ -220,6 +220,7 @@ public final class XSSFShapeGroup extends XSSFShape implements ShapeContainer<XS
chExt.setCy(y2); chExt.setCy(y2);
} }
@Override
protected CTShapeProperties getShapeProperties() { protected CTShapeProperties getShapeProperties() {
throw new IllegalStateException("Not supported for shape group"); throw new IllegalStateException("Not supported for shape group");
} }

View File

@ -21,13 +21,44 @@ import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Optional;
import java.util.function.Function;
import org.apache.poi.hssf.util.HSSFColor; import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.SimpleShape; import org.apache.poi.ss.usermodel.SimpleShape;
import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.util.Units; import org.apache.poi.xddf.usermodel.XDDFColor;
import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.apache.poi.xddf.usermodel.XDDFColorRgbBinary;
import org.apache.poi.xddf.usermodel.XDDFFillProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.text.TextContainer;
import org.apache.poi.xddf.usermodel.text.XDDFRunProperties;
import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTransform2D;
import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextHorzOverflowType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextVertOverflowType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType;
import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShape;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTShapeNonVisual;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt;
@ -36,9 +67,14 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STUnderlineValues;
/** /**
* Represents a shape with a predefined geometry in a SpreadsheetML drawing. * Represents a shape with a predefined geometry in a SpreadsheetML drawing.
* Possible shape types are defined in {@link org.apache.poi.ss.usermodel.ShapeTypes} * Possible shape types are defined in
* {@link org.apache.poi.ss.usermodel.ShapeTypes}
*/ */
public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph>, SimpleShape { public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParagraph>, SimpleShape, TextContainer {
/**
* The text body containing the paragraphs for this shape.
*/
private final XDDFTextBody _textBody;
/** /**
* List of the paragraphs that make up the text in this shape * List of the paragraphs that make up the text in this shape
*/ */
@ -59,10 +95,14 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
_paragraphs = new ArrayList<>(); _paragraphs = new ArrayList<>();
// initialize any existing paragraphs - this will be the default body paragraph in a new shape, // initialize any existing paragraphs - this will be the default body
// paragraph in a new shape,
// or existing paragraphs that have been loaded from the file // or existing paragraphs that have been loaded from the file
CTTextBody body = ctShape.getTxBody(); CTTextBody body = ctShape.getTxBody();
if(body != null) { if (body == null) {
_textBody = null;
} else {
_textBody = new XDDFTextBody(this, body);
for (int i = 0; i < body.sizeOfPArray(); i++) { for (int i = 0; i < body.sizeOfPArray(); i++) {
_paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape)); _paragraphs.add(new XSSFTextParagraph(body.getPArray(i), ctShape));
} }
@ -95,19 +135,12 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
geom.setPrst(STShapeType.RECT); geom.setPrst(STShapeType.RECT);
geom.addNewAvLst(); geom.addNewAvLst();
CTTextBody body = shape.addNewTxBody(); XDDFTextBody body = new XDDFTextBody(null, shape.addNewTxBody());
CTTextBodyProperties bodypr = body.addNewBodyPr(); XDDFTextParagraph p = body.initialize();
bodypr.setAnchor(STTextAnchoringType.T); XDDFRunProperties rp = p.getAfterLastRunProperties();
bodypr.setRtlCol(false); XDDFColor black = new XDDFColorRgbBinary(new byte[] { 0, 0, 0 });
CTTextParagraph p = body.addNewP(); XDDFFillProperties fp = new XDDFSolidFillProperties(black);
p.addNewPPr().setAlgn(STTextAlignType.L); rp.setFillProperties(fp);
CTTextCharacterProperties endPr = p.addNewEndParaRPr();
endPr.setLang("en-US");
endPr.setSz(1100);
CTSolidColorFillProperties scfpr = endPr.addNewSolidFill();
scfpr.addNewSrgbClr().setVal(new byte[] { 0, 0, 0 });
body.addNewLstStyle();
prototype = shape; prototype = shape;
} }
@ -119,29 +152,43 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
return ctShape; return ctShape;
} }
@Beta
public XDDFTextBody getTextBody() {
return _textBody;
}
protected void setXfrm(CTTransform2D t2d) {
ctShape.getSpPr().setXfrm(t2d);
}
@Override
public Iterator<XSSFTextParagraph> iterator() { public Iterator<XSSFTextParagraph> iterator() {
return _paragraphs.iterator(); return _paragraphs.iterator();
} }
/** /**
* Returns the text from all paragraphs in the shape. Paragraphs are separated by new lines. * Returns the text from all paragraphs in the shape. Paragraphs are
* separated by new lines.
* *
* @return text contained within this shape or empty string * @return text contained within this shape or empty string
*/ */
public String getText() { public String getText() {
final int MAX_LEVELS = 9; final int MAX_LEVELS = 9;
StringBuilder out = new StringBuilder(); StringBuilder out = new StringBuilder();
List<Integer> levelCount = new ArrayList<>(MAX_LEVELS); // maximum 9 levels List<Integer> levelCount = new ArrayList<>(MAX_LEVELS); // maximum 9
// levels
XSSFTextParagraph p = null; XSSFTextParagraph p = null;
// initialise the levelCount array - this maintains a record of the numbering to be used at each level // initialise the levelCount array - this maintains a record of the
// numbering to be used at each level
for (int k = 0; k < MAX_LEVELS; k++) { for (int k = 0; k < MAX_LEVELS; k++) {
levelCount.add(0); levelCount.add(0);
} }
for (int i = 0; i < _paragraphs.size(); i++) { for (int i = 0; i < _paragraphs.size(); i++) {
if (out.length() > 0) out.append('\n'); if (out.length() > 0) {
out.append('\n');
}
p = _paragraphs.get(i); p = _paragraphs.get(i);
if (p.isBullet() && p.getText().length() > 0) { if (p.isBullet() && p.getText().length() > 0) {
@ -183,13 +230,18 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
p = _paragraphs.get(index); p = _paragraphs.get(index);
// The rules for generating the auto numbers are as follows. If the following paragraph is also // The rules for generating the auto numbers are as follows. If the
// an auto-number, has the same type/scheme (and startAt if defined on this paragraph) then they are // following paragraph is also
// considered part of the same group. An empty bullet paragraph is counted as part of the same // an auto-number, has the same type/scheme (and startAt if defined on
// group but does not increment the count for the group. A change of type, startAt or the paragraph // this paragraph) then they are
// considered part of the same group. An empty bullet paragraph is
// counted as part of the same
// group but does not increment the count for the group. A change of
// type, startAt or the paragraph
// not being a bullet resets the count for that level to 1. // not being a bullet resets the count for that level to 1.
// first auto-number paragraph so initialise to 1 or the bullets startAt if present // first auto-number paragraph so initialise to 1 or the bullets startAt
// if present
startAt = p.getBulletAutoNumberStart(); startAt = p.getBulletAutoNumberStart();
scheme = p.getBulletAutoNumberScheme(); scheme = p.getBulletAutoNumberScheme();
if (levelCount.get(level) == 0) { if (levelCount.get(level) == 0) {
@ -205,11 +257,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
} }
while (true) { while (true) {
nextp = (index + 1) == _paragraphs.size() ? null : _paragraphs.get(index + 1); nextp = (index + 1) == _paragraphs.size() ? null : _paragraphs.get(index + 1);
if(nextp == null) break; // out of paragraphs if (nextp == null) {
if(!(nextp.isBullet() && p.isBulletAutoNumber())) break; // not an auto-number bullet break; // out of paragraphs
}
if (!(nextp.isBullet() && p.isBulletAutoNumber())) {
break; // not an auto-number bullet
}
if (nextp.getLevel() > level) { if (nextp.getLevel() > level) {
// recurse into the new level group // recurse into the new level group
if (out.length() > 0) out.append('\n'); if (out.length() > 0) {
out.append('\n');
}
index = processAutoNumGroup(index + 1, nextp.getLevel(), levelCount, out); index = processAutoNumGroup(index + 1, nextp.getLevel(), levelCount, out);
continue; // restart the loop given the new index continue; // restart the loop given the new index
} else if (nextp.getLevel() < level) { } else if (nextp.getLevel() < level) {
@ -221,12 +279,15 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
if (nextScheme == scheme && nextStartAt == startAt) { if (nextScheme == scheme && nextStartAt == startAt) {
// bullet is valid, so increment i // bullet is valid, so increment i
++index; ++index;
if (out.length() > 0) out.append('\n'); if (out.length() > 0) {
out.append('\n');
}
// indent for the level // indent for the level
for (int j = 0; j < level; j++) { for (int j = 0; j < level; j++) {
out.append('\t'); out.append('\t');
} }
// check for empty text - only output a bullet if there is text, but it is still part of the group // check for empty text - only output a bullet if there is text,
// but it is still part of the group
if (nextp.getText().length() > 0) { if (nextp.getText().length() > 0) {
// increment the count for this level // increment the count for this level
levelCount.set(level, levelCount.get(level) + 1); levelCount.set(level, levelCount.get(level) + 1);
@ -243,10 +304,15 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
return index; return index;
} }
/** /**
* Returns a string containing an appropriate prefix for an auto-numbering bullet * Returns a string containing an appropriate prefix for an auto-numbering
* @param scheme the auto-numbering scheme used by the bullet * bullet
* @param value the value of the bullet *
* @param scheme
* the auto-numbering scheme used by the bullet
* @param value
* the value of the bullet
* @return appropriate prefix for an auto-numbering bullet * @return appropriate prefix for an auto-numbering bullet
*/ */
private String getBulletPrefix(ListAutoNumber scheme, int value) { private String getBulletPrefix(ListAutoNumber scheme, int value) {
@ -255,13 +321,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
switch (scheme) { switch (scheme) {
case ALPHA_LC_PARENT_BOTH: case ALPHA_LC_PARENT_BOTH:
case ALPHA_LC_PARENT_R: case ALPHA_LC_PARENT_R:
if(scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) out.append('('); if (scheme == ListAutoNumber.ALPHA_LC_PARENT_BOTH) {
out.append('(');
}
out.append(valueToAlpha(value).toLowerCase(Locale.ROOT)); out.append(valueToAlpha(value).toLowerCase(Locale.ROOT));
out.append(')'); out.append(')');
break; break;
case ALPHA_UC_PARENT_BOTH: case ALPHA_UC_PARENT_BOTH:
case ALPHA_UC_PARENT_R: case ALPHA_UC_PARENT_R:
if(scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) out.append('('); if (scheme == ListAutoNumber.ALPHA_UC_PARENT_BOTH) {
out.append('(');
}
out.append(valueToAlpha(value)); out.append(valueToAlpha(value));
out.append(')'); out.append(')');
break; break;
@ -275,7 +345,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
break; break;
case ARABIC_PARENT_BOTH: case ARABIC_PARENT_BOTH:
case ARABIC_PARENT_R: case ARABIC_PARENT_R:
if(scheme == ListAutoNumber.ARABIC_PARENT_BOTH) out.append('('); if (scheme == ListAutoNumber.ARABIC_PARENT_BOTH) {
out.append('(');
}
out.append(value); out.append(value);
out.append(')'); out.append(')');
break; break;
@ -288,13 +360,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
break; break;
case ROMAN_LC_PARENT_BOTH: case ROMAN_LC_PARENT_BOTH:
case ROMAN_LC_PARENT_R: case ROMAN_LC_PARENT_R:
if(scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) out.append('('); if (scheme == ListAutoNumber.ROMAN_LC_PARENT_BOTH) {
out.append('(');
}
out.append(valueToRoman(value).toLowerCase(Locale.ROOT)); out.append(valueToRoman(value).toLowerCase(Locale.ROOT));
out.append(')'); out.append(')');
break; break;
case ROMAN_UC_PARENT_BOTH: case ROMAN_UC_PARENT_BOTH:
case ROMAN_UC_PARENT_R: case ROMAN_UC_PARENT_R:
if(scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) out.append('('); if (scheme == ListAutoNumber.ROMAN_UC_PARENT_BOTH) {
out.append('(');
}
out.append(valueToRoman(value)); out.append(valueToRoman(value));
out.append(')'); out.append(')');
break; break;
@ -307,7 +383,8 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
out.append('.'); out.append('.');
break; break;
default: default:
out.append('\u2022'); // can't set the font to wingdings so use the default bullet character out.append('\u2022'); // can't set the font to wingdings so use the
// default bullet character
break; break;
} }
out.append(" "); out.append(" ");
@ -328,7 +405,8 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
return alpha; return alpha;
} }
private static String[] _romanChars = new String[] { "M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I" }; private static String[] _romanChars = new String[] { "M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V",
"IV", "I" };
private static int[] _romanAlphaValues = new int[] { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 }; private static int[] _romanAlphaValues = new int[] { 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 };
/** /**
@ -355,8 +433,11 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
} }
/** /**
* Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape. * Set a single paragraph of text on the shape. Note this will replace all
* @param text string representing the paragraph text * existing paragraphs created on the shape.
*
* @param text
* string representing the paragraph text
*/ */
public void setText(String text) { public void setText(String text) {
clearText(); clearText();
@ -365,8 +446,11 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
} }
/** /**
* Set a single paragraph of text on the shape. Note this will replace all existing paragraphs created on the shape. * Set a single paragraph of text on the shape. Note this will replace all
* @param str rich text string representing the paragraph text * existing paragraphs created on the shape.
*
* @param str
* rich text string representing the paragraph text
*/ */
public void setText(XSSFRichTextString str) { public void setText(XSSFRichTextString str) {
@ -385,7 +469,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) { for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
CTRElt lt = str.getCTRst().getRArray(i); CTRElt lt = str.getCTRst().getRArray(i);
CTRPrElt ltPr = lt.getRPr(); CTRPrElt ltPr = lt.getRPr();
if(ltPr == null) ltPr = lt.addNewRPr(); if (ltPr == null) {
ltPr = lt.addNewRPr();
}
CTRegularTextRun r = p.addNewR(); CTRegularTextRun r = p.addNewR();
CTTextCharacterProperties rPr = r.addNewRPr(); CTTextCharacterProperties rPr = r.addNewRPr();
@ -403,7 +489,8 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
} }
/** /**
* Returns a collection of the XSSFTextParagraphs that are attached to this shape * Returns a collection of the XSSFTextParagraphs that are attached to this
* shape
* *
* @return text paragraphs in this shape * @return text paragraphs in this shape
*/ */
@ -436,7 +523,8 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
} }
/** /**
* Add a new paragraph run to this shape, set to the provided rich text string * Add a new paragraph run to this shape, set to the provided rich text
* string
* *
* @return created paragraph run * @return created paragraph run
*/ */
@ -455,7 +543,9 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) { for (int i = 0; i < str.getCTRst().sizeOfRArray(); i++) {
CTRElt lt = str.getCTRst().getRArray(i); CTRElt lt = str.getCTRst().getRArray(i);
CTRPrElt ltPr = lt.getRPr(); CTRPrElt ltPr = lt.getRPr();
if(ltPr == null) ltPr = lt.addNewRPr(); if (ltPr == null) {
ltPr = lt.addNewRPr();
}
CTRegularTextRun r = p.addNewR(); CTRegularTextRun r = p.addNewR();
CTTextCharacterProperties rPr = r.addNewRPr(); CTTextCharacterProperties rPr = r.addNewRPr();
@ -467,7 +557,8 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
} }
} }
// Note: the XSSFTextParagraph constructor will create its required XSSFTextRuns from the provided CTTextParagraph // Note: the XSSFTextParagraph constructor will create its required
// XSSFTextRuns from the provided CTTextParagraph
XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape); XSSFTextParagraph paragraph = new XSSFTextParagraph(p, ctShape);
_paragraphs.add(paragraph); _paragraphs.add(paragraph);
@ -477,14 +568,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* Sets the type of horizontal overflow for the text. * Sets the type of horizontal overflow for the text.
* *
* @param overflow - the type of horizontal overflow. * @param overflow
* A <code>null</code> values unsets this property. * - the type of horizontal overflow. A <code>null</code> values
* unsets this property.
*/ */
public void setTextHorizontalOverflow(TextHorizontalOverflow overflow) { public void setTextHorizontalOverflow(TextHorizontalOverflow overflow) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if (overflow == null) { if (overflow == null) {
if(bodyPr.isSetHorzOverflow()) bodyPr.unsetHorzOverflow(); if (bodyPr.isSetHorzOverflow()) {
bodyPr.unsetHorzOverflow();
}
} else { } else {
bodyPr.setHorzOverflow(STTextHorzOverflowType.Enum.forInt(overflow.ordinal() + 1)); bodyPr.setHorzOverflow(STTextHorzOverflowType.Enum.forInt(overflow.ordinal() + 1));
} }
@ -509,14 +603,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* Sets the type of vertical overflow for the text. * Sets the type of vertical overflow for the text.
* *
* @param overflow - the type of vertical overflow. * @param overflow
* A <code>null</code> values unsets this property. * - the type of vertical overflow. A <code>null</code> values
* unsets this property.
*/ */
public void setTextVerticalOverflow(TextVerticalOverflow overflow) { public void setTextVerticalOverflow(TextVerticalOverflow overflow) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if (overflow == null) { if (overflow == null) {
if(bodyPr.isSetVertOverflow()) bodyPr.unsetVertOverflow(); if (bodyPr.isSetVertOverflow()) {
bodyPr.unsetVertOverflow();
}
} else { } else {
bodyPr.setVertOverflow(STTextVertOverflowType.Enum.forInt(overflow.ordinal() + 1)); bodyPr.setVertOverflow(STTextVertOverflowType.Enum.forInt(overflow.ordinal() + 1));
} }
@ -541,14 +638,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* Sets the type of vertical alignment for the text within the shape. * Sets the type of vertical alignment for the text within the shape.
* *
* @param anchor - the type of alignment. * @param anchor
* A <code>null</code> values unsets this property. * - the type of alignment. A <code>null</code> values unsets
* this property.
*/ */
public void setVerticalAlignment(VerticalAlignment anchor) { public void setVerticalAlignment(VerticalAlignment anchor) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if (anchor == null) { if (anchor == null) {
if(bodyPr.isSetAnchor()) bodyPr.unsetAnchor(); if (bodyPr.isSetAnchor()) {
bodyPr.unsetAnchor();
}
} else { } else {
bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1)); bodyPr.setAnchor(STTextAnchoringType.Enum.forInt(anchor.ordinal() + 1));
} }
@ -573,14 +673,17 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* Sets the vertical orientation of the text * Sets the vertical orientation of the text
* *
* @param orientation vertical orientation of the text * @param orientation
* A <code>null</code> values unsets this property. * vertical orientation of the text A <code>null</code> values
* unsets this property.
*/ */
public void setTextDirection(TextDirection orientation) { public void setTextDirection(TextDirection orientation) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if (orientation == null) { if (orientation == null) {
if(bodyPr.isSetVert()) bodyPr.unsetVert(); if (bodyPr.isSetVert()) {
bodyPr.unsetVert();
}
} else { } else {
bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1)); bodyPr.setVert(STTextVerticalType.Enum.forInt(orientation.ordinal() + 1));
} }
@ -603,22 +706,22 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
return TextDirection.HORIZONTAL; return TextDirection.HORIZONTAL;
} }
/** /**
* Returns the distance (in points) between the bottom of the text frame * Returns the distance (in points) between the bottom of the text frame and
* and the bottom of the inscribed rectangle of the shape that contains the text. * the bottom of the inscribed rectangle of the shape that contains the
* text.
* *
* @return the bottom inset in points * @return the bottom inset in points
*/ */
public double getBottomInset() { public double getBottomInset() {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); Double inset = _textBody.getBodyProperties().getBottomInset();
if (bodyPr != null) { if (inset == null) {
if(bodyPr.isSetBIns()){ // If this attribute is omitted, then a value of 0.05 inches is
return Units.toPoints(bodyPr.getBIns()); // implied
}
}
// If this attribute is omitted, then a value of 0.05 inches is implied
return 3.6; return 3.6;
} else {
return inset;
}
} }
/** /**
@ -629,112 +732,115 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
* @return the left inset in points * @return the left inset in points
*/ */
public double getLeftInset() { public double getLeftInset() {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); Double inset = _textBody.getBodyProperties().getLeftInset();
if (bodyPr != null) { if (inset == null) {
if(bodyPr.isSetLIns()){ // If this attribute is omitted, then a value of 0.05 inches is
return Units.toPoints(bodyPr.getLIns()); // implied
}
}
// If this attribute is omitted, then a value of 0.05 inches is implied
return 3.6; return 3.6;
} else {
return inset;
}
} }
/** /**
* Returns the distance (in points) between the right edge of the * Returns the distance (in points) between the right edge of the text frame
* text frame and the right edge of the inscribed rectangle of the shape * and the right edge of the inscribed rectangle of the shape that contains
* that contains the text. * the text.
* *
* @return the right inset in points * @return the right inset in points
*/ */
public double getRightInset() { public double getRightInset() {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); Double inset = _textBody.getBodyProperties().getRightInset();
if (bodyPr != null) { if (inset == null) {
if(bodyPr.isSetRIns()){ // If this attribute is omitted, then a value of 0.05 inches is
return Units.toPoints(bodyPr.getRIns()); // implied
}
}
// If this attribute is omitted, then a value of 0.05 inches is implied
return 3.6; return 3.6;
} else {
return inset;
}
} }
/** /**
* Returns the distance (in points) between the top of the text frame * Returns the distance (in points) between the top of the text frame and
* and the top of the inscribed rectangle of the shape that contains the text. * the top of the inscribed rectangle of the shape that contains the text.
* *
* @return the top inset in points * @return the top inset in points
*/ */
public double getTopInset() { public double getTopInset() {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); Double inset = _textBody.getBodyProperties().getTopInset();
if (bodyPr != null) { if (inset == null) {
if(bodyPr.isSetTIns()){ // If this attribute is omitted, then a value of 0.05 inches is
return Units.toPoints(bodyPr.getTIns()); // implied
}
}
// If this attribute is omitted, then a value of 0.05 inches is implied
return 3.6; return 3.6;
} else {
return inset;
}
} }
/** /**
* Sets the bottom inset. * Sets the bottom inset.
*
* @see #getBottomInset() * @see #getBottomInset()
* *
* @param margin the bottom margin * @param margin
* the bottom margin
*/ */
public void setBottomInset(double margin) { public void setBottomInset(double margin) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) {
if (margin == -1) { if (margin == -1) {
if(bodyPr.isSetBIns()) bodyPr.unsetBIns(); _textBody.getBodyProperties().setBottomInset(null);
} else bodyPr.setBIns(Units.toEMU(margin)); } else {
_textBody.getBodyProperties().setBottomInset(margin);
} }
} }
/** /**
* Sets the left inset. * Sets the left inset.
*
* @see #getLeftInset() * @see #getLeftInset()
* *
* @param margin the left margin * @param margin
* the left margin
*/ */
public void setLeftInset(double margin) { public void setLeftInset(double margin) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) {
if (margin == -1) { if (margin == -1) {
if(bodyPr.isSetLIns()) bodyPr.unsetLIns(); _textBody.getBodyProperties().setLeftInset(null);
} else bodyPr.setLIns(Units.toEMU(margin)); } else {
_textBody.getBodyProperties().setLeftInset(margin);
} }
} }
/** /**
* Sets the right inset. * Sets the right inset.
*
* @see #getRightInset() * @see #getRightInset()
* *
* @param margin the right margin * @param margin
* the right margin
*/ */
public void setRightInset(double margin) { public void setRightInset(double margin) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) {
if (margin == -1) { if (margin == -1) {
if(bodyPr.isSetRIns()) bodyPr.unsetRIns(); _textBody.getBodyProperties().setRightInset(null);
} else bodyPr.setRIns(Units.toEMU(margin)); } else {
_textBody.getBodyProperties().setRightInset(margin);
} }
} }
/** /**
* Sets the top inset. * Sets the top inset.
*
* @see #getTopInset() * @see #getTopInset()
* *
* @param margin the top margin * @param margin
* the top margin
*/ */
public void setTopInset(double margin) { public void setTopInset(double margin) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) {
if (margin == -1) { if (margin == -1) {
if(bodyPr.isSetTIns()) bodyPr.unsetTIns(); _textBody.getBodyProperties().setTopInset(null);
} else bodyPr.setTIns(Units.toEMU(margin)); } else {
_textBody.getBodyProperties().setTopInset(margin);
} }
} }
/** /**
* @return whether to wrap words within the bounding rectangle * @return whether to wrap words within the bounding rectangle
*/ */
@ -750,7 +856,8 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* *
* @param wrap whether to wrap words within the bounding rectangle * @param wrap
* whether to wrap words within the bounding rectangle
*/ */
public void setWordWrap(boolean wrap) { public void setWordWrap(boolean wrap) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
@ -761,22 +868,36 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* *
* Specifies that a shape should be auto-fit to fully contain the text described within it. * Specifies that a shape should be auto-fit to fully contain the text
* Auto-fitting is when text within a shape is scaled in order to contain all the text inside * described within it. Auto-fitting is when text within a shape is scaled
* in order to contain all the text inside
* *
* @param value type of autofit * @param value
* type of autofit
*/ */
public void setTextAutofit(TextAutofit value) { public void setTextAutofit(TextAutofit value) {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if(bodyPr.isSetSpAutoFit()) bodyPr.unsetSpAutoFit(); if (bodyPr.isSetSpAutoFit()) {
if(bodyPr.isSetNoAutofit()) bodyPr.unsetNoAutofit(); bodyPr.unsetSpAutoFit();
if(bodyPr.isSetNormAutofit()) bodyPr.unsetNormAutofit(); }
if (bodyPr.isSetNoAutofit()) {
bodyPr.unsetNoAutofit();
}
if (bodyPr.isSetNormAutofit()) {
bodyPr.unsetNormAutofit();
}
switch (value) { switch (value) {
case NONE: bodyPr.addNewNoAutofit(); break; case NONE:
case NORMAL: bodyPr.addNewNormAutofit(); break; bodyPr.addNewNoAutofit();
case SHAPE: bodyPr.addNewSpAutoFit(); break; break;
case NORMAL:
bodyPr.addNewNormAutofit();
break;
case SHAPE:
bodyPr.addNewSpAutoFit();
break;
} }
} }
} }
@ -788,15 +909,20 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
public TextAutofit getTextAutofit() { public TextAutofit getTextAutofit() {
CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr(); CTTextBodyProperties bodyPr = ctShape.getTxBody().getBodyPr();
if (bodyPr != null) { if (bodyPr != null) {
if(bodyPr.isSetNoAutofit()) return TextAutofit.NONE; if (bodyPr.isSetNoAutofit()) {
else if (bodyPr.isSetNormAutofit()) return TextAutofit.NORMAL; return TextAutofit.NONE;
else if (bodyPr.isSetSpAutoFit()) return TextAutofit.SHAPE; } else if (bodyPr.isSetNormAutofit()) {
return TextAutofit.NORMAL;
} else if (bodyPr.isSetSpAutoFit()) {
return TextAutofit.SHAPE;
}
} }
return TextAutofit.NORMAL; return TextAutofit.NORMAL;
} }
/** /**
* Gets the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}. * Gets the shape type, one of the constants defined in
* {@link org.apache.poi.ss.usermodel.ShapeTypes}.
* *
* @return the shape type * @return the shape type
* @see org.apache.poi.ss.usermodel.ShapeTypes * @see org.apache.poi.ss.usermodel.ShapeTypes
@ -808,13 +934,16 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
/** /**
* Sets the shape types. * Sets the shape types.
* *
* @param type the shape type, one of the constants defined in {@link org.apache.poi.ss.usermodel.ShapeTypes}. * @param type
* the shape type, one of the constants defined in
* {@link org.apache.poi.ss.usermodel.ShapeTypes}.
* @see org.apache.poi.ss.usermodel.ShapeTypes * @see org.apache.poi.ss.usermodel.ShapeTypes
*/ */
public void setShapeType(int type) { public void setShapeType(int type) {
ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type)); ctShape.getSpPr().getPrstGeom().setPrst(STShapeType.Enum.forInt(type));
} }
@Override
protected CTShapeProperties getShapeProperties() { protected CTShapeProperties getShapeProperties() {
return ctShape.getSpPr(); return ctShape.getSpPr();
} }
@ -825,14 +954,22 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
*/ */
private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr) { private static void applyAttributes(CTRPrElt pr, CTTextCharacterProperties rPr) {
if(pr.sizeOfBArray() > 0) rPr.setB(pr.getBArray(0).getVal()); if (pr.sizeOfBArray() > 0) {
rPr.setB(pr.getBArray(0).getVal());
}
if (pr.sizeOfUArray() > 0) { if (pr.sizeOfUArray() > 0) {
STUnderlineValues.Enum u1 = pr.getUArray(0).getVal(); STUnderlineValues.Enum u1 = pr.getUArray(0).getVal();
if(u1 == STUnderlineValues.SINGLE) rPr.setU(STTextUnderlineType.SNG); if (u1 == STUnderlineValues.SINGLE) {
else if(u1 == STUnderlineValues.DOUBLE) rPr.setU(STTextUnderlineType.DBL); rPr.setU(STTextUnderlineType.SNG);
else if(u1 == STUnderlineValues.NONE) rPr.setU(STTextUnderlineType.NONE); } else if (u1 == STUnderlineValues.DOUBLE) {
rPr.setU(STTextUnderlineType.DBL);
} else if (u1 == STUnderlineValues.NONE) {
rPr.setU(STTextUnderlineType.NONE);
}
}
if (pr.sizeOfIArray() > 0) {
rPr.setI(pr.getIArray(0).getVal());
} }
if(pr.sizeOfIArray() > 0) rPr.setI(pr.getIArray(0).getVal());
if (pr.sizeOfRFontArray() > 0) { if (pr.sizeOfRFontArray() > 0) {
CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin(); CTTextFont rFont = rPr.isSetLatin() ? rPr.getLatin() : rPr.addNewLatin();
@ -850,8 +987,7 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
if (xlsColor.isSetRgb()) { if (xlsColor.isSetRgb()) {
CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr(); CTSRgbColor clr = fill.isSetSrgbClr() ? fill.getSrgbClr() : fill.addNewSrgbClr();
clr.setVal(xlsColor.getRgb()); clr.setVal(xlsColor.getRgb());
} } else if (xlsColor.isSetIndexed()) {
else if(xlsColor.isSetIndexed()) {
HSSFColor indexed = HSSFColor.getIndexHash().get((int) xlsColor.getIndexed()); HSSFColor indexed = HSSFColor.getIndexHash().get((int) xlsColor.getIndexed());
if (indexed != null) { if (indexed != null) {
byte[] rgb = new byte[3]; byte[] rgb = new byte[3];
@ -874,4 +1010,18 @@ public class XSSFSimpleShape extends XSSFShape implements Iterable<XSSFTextParag
public int getShapeId() { public int getShapeId() {
return (int) ctShape.getNvSpPr().getCNvPr().getId(); return (int) ctShape.getNvSpPr().getCNvPr().getId();
} }
@Override
public <R> Optional<R> findDefinedParagraphProperty(Function<CTTextParagraphProperties, Boolean> isSet,
Function<CTTextParagraphProperties, R> getter) {
// TODO Auto-generated method stub
return Optional.empty();
}
@Override
public <R> Optional<R> findDefinedRunProperty(Function<CTTextCharacterProperties, Boolean> isSet,
Function<CTTextCharacterProperties, R> getter) {
// TODO Auto-generated method stub
return Optional.empty();
}
} }

View File

@ -0,0 +1,81 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xddf.usermodel.text;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.apache.poi.util.Units;
import org.junit.Test;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;
public class TestXDDFTextBodyProperties {
@Test
public void testProperties() throws IOException {
XDDFBodyProperties body = new XDDFTextBody(null).getBodyProperties();
CTTextBodyProperties props = body.getXmlObject();
body.setBottomInset(null);
assertFalse(props.isSetBIns());
body.setBottomInset(3.6);
assertTrue(props.isSetBIns());
assertEquals(Units.toEMU(3.6), props.getBIns());
body.setLeftInset(null);
assertFalse(props.isSetLIns());
body.setLeftInset(3.6);
assertTrue(props.isSetLIns());
assertEquals(Units.toEMU(3.6), props.getLIns());
body.setRightInset(null);
assertFalse(props.isSetRIns());
body.setRightInset(3.6);
assertTrue(props.isSetRIns());
assertEquals(Units.toEMU(3.6), props.getRIns());
body.setTopInset(null);
assertFalse(props.isSetTIns());
body.setTopInset(3.6);
assertTrue(props.isSetTIns());
assertEquals(Units.toEMU(3.6), props.getTIns());
body.setAutoFit(null);
assertFalse(props.isSetNoAutofit());
assertFalse(props.isSetNormAutofit());
assertFalse(props.isSetSpAutoFit());
body.setAutoFit(new XDDFNoAutoFit());
assertTrue(props.isSetNoAutofit());
assertFalse(props.isSetNormAutofit());
assertFalse(props.isSetSpAutoFit());
body.setAutoFit(new XDDFNormalAutoFit());
assertFalse(props.isSetNoAutofit());
assertTrue(props.isSetNormAutofit());
assertFalse(props.isSetSpAutoFit());
body.setAutoFit(new XDDFShapeAutoFit());
assertFalse(props.isSetNoAutofit());
assertFalse(props.isSetNormAutofit());
assertTrue(props.isSetSpAutoFit());
}
}

View File

@ -0,0 +1,135 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.xddf.usermodel.text;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextShape;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFTextBox;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
public class TestXDDFTextRun {
@Test
public void testTextRunPropertiesInSlide() throws IOException {
try (XMLSlideShow ppt = new XMLSlideShow()) {
XSLFSlide slide = ppt.createSlide();
XSLFTextShape sh = slide.createAutoShape();
sh.addNewTextParagraph();
XDDFTextBody body = sh.getTextBody();
XDDFTextParagraph para = body.getParagraph(0);
XDDFTextRun r = para.appendRegularRun("text");
assertEquals(LocaleUtil.getUserLocale().toLanguageTag(), r.getLanguage().toLanguageTag());
assertNull(r.getCharacterSpacing());
r.setCharacterSpacing(3.0);
assertEquals(3., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(-3.0);
assertEquals(-3., r.getCharacterSpacing(), 0);
r.setCharacterSpacing(0.0);
assertEquals(0., r.getCharacterSpacing(), 0);
assertEquals(11.0, r.getFontSize(), 0);
r.setFontSize(13.0);
assertEquals(13.0, r.getFontSize(), 0);
assertFalse(r.isSuperscript());
r.setSuperscript(0.8);
assertTrue(r.isSuperscript());
r.setSuperscript(null);
assertFalse(r.isSuperscript());
assertFalse(r.isSubscript());
r.setSubscript(0.7);
assertTrue(r.isSubscript());
r.setSubscript(null);
assertFalse(r.isSubscript());
r.setBaseline(0.9);
assertTrue(r.isSuperscript());
r.setBaseline(-0.6);
assertTrue(r.isSubscript());
}
}
@Test
public void testTextRunPropertiesInSheet() throws IOException {
try (XSSFWorkbook wb = new XSSFWorkbook()) {
XSSFSheet sheet = wb.createSheet();
XSSFDrawing drawing = sheet.createDrawingPatriarch();
XSSFTextBox shape = drawing.createTextbox(new XSSFClientAnchor(0, 0, 0, 0, 2, 2, 3, 4));
shape.addNewTextParagraph().addNewTextRun().setText("Line 1");
XDDFTextBody body = shape.getTextBody();
XDDFTextParagraph para = body.getParagraph(1);
List<XDDFTextRun> runs = para.getTextRuns();
assertEquals(1, runs.size());
XDDFTextRun run = runs.get(0);
assertEquals("Line 1", run.getText());
assertFalse(run.isStrikeThrough());
run.setStrikeThrough(StrikeType.SINGLE_STRIKE);
assertTrue(run.isStrikeThrough());
run.setStrikeThrough(StrikeType.NO_STRIKE);
assertFalse(run.isStrikeThrough());
assertFalse(run.isCapitals());
run.setCapitals(CapsType.SMALL);
assertTrue(run.isCapitals());
run.setCapitals(CapsType.NONE);
assertFalse(run.isCapitals());
assertFalse(run.isBold());
run.setBold(true);
assertTrue(run.isBold());
run.setBold(false);
assertFalse(run.isBold());
assertFalse(run.isItalic());
run.setItalic(true);
assertTrue(run.isItalic());
run.setItalic(false);
assertFalse(run.isItalic());
assertFalse(run.isUnderline());
run.setUnderline(UnderlineType.WAVY_DOUBLE);
assertTrue(run.isUnderline());
run.setUnderline(UnderlineType.NONE);
assertFalse(run.isUnderline());
assertNotNull(run.getText());
}
}
}

View File

@ -30,6 +30,7 @@ import java.awt.Color;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.apache.poi.POIDataSamples; import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.usermodel.HSLFTextShape; import org.apache.poi.hslf.usermodel.HSLFTextShape;
@ -38,6 +39,8 @@ import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory; import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.sl.usermodel.VerticalAlignment;
import org.apache.poi.xddf.usermodel.text.XDDFBodyProperties;
import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.apache.poi.xslf.XSLFTestDataSamples; import org.apache.poi.xslf.XSLFTestDataSamples;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@ -83,6 +86,8 @@ public class TestXSLFTextShape {
assertEquals("Title Slide",layout.getName()); assertEquals("Title Slide",layout.getName());
XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0);
XDDFTextBody tb1 = shape1.getTextBody();
XDDFBodyProperties tbp1 = tb1.getBodyProperties();
CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false); CTPlaceholder ph1 = shape1.getPlaceholderDetails().getCTPlaceholder(false);
assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType()); assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType());
// anchor is not defined in the shape // anchor is not defined in the shape
@ -104,15 +109,24 @@ public class TestXSLFTextShape {
assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" assertEquals(3.6, shape1.getTopInset(), 0); // 0.05"
assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05"
assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment());
assertNull(tbp1.getLeftInset());
assertNull(tbp1.getRightInset());
assertNull(tbp1.getBottomInset());
assertNull(tbp1.getTopInset());
assertNull(tbp1.getAnchoring());
// now check text properties // now check text properties
assertEquals("Centered Title", shape1.getText()); assertEquals("Centered Title", shape1.getText());
assertEquals("Centered Title",
tb1.getParagraphs().stream().map(p -> p.getText()).collect(Collectors.joining("\n")));
XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals("Calibri", r1.getFontFamily()); assertEquals("Calibri", r1.getFontFamily());
assertEquals(44.0, r1.getFontSize(), 0); assertEquals(44.0, r1.getFontSize(), 0);
assertTrue(sameColor(Color.black, r1.getFontColor())); assertTrue(sameColor(Color.black, r1.getFontColor()));
XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1);
XDDFTextBody tb2 = shape2.getTextBody();
XDDFBodyProperties tbp2 = tb2.getBodyProperties();
CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false); CTPlaceholder ph2 = shape2.getPlaceholderDetails().getCTPlaceholder(false);
assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType()); assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType());
// anchor is not defined in the shape // anchor is not defined in the shape
@ -134,8 +148,14 @@ public class TestXSLFTextShape {
assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" assertEquals(3.6, shape2.getTopInset(), 0); // 0.05"
assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05"
assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment());
assertNull(tbp2.getLeftInset());
assertNull(tbp2.getRightInset());
assertNull(tbp2.getBottomInset());
assertNull(tbp2.getTopInset());
assertNull(tbp2.getAnchoring());
assertEquals("subtitle", shape2.getText()); assertEquals("subtitle", shape2.getText());
assertEquals("subtitle", tb2.getParagraphs().stream().map(p -> p.getText()).collect(Collectors.joining("\n")));
XSLFTextRun r2 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); XSLFTextRun r2 = shape2.getTextParagraphs().get(0).getTextRuns().get(0);
assertEquals("Calibri", r2.getFontFamily()); assertEquals("Calibri", r2.getFontFamily());
assertEquals(32.0, r2.getFontSize(), 0); assertEquals(32.0, r2.getFontSize(), 0);

View File

@ -16,12 +16,23 @@
==================================================================== */ ==================================================================== */
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.awt.Color; import java.awt.Color;
import java.io.IOException; import java.io.IOException;
import java.util.List;
import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xddf.usermodel.text.XDDFBodyProperties;
import org.apache.poi.xddf.usermodel.text.XDDFNoAutoFit;
import org.apache.poi.xddf.usermodel.text.XDDFNormalAutoFit;
import org.apache.poi.xddf.usermodel.text.XDDFShapeAutoFit;
import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
import org.apache.poi.xddf.usermodel.text.XDDFTextParagraph;
import org.junit.Test; import org.junit.Test;
public class TestXSSFSimpleShape { public class TestXSSFSimpleShape {
@ -68,6 +79,16 @@ public class TestXSSFSimpleShape {
shape.addNewTextParagraph(new XSSFRichTextString()); shape.addNewTextParagraph(new XSSFRichTextString());
assertEquals("null\n\ntest-other-text\nrtstring\nnull", shape.getText()); assertEquals("null\n\ntest-other-text\nrtstring\nnull", shape.getText());
XDDFTextBody body = shape.getTextBody();
assertNotNull(body);
List<XDDFTextParagraph> paragraphs = body.getParagraphs();
assertEquals(5, paragraphs.size());
assertEquals("null", body.getParagraph(0).getText());
assertEquals("", body.getParagraph(1).getText());
assertEquals("test-other-text", body.getParagraph(2).getText());
assertEquals("rtstring", body.getParagraph(3).getText());
assertEquals("null", body.getParagraph(4).getText());
assertEquals(TextHorizontalOverflow.OVERFLOW, shape.getTextHorizontalOverflow()); assertEquals(TextHorizontalOverflow.OVERFLOW, shape.getTextHorizontalOverflow());
shape.setTextHorizontalOverflow(TextHorizontalOverflow.CLIP); shape.setTextHorizontalOverflow(TextHorizontalOverflow.CLIP);
assertEquals(TextHorizontalOverflow.CLIP, shape.getTextHorizontalOverflow()); assertEquals(TextHorizontalOverflow.CLIP, shape.getTextHorizontalOverflow());
@ -108,37 +129,56 @@ public class TestXSSFSimpleShape {
shape.setTextDirection(null); shape.setTextDirection(null);
assertEquals(TextDirection.HORIZONTAL, shape.getTextDirection()); assertEquals(TextDirection.HORIZONTAL, shape.getTextDirection());
XDDFBodyProperties props = body.getBodyProperties();
assertNotNull(props);
assertEquals(3.6, shape.getBottomInset(), 0.01); assertEquals(3.6, shape.getBottomInset(), 0.01);
assertNull(props.getBottomInset());
shape.setBottomInset(12.32); shape.setBottomInset(12.32);
assertEquals(12.32, shape.getBottomInset(), 0.01); assertEquals(12.32, shape.getBottomInset(), 0.01);
assertEquals(12.32, props.getBottomInset(), 0.01);
shape.setBottomInset(-1); shape.setBottomInset(-1);
assertEquals(3.6, shape.getBottomInset(), 0.01); assertEquals(3.6, shape.getBottomInset(), 0.01);
assertNull(props.getBottomInset());
shape.setBottomInset(-1); shape.setBottomInset(-1);
assertEquals(3.6, shape.getBottomInset(), 0.01); assertEquals(3.6, shape.getBottomInset(), 0.01);
assertNull(props.getBottomInset());
assertEquals(3.6, shape.getLeftInset(), 0.01); assertEquals(3.6, shape.getLeftInset(), 0.01);
assertNull(props.getLeftInset());
shape.setLeftInset(12.31); shape.setLeftInset(12.31);
assertEquals(12.31, shape.getLeftInset(), 0.01); assertEquals(12.31, shape.getLeftInset(), 0.01);
assertEquals(12.31, props.getLeftInset(), 0.01);
shape.setLeftInset(-1); shape.setLeftInset(-1);
assertEquals(3.6, shape.getLeftInset(), 0.01); assertEquals(3.6, shape.getLeftInset(), 0.01);
assertNull(props.getLeftInset());
shape.setLeftInset(-1); shape.setLeftInset(-1);
assertEquals(3.6, shape.getLeftInset(), 0.01); assertEquals(3.6, shape.getLeftInset(), 0.01);
assertNull(props.getLeftInset());
assertEquals(3.6, shape.getRightInset(), 0.01); assertEquals(3.6, shape.getRightInset(), 0.01);
assertNull(props.getRightInset());
shape.setRightInset(13.31); shape.setRightInset(13.31);
assertEquals(13.31, shape.getRightInset(), 0.01); assertEquals(13.31, shape.getRightInset(), 0.01);
assertEquals(13.31, props.getRightInset(), 0.01);
shape.setRightInset(-1); shape.setRightInset(-1);
assertEquals(3.6, shape.getRightInset(), 0.01); assertEquals(3.6, shape.getRightInset(), 0.01);
assertNull(props.getRightInset());
shape.setRightInset(-1); shape.setRightInset(-1);
assertEquals(3.6, shape.getRightInset(), 0.01); assertEquals(3.6, shape.getRightInset(), 0.01);
assertNull(props.getRightInset());
assertEquals(3.6, shape.getTopInset(), 0.01); assertEquals(3.6, shape.getTopInset(), 0.01);
assertNull(props.getTopInset());
shape.setTopInset(23.31); shape.setTopInset(23.31);
assertEquals(23.31, shape.getTopInset(), 0.01); assertEquals(23.31, shape.getTopInset(), 0.01);
assertEquals(23.31, props.getTopInset(), 0.01);
shape.setTopInset(-1); shape.setTopInset(-1);
assertEquals(3.6, shape.getTopInset(), 0.01); assertEquals(3.6, shape.getTopInset(), 0.01);
assertNull(props.getTopInset());
shape.setTopInset(-1); shape.setTopInset(-1);
assertEquals(3.6, shape.getTopInset(), 0.01); assertEquals(3.6, shape.getTopInset(), 0.01);
assertNull(props.getTopInset());
assertTrue(shape.getWordWrap()); assertTrue(shape.getWordWrap());
shape.setWordWrap(false); shape.setWordWrap(false);
@ -147,12 +187,16 @@ public class TestXSSFSimpleShape {
assertTrue(shape.getWordWrap()); assertTrue(shape.getWordWrap());
assertEquals(TextAutofit.NORMAL, shape.getTextAutofit()); assertEquals(TextAutofit.NORMAL, shape.getTextAutofit());
assertTrue(props.getAutoFit() instanceof XDDFNormalAutoFit);
shape.setTextAutofit(TextAutofit.NORMAL); shape.setTextAutofit(TextAutofit.NORMAL);
assertEquals(TextAutofit.NORMAL, shape.getTextAutofit()); assertEquals(TextAutofit.NORMAL, shape.getTextAutofit());
assertTrue(props.getAutoFit() instanceof XDDFNormalAutoFit);
shape.setTextAutofit(TextAutofit.SHAPE); shape.setTextAutofit(TextAutofit.SHAPE);
assertEquals(TextAutofit.SHAPE, shape.getTextAutofit()); assertEquals(TextAutofit.SHAPE, shape.getTextAutofit());
assertTrue(props.getAutoFit() instanceof XDDFShapeAutoFit);
shape.setTextAutofit(TextAutofit.NONE); shape.setTextAutofit(TextAutofit.NONE);
assertEquals(TextAutofit.NONE, shape.getTextAutofit()); assertEquals(TextAutofit.NONE, shape.getTextAutofit());
assertTrue(props.getAutoFit() instanceof XDDFNoAutoFit);
assertEquals(5, shape.getShapeType()); assertEquals(5, shape.getShapeType());
shape.setShapeType(23); shape.setShapeType(23);