diff --git a/OpenXmlFormats/Wordprocessing/Paragraph.cs b/OpenXmlFormats/Wordprocessing/Paragraph.cs index 4369db897..5ec6569b8 100644 --- a/OpenXmlFormats/Wordprocessing/Paragraph.cs +++ b/OpenXmlFormats/Wordprocessing/Paragraph.cs @@ -1229,6 +1229,11 @@ public bool IsSetSectPr() { return this.sectPr != null; } + + public void UnsetJc() + { + this.jc=null; + } } diff --git a/ooxml/XWPF/Usermodel/XWPFParagraph.cs b/ooxml/XWPF/Usermodel/XWPFParagraph.cs index c3b522752..fa983d410 100644 --- a/ooxml/XWPF/Usermodel/XWPFParagraph.cs +++ b/ooxml/XWPF/Usermodel/XWPFParagraph.cs @@ -569,18 +569,27 @@ public String FootnoteText /// /// Returns the paragraph alignment which shall be applied to text in this paragraph. /// - public ParagraphAlignment Alignment + public ParagraphAlignment? Alignment { get { - CT_PPr pr = GetCTPPr(); - return pr == null || !pr.IsSetJc() ? ParagraphAlignment.LEFT : EnumConverter.ValueOf(pr.jc.val); + CT_PPr pr = GetCTPPr(false); + return (pr == null || !pr.IsSetJc()) ? ParagraphAlignment.LEFT : EnumConverter.ValueOf(pr.jc.val); } set { - CT_PPr pr = GetCTPPr(); - CT_Jc jc = pr.IsSetJc() ? pr.jc : pr.AddNewJc(); - jc.val = EnumConverter.ValueOf(value); + if(value==null) + { + CT_PPr pr = GetCTPPr(false); + if(pr!=null) + pr.UnsetJc(); + } + else + { + CT_PPr pr = GetCTPPr(true); + CT_Jc jc = pr.IsSetJc() ? pr.jc : pr.AddNewJc(); + jc.val = EnumConverter.ValueOf((ParagraphAlignment) value); + } } } @@ -621,7 +630,7 @@ public TextAlignment VerticalAlignment { get { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(false); return (pr == null || !pr.IsSetTextAlignment()) ? TextAlignment.AUTO : EnumConverter.ValueOf(pr.textAlignment.val); } @@ -1242,8 +1251,8 @@ public bool IsWordWrapped { get { - CT_OnOff wordWrap = GetCTPPr().IsSetWordWrap() ? GetCTPPr() - .wordWrap : null; + var ppr = GetCTPPr(false); + CT_OnOff wordWrap = ppr!=null && ppr.IsSetWordWrap() ? ppr.wordWrap : null; if (wordWrap != null) { return wordWrap.val; @@ -1274,15 +1283,28 @@ public String Style { get { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(false); + if(pr==null) + { + return null; + } CT_String style = pr.IsSetPStyle() ? pr.pStyle : null; return style != null ? style.val : null; } set { - CT_PPr pr = GetCTPPr(); - CT_String style = pr.pStyle != null ? pr.pStyle : pr.AddNewPStyle(); - style.val = value; + if(value==null) + { + var pr= GetCTPPr(false); + if(pr!=null) + pr.jc = null; + } + else + { + CT_PPr pr = GetCTPPr(true); + CT_String style = pr.pStyle != null ? pr.pStyle : pr.AddNewPStyle(); + style.val = value; + } } } @@ -1292,12 +1314,15 @@ public String Style */ private CT_PBdr GetCTPBrd(bool create) { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(create); + if(pr==null) + { + return null; + } CT_PBdr ct = pr.IsSetPBdr() ? pr.pBdr : null; - if (create && ct == null) + if(create && ct == null) ct = pr.AddNewPBdr(); return ct; - } /** @@ -1306,7 +1331,7 @@ private CT_PBdr GetCTPBrd(bool create) */ private CT_Spacing GetCTSpacing(bool create) { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(create); CT_Spacing ct = pr.spacing == null ? null : pr.spacing; if (create && ct == null) ct = pr.AddNewSpacing(); @@ -1319,20 +1344,23 @@ private CT_Spacing GetCTSpacing(bool create) */ private CT_Ind GetCTInd(bool create) { - CT_PPr pr = GetCTPPr(); + CT_PPr pr = GetCTPPr(create); CT_Ind ct = pr.ind == null ? null : pr.ind; if (create && ct == null) ct = pr.AddNewInd(); return ct; } - + internal CT_PPr GetCTPPr() + { + return GetCTPPr(true); + } /** * Get a copy of the currently used CTPPr, if none is used, return * a new instance. */ - internal CT_PPr GetCTPPr() + internal CT_PPr GetCTPPr(bool create) { - CT_PPr pr = paragraph.pPr == null ? paragraph.AddNewPPr() + CT_PPr pr = (paragraph.pPr == null||!create) ? paragraph.AddNewPPr() : paragraph.pPr; return pr; } @@ -1862,6 +1890,17 @@ private bool IsTheOnlyCTFieldInRuns(XWPFFieldRun run) && ctField == ((XWPFFieldRun) r).GetCTField()); return count <= 1; } + + /// + /// Returns true if the paragraph has a paragraph alignment value of its own + /// or false in case it should fall back to the alignment value set by the paragraph style. + /// + /// + public bool IsAlignmentSet() + { + var pr = GetCTPPr(false); + return pr != null && pr.IsSetJc(); + } } } diff --git a/testcases/ooxml/XWPF/TestXWPFBugs.cs b/testcases/ooxml/XWPF/TestXWPFBugs.cs index 21d1ff2f0..b6e6b4017 100644 --- a/testcases/ooxml/XWPF/TestXWPFBugs.cs +++ b/testcases/ooxml/XWPF/TestXWPFBugs.cs @@ -27,6 +27,7 @@ namespace TestCases.XWPF using NUnit.Framework;using NUnit.Framework.Legacy; using System; using System.IO; + using System.Reflection.Metadata; using System.Xml; using TestCases; @@ -287,6 +288,20 @@ private static void addNumberingWithAbstractId(XWPFNumbering documentNumbering, documentNumbering.AddNum(abstractNumID); } + + [Test] + public void CorrectParagraphAlignment() + { + using (var document = XWPFTestDataSamples.OpenSampleDocument("bug-paragraph-alignment.docx")) { + XWPFParagraph centeredParagraph = document.GetParagraphArray(0); + ClassicAssert.IsFalse(centeredParagraph.IsAlignmentSet()); + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, centeredParagraph.Alignment); // LEFT is a fallback value here. + + XWPFParagraph leftParagraph = document.GetParagraphArray(1); + ClassicAssert.IsTrue(leftParagraph.IsAlignmentSet()); + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, leftParagraph.Alignment); // LEFT is the real alignment value. + } + } } } diff --git a/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs b/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs index 1947b95d0..229eb2179 100644 --- a/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs +++ b/testcases/ooxml/XWPF/UserModel/TestXWPFParagraph.cs @@ -105,23 +105,32 @@ public void TestSetBorderTop() } [Test] - public void TestSetAlignment() + public void TestSetGetAlignment() { //new clean instance of paragraph - XWPFDocument doc = new XWPFDocument(); - XWPFParagraph p = doc.CreateParagraph(); + using(XWPFDocument doc = new XWPFDocument()) + { + XWPFParagraph p = doc.CreateParagraph(); - ClassicAssert.AreEqual(ParagraphAlignment.LEFT, p.Alignment); + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, p.Alignment); + ClassicAssert.IsFalse(p.IsAlignmentSet()); - CT_P ctp = p.GetCTP(); - CT_PPr ppr = ctp.pPr == null ? ctp.AddNewPPr() : ctp.pPr; + CT_P ctp = p.GetCTP(); + CT_PPr ppr = ctp.pPr == null ? ctp.AddNewPPr() : ctp.pPr; - CT_Jc align = ppr.AddNewJc(); - align.val = (ST_Jc.center); - ClassicAssert.AreEqual(ParagraphAlignment.CENTER, p.Alignment); + CT_Jc align = ppr.AddNewJc(); + align.val = (ST_Jc.center); + ClassicAssert.AreEqual(ParagraphAlignment.CENTER, p.Alignment); + ClassicAssert.IsTrue(p.IsAlignmentSet()); - p.Alignment = (ParagraphAlignment.BOTH); - ClassicAssert.AreEqual((int)ST_Jc.both, (int)ppr.jc.val); + p.Alignment = (ParagraphAlignment.BOTH); + ClassicAssert.AreEqual((int) ST_Jc.both, (int) ppr.jc.val); + ClassicAssert.IsTrue(p.IsAlignmentSet()); + + p.Alignment=null; + ClassicAssert.AreEqual(ParagraphAlignment.LEFT, p.Alignment); + ClassicAssert.IsFalse(p.IsAlignmentSet()); + } } [Test] diff --git a/testcases/test-data/document/bug-paragraph-alignment.docx b/testcases/test-data/document/bug-paragraph-alignment.docx new file mode 100644 index 000000000..de4a46855 Binary files /dev/null and b/testcases/test-data/document/bug-paragraph-alignment.docx differ