From e5384f8dd6de3081773d11f4386a70937821687c Mon Sep 17 00:00:00 2001 From: Mark Murphy Date: Fri, 16 Dec 2016 03:21:02 +0000 Subject: [PATCH] 60465: Cannot specify interline spacing for a Paragraph in XWPF Task-Url: https://bz.apache.org/bugzilla/show_bug.cgi?id=60465 git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1774551 13f79535-47bb-0310-9956-ffa450edef68 --- .../usermodel/examples/SimpleDocument.java | 2 +- .../poi/xwpf/usermodel/XWPFParagraph.java | 59 ++++++++++++++++++- .../poi/xwpf/usermodel/TestXWPFParagraph.java | 20 +++++++ 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java index 4f5487b1fc..28433c4ed0 100644 --- a/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java +++ b/src/examples/src/org/apache/poi/xwpf/usermodel/examples/SimpleDocument.java @@ -85,7 +85,7 @@ public class SimpleDocument { //p3.setAlignment(ParagraphAlignment.DISTRIBUTE); p3.setAlignment(ParagraphAlignment.BOTH); - p3.setSpacingLineRule(LineSpacingRule.EXACT); + p3.setSpacingBetween(15, LineSpacingRule.EXACT); p3.setIndentationFirstLine(600); diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java index 4e2d3654d1..a58d0b97e0 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFParagraph.java @@ -899,7 +899,7 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents, Para * Specifies the spacing that should be added after the last line in this * paragraph in the document in absolute units. * - * @return bigInteger - value representing the spacing after the paragraph + * @return int - value representing the spacing after the paragraph * @see #setSpacingAfterLines(int) */ public int getSpacingAfterLines() { @@ -922,7 +922,7 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents, Para * * @param spaces - * a positive whole number, whose contents consist of a - * measurement in twentieths of a + * measurement in hundredths of a line */ public void setSpacingAfterLines(int spaces) { CTSpacing spacing = getCTSpacing(true); @@ -1012,11 +1012,66 @@ public class XWPFParagraph implements IBodyElement, IRunBody, ISDTContents, Para * @param rule * @see LineSpacingRule */ + // TODO Fix this to convert line to equivalent value, or deprecate this in + // favor of setSpacingLine(double, LineSpacingRule) public void setSpacingLineRule(LineSpacingRule rule) { CTSpacing spacing = getCTSpacing(true); spacing.setLineRule(STLineSpacingRule.Enum.forInt(rule.getValue())); } + /** + * Return the spacing between lines of a paragraph. The units of the return value depends on the + * {@link LineSpacingRule}. If AUTO, the return value is in lines, otherwise the return + * value is in points + * + * @return a double specifying points or lines. + */ + public double getSpacingBetween() { + CTSpacing spacing = getCTSpacing(false); + if (spacing == null || !spacing.isSetLine()) { + return -1; + } else if (spacing.getLineRule() == null || spacing.getLineRule() == STLineSpacingRule.AUTO) { + BigInteger[] val = spacing.getLine().divideAndRemainder(BigInteger.valueOf(240L)); + return val[0].doubleValue() + (val[1].doubleValue() / 240L); + } + BigInteger[] val = spacing.getLine().divideAndRemainder(BigInteger.valueOf(20L)); + return val[0].doubleValue() + (val[1].doubleValue() / 20L); + } + + /** + * Sets the spacing between lines in a paragraph + * + * @param spacing - A double specifying spacing in inches or lines. If rule is + * AUTO, then spacing is in lines. Otherwise spacing is in points. + * @param rule - {@link LineSpacingRule} indicating how spacing is interpreted. If + * AUTO, then spacing value is in lines, and the height depends on the + * font size. If AT_LEAST, then spacing value is in inches, and is the + * minimum size of the line. If the line height is taller, then the + * line expands to match. If EXACT, then spacing is the exact line + * height. If the text is taller than the line height, then it is + * clipped at the top. + */ + public void setSpacingBetween(double spacing, LineSpacingRule rule) { + CTSpacing ctSp = getCTSpacing(true); + switch (rule) { + case AUTO: + ctSp.setLine(new BigInteger(String.valueOf(Math.round(spacing * 240.0)))); + break; + default: + ctSp.setLine(new BigInteger(String.valueOf(Math.round(spacing * 20.0)))); + } + ctSp.setLineRule(STLineSpacingRule.Enum.forInt(rule.getValue())); + } + + /** + * Sets the spacing between lines in a paragraph + * + * @param spacing - A double specifying spacing in lines. + */ + public void setSpacingBetween(double spacing) { + setSpacingBetween(spacing, LineSpacingRule.AUTO); + } + /** * Specifies the indentation which shall be placed between the left text * margin for this paragraph and the left edge of that paragraph's content diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java index 756aeef554..d718a621b5 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFParagraph.java @@ -160,14 +160,34 @@ public final class TestXWPFParagraph { CTP ctp = p.getCTP(); CTPPr ppr = ctp.getPPr() == null ? ctp.addNewPPr() : ctp.getPPr(); + assertEquals(-1, p.getSpacingBefore()); assertEquals(-1, p.getSpacingAfter()); + assertEquals(-1, p.getSpacingBetween(), 0.1); + assertEquals(LineSpacingRule.AUTO, p.getSpacingLineRule()); CTSpacing spacing = ppr.addNewSpacing(); spacing.setAfter(new BigInteger("10")); assertEquals(10, p.getSpacingAfter()); + spacing.setBefore(new BigInteger("10")); + assertEquals(10, p.getSpacingBefore()); p.setSpacingAfter(100); assertEquals(100, spacing.getAfter().intValue()); + p.setSpacingBefore(100); + assertEquals(100, spacing.getBefore().intValue()); + + p.setSpacingBetween(.25, LineSpacingRule.EXACT); + assertEquals(.25, p.getSpacingBetween(), 0.01); + assertEquals(LineSpacingRule.EXACT, p.getSpacingLineRule()); + p.setSpacingBetween(1.25, LineSpacingRule.AUTO); + assertEquals(1.25, p.getSpacingBetween(), 0.01); + assertEquals(LineSpacingRule.AUTO, p.getSpacingLineRule()); + p.setSpacingBetween(.5, LineSpacingRule.AT_LEAST); + assertEquals(.5, p.getSpacingBetween(), 0.01); + assertEquals(LineSpacingRule.AT_LEAST, p.getSpacingLineRule()); + p.setSpacingBetween(1.15); + assertEquals(1.15, p.getSpacingBetween(), 0.01); + assertEquals(LineSpacingRule.AUTO, p.getSpacingLineRule()); doc.close(); }