From 6b1a10ac9756439f61d0d0ee9a988287c0f71936 Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Tue, 14 Sep 2010 16:32:02 +0000 Subject: [PATCH] Correct XWPFRun detection of bold/italic in a paragraph with multiple runs of different styles git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@996976 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../poi/xwpf/usermodel/XWPFDocument.java | 2 +- .../apache/poi/xwpf/usermodel/XWPFRun.java | 25 +++- .../xwpf/extractor/TestXWPFWordExtractor.java | 12 +- .../poi/xwpf/usermodel/TestXWPFRun.java | 137 +++++++++++++++++- test-data/document/TestDocument.docx | Bin 10369 -> 10861 bytes 6 files changed, 167 insertions(+), 10 deletions(-) diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 1f0db4a167..8d05120a97 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + Correct XWPFRun detection of bold/italic in a paragraph with multiple runs of different styles Link XWPFPicture to XWPFRun, so that embedded pictures can be access from where they live in the text stream Improve handling of Hyperlinks inside XWPFParagraph objects through XWPFHyperlinkRun Make XWPFParagraph make more use of XWPFRun, and less on internal StringBuffers diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java index bc773132ef..ab3b933e51 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFDocument.java @@ -1161,7 +1161,7 @@ public class XWPFDocument extends POIXMLDocument implements Document, IBody { * @see org.apache.poi.xwpf.usermodel.IBody#getParagraphArray(int) */ public XWPFParagraph getParagraphArray(int pos) { - if(pos > 0 && pos < paragraphs.size()){ + if(pos >= 0 && pos < paragraphs.size()){ return paragraphs.get(pos); } return null; diff --git a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java index d7fbd2d6a9..a72a0c7602 100644 --- a/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java +++ b/src/ooxml/java/org/apache/poi/xwpf/usermodel/XWPFRun.java @@ -118,6 +118,19 @@ public class XWPFRun { public XWPFParagraph getParagraph() { return paragraph; } + + /** + * For isBold, isItalic etc + */ + private boolean isCTOnOff(CTOnOff onoff) { + if(! onoff.isSetVal()) + return true; + if(onoff.getVal() == STOnOff.ON) + return true; + if(onoff.getVal() == STOnOff.TRUE) + return true; + return false; + } /** * Whether the bold property shall be applied to all non-complex script @@ -127,7 +140,9 @@ public class XWPFRun { */ public boolean isBold() { CTRPr pr = run.getRPr(); - return pr != null && pr.isSetB(); + if(pr == null || !pr.isSetB()) + return false; + return isCTOnOff(pr.getB()); } /** @@ -208,7 +223,9 @@ public class XWPFRun { */ public boolean isItalic() { CTRPr pr = run.getRPr(); - return pr != null && pr.isSetI(); + if(pr == null || !pr.isSetI()) + return false; + return isCTOnOff(pr.getI()); } /** @@ -284,7 +301,9 @@ public class XWPFRun { */ public boolean isStrike() { CTRPr pr = run.getRPr(); - return pr != null && pr.isSetStrike(); + if(pr == null || !pr.isSetStrike()) + return false; + return isCTOnOff(pr.getStrike()); } /** diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java b/src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java index 77315f795b..116b699066 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/extractor/TestXWPFWordExtractor.java @@ -98,16 +98,20 @@ public class TestXWPFWordExtractor extends TestCase { // Now check contents extractor.setFetchHyperlinks(false); assertEquals( - "This is a test document\nThis bit is in bold and italic\n" + - "Back to normal\nWe have a hyperlink here, and another.\n", + "This is a test document.\nThis bit is in bold and italic\n" + + "Back to normal\n" + + "This contains BOLD, ITALIC and BOTH, as well as RED and YELLOW text.\n" + + "We have a hyperlink here, and another.\n", extractor.getText() ); // One hyperlink is a real one, one is just to the top of page extractor.setFetchHyperlinks(true); assertEquals( - "This is a test document\nThis bit is in bold and italic\n" + - "Back to normal\nWe have a hyperlink here, and another.\n", + "This is a test document.\nThis bit is in bold and italic\n" + + "Back to normal\n" + + "This contains BOLD, ITALIC and BOTH, as well as RED and YELLOW text.\n" + + "We have a hyperlink here, and another.\n", extractor.getText() ); } diff --git a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java index 1e55cc5e99..695f936a58 100644 --- a/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java +++ b/src/ooxml/testcases/org/apache/poi/xwpf/usermodel/TestXWPFRun.java @@ -20,6 +20,7 @@ import java.math.BigInteger; import junit.framework.TestCase; +import org.apache.poi.xwpf.XWPFTestDataSamples; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTBr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTR; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr; @@ -190,7 +191,139 @@ public class TestXWPFRun extends TestCase { run.addBreak(BreakType.TEXT_WRAPPING); assertEquals(2, run.getCTR().sizeOfBrArray()); } - + /** + * Test that on an existing document, we do the + * right thing with it + */ + public void testExisting() { + XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("TestDocument.docx"); + XWPFParagraph p; + XWPFRun run; + + + // First paragraph is simple + p = doc.getParagraphArray(0); + assertEquals("This is a test document.", p.getText()); + assertEquals(2, p.getRuns().size()); + + run = p.getRuns().get(0); + assertEquals("This is a test document", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + run = p.getRuns().get(1); + assertEquals(".", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + + // Next paragraph is all in one style, but a different one + p = doc.getParagraphArray(1); + assertEquals("This bit is in bold and italic", p.getText()); + assertEquals(1, p.getRuns().size()); + + run = p.getRuns().get(0); + assertEquals("This bit is in bold and italic", run.toString()); + assertEquals(true, run.isBold()); + assertEquals(true, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(true, run.getCTR().getRPr().isSetB()); + assertEquals(false, run.getCTR().getRPr().getB().isSetVal()); + + + // Back to normal + p = doc.getParagraphArray(2); + assertEquals("Back to normal", p.getText()); + assertEquals(1, p.getRuns().size()); + + run = p.getRuns().get(0); + assertEquals("Back to normal", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + + // Different styles in one paragraph + p = doc.getParagraphArray(3); + assertEquals("This contains BOLD, ITALIC and BOTH, as well as RED and YELLOW text.", p.getText()); + assertEquals(11, p.getRuns().size()); + + run = p.getRuns().get(0); + assertEquals("This contains ", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + run = p.getRuns().get(1); + assertEquals("BOLD", run.toString()); + assertEquals(true, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + + run = p.getRuns().get(2); + assertEquals(", ", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + run = p.getRuns().get(3); + assertEquals("ITALIC", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(true, run.isItalic()); + assertEquals(false, run.isStrike()); + + run = p.getRuns().get(4); + assertEquals(" and ", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + run = p.getRuns().get(5); + assertEquals("BOTH", run.toString()); + assertEquals(true, run.isBold()); + assertEquals(true, run.isItalic()); + assertEquals(false, run.isStrike()); + + run = p.getRuns().get(6); + assertEquals(", as well as ", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + run = p.getRuns().get(7); + assertEquals("RED", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + + run = p.getRuns().get(8); + assertEquals(" and ", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + + run = p.getRuns().get(9); + assertEquals("YELLOW", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + + run = p.getRuns().get(10); + assertEquals(" text.", run.toString()); + assertEquals(false, run.isBold()); + assertEquals(false, run.isItalic()); + assertEquals(false, run.isStrike()); + assertEquals(null, run.getCTR().getRPr()); + } } - diff --git a/test-data/document/TestDocument.docx b/test-data/document/TestDocument.docx index 058dec5e4c3dff0b7afbe5e0ad2a93a0359bbb82..d87a542ecd1018d3f52b5cfc9a977e6a54bc9f7b 100644 GIT binary patch delta 5606 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"}>jGj9XBX6u7&mr+%lKn0#MaXPr( zW}4M!>ED^QesRgCi?+wZ5W_={PM+$Onb={z=F3giHvr%ZMjA^8Dq7;G0K!jSwRE%u=J2*jP;EwTmVp6r`~h9JbkG4AvoGC3<|wT-ti1_9mz4g&kU zmnlw`Zw}kEPn5yO=KD7}+X?GC7K3dnC;b=-#;{#8k<%h1av%!P-P;2=?zub{z7mL4 z){Jw&Zf=$oLnCUt9)ejK2T+YFB#j=woLscnnloIref~YrV5^{CF*4 zJc(vG7WR`}1)U6{k$w{9e?(n=lN7=dO&BcDl#hma)!=hqf-)a)ecNa7^$i;)18e$Z z!1AO~bhRl*CwBddie7FIx^IJVR9d_LNLE1G0-b@2e-HmVT3JF43~dMXA~^;0s3LN> z8ZrYng<4@m;9NxpeDmFv$OB(KjkQwMR#$OOtouYgd2U#4y(6R zZ~Zu{w1;=}5T>h>CuNAxj=eDxRt#(w@rO-Fa{Xz05lc-8h{8QVwdM?FB*1H#L5p*i zg6mal6dz|n?**b^)~rMiuYiS#8 zoxoW24m-YPJ%`GcLosDG2AQh?HeKrIqThKnFriv8dB>>1xNUQI+CkYI8~z{^KLwv{ zYiaYmTyxWe$p(U6_9vwMn2>7DeG9)E7#J{57XK6RrRUt*So%<`>vd?K z75)N7{N=|5ucy-4%~qe(pDnT9^Xzz*KHF3KHe5vcsR&K_!!pgyb#jq)143Ad{J%pr z@=n)Lp!5$wSHAqW& zeR6(Kzp+sw$%;sBO_HQ>HHMjcOlhEQwYlTA)=Ds zg~s-ZXPHN?_t5lIeSNt*x!(BC%jgoe>4T9W=ak|vuImSQ-^Ty!x2J(SDie!K8Cqvu zoBUU1t{d0H2**E`VT$ChrSDWMhHx>7DlRDR-#iya1vU<-1IoDl?pb z7!TcB!bVecokhE1$+Fgt(dnPwvt3Doj!Z>9aThBJv4+WEc`b50WWLz()@lknf9-5> zn}r7hB9||m7D!VT{5d$RlR^tH3u1lgOQ7~f67<3F_QEZi^-re8mDC+FTzS(w-*+_b z_ib%DY(?nF%CTJv~QC#*I z8{hVw+(2NFEb`c=J`y_e|4Jq3L`Agw85#6Sy*odjl0Qp~O+QDqWR1scrRJO`;E$FB zs#=G}AmGzr9L$5tfZ%`z9z~A?ic%hFh%{YFNcZZtvcl+PM?jiW?!MRQIj|oO^#;PCx&_k_tL`04Xqjf}_mlf?OY+ylz@G-2glZy^gA~&4kx+jpcD8P$AZ2_VD zITT8n&Gh`xCcX-jCWK=S5AuIed*THVY)CGc0N2cC4)L3VnE`z;)R8jFXAktC3o&^p z6A+>(v;qOQ{+jI&`QNC({H0V)L}F11A`ZnhWDdh_g)j;XaHjbzH)uy0@((7K^cr%W z>0l;cHn+7!GK}64kvNl_qcr6iw6_EeLzBr75jT_EJyDRVUx(Qd5hyC*cEOYfDf~dI zIpTuM;U2)Io6?G|o5t1lPZ`F*Ug%$3U4Be2f`Gs8p$57*MJ0`W&arcVWa*R)SZ<@bz_P6PK z`}Nkq(|qR^+y>@@e%eVsAC){yW>$xk&$g2^MFuSw#58uY_dqO3FN3(X%6nfE+SgjU zJ-47`3Zix-I)_T>JH<}WMLvBw3R}my!x_z{+YOsjPnD;p#Z035xAgVc^;YS0Hv8pUjS&fP1l-X4xy7{Y0po{o%&&;RxR5 zZe?6_h3xL)kU|D!sab3`u$bC1G-8~Vx6tAB{^r$`79ta%$M1hC8Mp1RS{q)yHYC^t z5vFNo_Vv4Oj^_)?jlw{JzCv|FbFbo+6_vo9t9k}kQN6-%U$9qTTz(HyEH zar_kvr3reI+|9fCoi{Gnns4T~T+D+iM84V-!;B@<-vz;MR4usw>!5*G&|# zFw-$SIPAg7E<8EZ8NE^z7mF4*WBGfao70$w?Vd|r-riUBVkk@7%_}kuwz>% delta 5104 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 MX2$-&_WR5K09EsHTL1t6 -- 2.39.5