Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / qa / extras / ooxmlexport / ooxmlexport17.cxx
blob8473d8c6eb6bf78df528147ec1d231f4ccd92484
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <swmodeltestbase.hxx>
12 #include <queue>
14 #include <com/sun/star/beans/NamedValue.hpp>
15 #include <com/sun/star/style/ParagraphAdjust.hpp>
16 #include <com/sun/star/text/WritingMode2.hpp>
17 #include <com/sun/star/text/XBookmarksSupplier.hpp>
18 #include <com/sun/star/text/XDocumentIndex.hpp>
19 #include <com/sun/star/text/XFootnotesSupplier.hpp>
20 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
21 #include <com/sun/star/text/XTextField.hpp>
22 #include <com/sun/star/text/TextGridMode.hpp>
23 #include <com/sun/star/drawing/XShapes.hpp>
24 #include <com/sun/star/util/XRefreshable.hpp>
25 #include <com/sun/star/text/XTextDocument.hpp>
26 #include <com/sun/star/frame/XStorable.hpp>
27 #include <com/sun/star/awt/FontSlant.hpp>
28 #include <com/sun/star/awt/FontWeight.hpp>
30 #include <comphelper/scopeguard.hxx>
31 #include <comphelper/sequenceashashmap.hxx>
32 #include <officecfg/Office/Common.hxx>
33 #include <o3tl/string_view.hxx>
34 #include <comphelper/propertyvalue.hxx>
36 #include <unotxdoc.hxx>
37 #include <docsh.hxx>
38 #include <wrtsh.hxx>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <rootfrm.hxx>
42 class Test : public SwModelTestBase
44 public:
45 Test() : SwModelTestBase("/sw/qa/extras/ooxmlexport/data/", "Office Open XML Text") {}
48 DECLARE_OOXMLEXPORT_TEST(testTdf135164_cancelledNumbering, "tdf135164_cancelledNumbering.docx")
50 uno::Reference<beans::XPropertySet> xPara(getParagraph(1, u"TBMM DÖNEMİ"), uno::UNO_QUERY);
51 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
53 xPara.set(getParagraph(2, "Numbering explicitly cancelled"), uno::UNO_QUERY);
54 CPPUNIT_ASSERT_EQUAL(OUString(""), getProperty<OUString>(xPara, "ListLabelString"));
56 xPara.set(getParagraph(6, "Default style has roman numbering"), uno::UNO_QUERY);
57 CPPUNIT_ASSERT_EQUAL(OUString("i"), getProperty<OUString>(xPara, "ListLabelString"));
60 DECLARE_OOXMLEXPORT_TEST(testTdf147861_customField, "tdf147861_customField.docx")
62 // These should each be specific values, not a shared DocProperty
63 getParagraph(1, "CustomEditedTitle"); // edited
64 // A couple of nulls at the end of the string thwarted all attempts at an "equals" comparison.
65 CPPUNIT_ASSERT(getParagraph(2)->getString().startsWith(" INSERT Custom Title here"));
66 getParagraph(3, "My Title"); // edited
68 // Verify that these are fields, and not just plain text
69 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
70 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
71 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
72 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
73 CPPUNIT_ASSERT_EQUAL(OUString("CustomEditedTitle"), xField->getPresentation(false));
74 // The " (fixed)" part is unnecessary, but it must be consistent across a round-trip
75 CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Title (fixed)"), xField->getPresentation(true));
78 DECLARE_OOXMLEXPORT_TEST(testTdf148380_createField, "tdf148380_createField.docx")
80 // Verify that these are fields, and not just plain text
81 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
82 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
83 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
84 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
85 // This should NOT be "Lorenzo Chavez", or a real date since the user hand-modified the result.
86 CPPUNIT_ASSERT_EQUAL(OUString("Myself - that's who"), xField->getPresentation(false));
87 xField.set(xFields->nextElement(), uno::UNO_QUERY);
88 CPPUNIT_ASSERT_EQUAL(OUString("yesterday at noon"), xField->getPresentation(false));
91 DECLARE_OOXMLEXPORT_TEST(testTdf148380_fldLocked, "tdf148380_fldLocked.docx")
93 getParagraph(2, "4/5/2022 4:29:00 PM");
94 getParagraph(4, "1/23/4567 8:9:10 PM");
96 // Verify that these are fields, and not just plain text
97 // (import only, since export thankfully just dumps these fixed fields as plain text
98 if (isExported())
99 return;
100 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
101 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
102 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
103 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
104 // This should NOT be updated at FILEOPEN to match the last modified time - it is locked.
105 CPPUNIT_ASSERT_EQUAL(OUString("4/5/2022 4:29:00 PM"), xField->getPresentation(false));
106 CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Modified (fixed)"), xField->getPresentation(true));
107 xField.set(xFields->nextElement(), uno::UNO_QUERY);
108 CPPUNIT_ASSERT_EQUAL(OUString("1/23/4567 8:9:10 PM"), xField->getPresentation(false));
109 CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Last printed (fixed)"), xField->getPresentation(true));
112 DECLARE_OOXMLEXPORT_TEST(testTdf148380_usernameField, "tdf148380_usernameField.docx")
114 // Verify that these are fields, and not just plain text
115 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
116 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
117 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
118 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
119 // These should match the as-last-seen-in-the-text name, and not the application's user name
120 CPPUNIT_ASSERT_EQUAL(OUString("Charlie Brown"), xField->getPresentation(false));
121 xField.set(xFields->nextElement(), uno::UNO_QUERY);
122 CPPUNIT_ASSERT_EQUAL(OUString("CB"), xField->getPresentation(false));
125 DECLARE_OOXMLEXPORT_TEST(testTdf148380_modifiedField, "tdf148380_modifiedField.docx")
127 getParagraph(2, "4/5/2022 3:29:00 PM"); // default (unspecified) date format
129 // Verify that these are fields, and not just plain text
130 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
131 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
132 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
133 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
134 // unspecified SAVEDATE gets default US formatting because style.xml has w:lang w:val="en-US"
135 CPPUNIT_ASSERT_EQUAL(OUString("4/5/2022 3:29:00 PM"), xField->getPresentation(false));
136 xField.set(xFields->nextElement(), uno::UNO_QUERY);
137 // This was hand-modified and really should be Charlie Brown, not Charles ...
138 CPPUNIT_ASSERT_EQUAL(OUString("Charlie Brown"), xField->getPresentation(false));
141 DECLARE_OOXMLEXPORT_TEST(testTdf148380_printField, "tdf148380_printField.docx")
143 // Verify that these are fields, and not just plain text
144 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
145 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
146 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
147 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
148 // unspecified SAVEDATE gets default GB formatting because style.xml has w:lang w:val="en-GB"
149 CPPUNIT_ASSERT_EQUAL(OUString("08/04/2022 07:10:00 AM"), xField->getPresentation(false));
150 CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Modified"), xField->getPresentation(true));
151 xField.set(xFields->nextElement(), uno::UNO_QUERY);
152 // MS Word actually shows "8 o'clock-ish" until the document is reprinted,
153 // but it seems best to actually show the real last-printed date since it can't be FIXEDFLD
154 CPPUNIT_ASSERT_EQUAL(OUString("08/04/2022 06:47:00 AM"), xField->getPresentation(false));
155 CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Last printed"), xField->getPresentation(true));
158 DECLARE_OOXMLEXPORT_TEST(testTdf132475_printField, "tdf132475_printField.docx")
160 // The last printed date field: formatted two different ways
161 getParagraph(2, "Thursday, March 17, 2022");
162 getParagraph(3, "17-Mar-22");
163 // Time zone affects the displayed time in MS Word. LO shows GMT time. Word only updated by F9
164 getParagraph(5, "12:49");
165 getParagraph(6, "12:49:00 PM");
167 // Verify that these are fields, and not just plain text
168 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
169 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
170 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
171 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
172 CPPUNIT_ASSERT_EQUAL(OUString("Thursday, March 17, 2022"), xField->getPresentation(false));
173 CPPUNIT_ASSERT_EQUAL(OUString("DocInformation:Last printed"), xField->getPresentation(true));
176 DECLARE_OOXMLEXPORT_TEST(testTdf114734_commentFormating, "tdf114734_commentFormating.docx")
178 // Get the PostIt/Comment/Annotation
179 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
180 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
181 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
182 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
184 uno::Reference<text::XText> xText = getProperty<uno::Reference<text::XText>>(xField, "TextRange");
185 uno::Reference<text::XTextRange> xParagraph = getParagraphOfText(1, xText);
186 // Paragraph formatting was lost: should be right to left, and thus right-justified
187 CPPUNIT_ASSERT_EQUAL_MESSAGE("Right to Left comment",
188 text::WritingMode2::RL_TB,
189 getProperty<sal_Int16>(xParagraph, "WritingMode"));
190 CPPUNIT_ASSERT_EQUAL_MESSAGE("literal right justified",
191 sal_Int16(style::ParagraphAdjust_RIGHT),
192 getProperty<sal_Int16>(xParagraph, "ParaAdjust"));
195 DECLARE_OOXMLEXPORT_TEST(testTdf139759_commentHighlightBackground, "tdf139759_commentHighlightBackground.docx")
197 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
198 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
199 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
200 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
202 uno::Reference<text::XText> xText = getProperty<uno::Reference<text::XText>>(xField, "TextRange");
203 uno::Reference<text::XTextRange> xParagraph = getParagraphOfText(1, xText);
204 CPPUNIT_ASSERT_EQUAL(COL_YELLOW, getProperty<Color>(getRun(xParagraph, 2), "CharBackColor"));
207 CPPUNIT_TEST_FIXTURE(Test, testTdf135906)
209 loadAndReload("tdf135906.docx");
210 // just test round-tripping. The document was exported as corrupt and didn't re-load.
213 DECLARE_OOXMLEXPORT_TEST(testTdf146802, "tdf146802.docx")
215 // First check if the load failed, as before the fix.
216 CPPUNIT_ASSERT(mxComponent);
218 // There is a group shape with text box inside having an embedded VML formula,
219 // check if something missing.
220 CPPUNIT_ASSERT_EQUAL_MESSAGE("Where is the formula?", 2, getShapes());
221 // Before the fix the bugdoc failed to load or the formula was missing.
224 CPPUNIT_TEST_FIXTURE(Test, testParaStyleNumLevel)
226 loadAndSave("para-style-num-level.docx");
227 xmlDocUniquePtr pXmlDoc = parseExport("word/styles.xml");
228 // Without the accompanying fix in place, this test would have failed with:
229 // - Expected: 1
230 // - Actual : 0
231 // i.e. a custom list level in a para style was lost on import+export.
232 assertXPath(pXmlDoc, "/w:styles/w:style[@w:styleId='Mystyle']/w:pPr/w:numPr/w:ilvl", "val", "1");
235 CPPUNIT_TEST_FIXTURE(Test, testClearingBreak)
237 // Given a document with a clearing break, when saving to DOCX:
238 loadAndSave("clearing-break.docx");
240 // Then make sure that the clearing break is not lost:
241 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
242 // Without the accompanying fix in place, this test would have failed with:
243 // - XPath '/w:document/w:body/w:p/w:r/w:br' number of nodes is incorrect
244 // i.e. first the clearing break was turned into a plain break, then it was completely lost.
245 assertXPath(pXmlDoc, "/w:document/w:body/w:p/w:r/w:br", "clear", "all");
248 CPPUNIT_TEST_FIXTURE(Test, testContentControlExport)
250 // Given a document with a content control around one or more text portions:
251 createSwDoc();
252 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
253 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
254 uno::Reference<text::XText> xText = xTextDocument->getText();
255 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
256 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
257 xCursor->gotoStart(/*bExpand=*/false);
258 xCursor->gotoEnd(/*bExpand=*/true);
259 uno::Reference<text::XTextContent> xContentControl(
260 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
261 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
262 xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::Any(true));
263 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
265 // When exporting to DOCX:
266 save("Office Open XML Text");
268 // Then make sure the expected markup is used:
269 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
270 // Without the accompanying fix in place, this test would have failed with:
271 // - Expected: 1
272 // - Actual : 0
273 // XPath '//w:sdt/w:sdtPr/w:showingPlcHdr' number of nodes is incorrect
274 // i.e. the SDT elements were missing on export.
275 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:showingPlcHdr", 1);
276 assertXPath(pXmlDoc, "//w:sdt/w:sdtContent", 1);
279 CPPUNIT_TEST_FIXTURE(Test, testCheckboxContentControlExport)
281 // Given a document with a checkbox content control around a text portion:
282 createSwDoc();
283 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
284 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
285 uno::Reference<text::XText> xText = xTextDocument->getText();
286 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
287 xText->insertString(xCursor, OUString(u"☐"), /*bAbsorb=*/false);
288 xCursor->gotoStart(/*bExpand=*/false);
289 xCursor->gotoEnd(/*bExpand=*/true);
290 uno::Reference<text::XTextContent> xContentControl(
291 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
292 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
293 xContentControlProps->setPropertyValue("Checkbox", uno::Any(true));
294 xContentControlProps->setPropertyValue("Checked", uno::Any(true));
295 xContentControlProps->setPropertyValue("CheckedState", uno::Any(OUString(u"☒")));
296 xContentControlProps->setPropertyValue("UncheckedState", uno::Any(OUString(u"☐")));
297 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
299 // When exporting to DOCX:
300 save("Office Open XML Text");
302 // Then make sure the expected markup is used:
303 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
304 // Without the fix in place, this test would have failed with:
305 // - Expected: 1
306 // - Actual : 0
307 // - XPath '//w:sdt/w:sdtPr/w14:checkbox/w14:checked' number of nodes is incorrect
308 // i.e. <w14:checkbox> and its child elements were lost.
309 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w14:checkbox/w14:checked", "val", "1");
310 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w14:checkbox/w14:checkedState", "val", "2612");
311 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w14:checkbox/w14:uncheckedState", "val", "2610");
314 CPPUNIT_TEST_FIXTURE(Test, testDropdownContentControlExport)
316 // Given a document with a dropdown content control around a text portion:
317 createSwDoc();
318 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
319 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
320 uno::Reference<text::XText> xText = xTextDocument->getText();
321 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
322 xText->insertString(xCursor, "choose an item", /*bAbsorb=*/false);
323 xCursor->gotoStart(/*bExpand=*/false);
324 xCursor->gotoEnd(/*bExpand=*/true);
325 uno::Reference<text::XTextContent> xContentControl(
326 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
327 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
329 xContentControlProps->setPropertyValue("DropDown", uno::Any(true));
330 uno::Sequence<beans::PropertyValues> aListItems = {
332 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))),
333 comphelper::makePropertyValue("Value", uno::Any(OUString("R"))),
336 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))),
337 comphelper::makePropertyValue("Value", uno::Any(OUString("G"))),
340 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))),
341 comphelper::makePropertyValue("Value", uno::Any(OUString("B"))),
344 xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems));
346 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
348 // When exporting to DOCX:
349 save("Office Open XML Text");
351 // Then make sure the expected markup is used:
352 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
353 // Without the fix in place, this test would have failed with:
354 // - Expected: 1
355 // - Actual : 0
356 // - XPath '//w:sdt/w:sdtPr/w:dropDownList/w:listItem[1]' number of nodes is incorrect
357 // i.e. the list items were lost on export.
358 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[1]", "displayText", "red");
359 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[1]", "value", "R");
360 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[2]", "displayText", "green");
361 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[2]", "value", "G");
362 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[3]", "displayText", "blue");
363 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dropDownList/w:listItem[3]", "value", "B");
366 CPPUNIT_TEST_FIXTURE(Test, testPictureContentControlExport)
368 // Given a document with a picture content control around a text portion:
369 createSwDoc();
370 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
371 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
372 uno::Reference<text::XText> xText = xTextDocument->getText();
373 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
374 uno::Reference<beans::XPropertySet> xTextGraphic(
375 xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
376 xTextGraphic->setPropertyValue("AnchorType",
377 uno::Any(text::TextContentAnchorType_AS_CHARACTER));
378 uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY);
379 xText->insertTextContent(xCursor, xTextContent, false);
380 xCursor->gotoStart(/*bExpand=*/false);
381 xCursor->gotoEnd(/*bExpand=*/true);
382 uno::Reference<text::XTextContent> xContentControl(
383 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
384 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
385 xContentControlProps->setPropertyValue("Picture", uno::Any(true));
386 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
388 // When exporting to DOCX:
389 save("Office Open XML Text");
391 // Then make sure the expected markup is used:
392 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
393 // Without the fix in place, this test would have failed with:
394 // - Expected: 1
395 // - Actual : 0
396 // i.e. <w:picture> was lost on export.
397 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:picture", 1);
400 CPPUNIT_TEST_FIXTURE(Test, testDateContentControlExport)
402 // Given a document with a date content control around a text portion:
403 createSwDoc();
404 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
405 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
406 uno::Reference<text::XText> xText = xTextDocument->getText();
407 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
408 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
409 xCursor->gotoStart(/*bExpand=*/false);
410 xCursor->gotoEnd(/*bExpand=*/true);
411 uno::Reference<text::XTextContent> xContentControl(
412 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
413 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
414 xContentControlProps->setPropertyValue("Date", uno::Any(true));
415 xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("M/d/yyyy")));
416 xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US")));
417 xContentControlProps->setPropertyValue("CurrentDate", uno::Any(OUString("2022-05-26T00:00:00Z")));
418 xContentControlProps->setPropertyValue("PlaceholderDocPart", uno::Any(OUString("DefaultPlaceholder_-1854013437")));
419 xContentControlProps->setPropertyValue("DataBindingPrefixMappings", uno::Any(OUString("xmlns:ns0='http://schemas.microsoft.com/vsto/samples' ")));
420 xContentControlProps->setPropertyValue("DataBindingXpath", uno::Any(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]")));
421 xContentControlProps->setPropertyValue("DataBindingStoreItemID", uno::Any(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}")));
422 xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000")));
423 xContentControlProps->setPropertyValue("Appearance", uno::Any(OUString("hidden")));
424 xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("myalias")));
425 xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
426 xContentControlProps->setPropertyValue("Id", uno::Any(static_cast<sal_Int32>(123)));
427 xContentControlProps->setPropertyValue("TabIndex", uno::Any(sal_uInt32(4294967295))); // -1
428 xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("sdtLocked")));
430 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
432 // When exporting to DOCX:
433 save("Office Open XML Text");
435 // Then make sure the expected markup is used:
436 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
437 // Without the fix in place, this test would have failed with:
438 // - Expected: 1
439 // - Actual : 0
440 // - XPath '//w:sdt/w:sdtPr/w:date/w:dateFormat' number of nodes is incorrect
441 // i.e. the <w:date> was lost on export.
442 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:date/w:dateFormat", "val", "M/d/yyyy");
443 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:date/w:lid", "val", "en-US");
444 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:date", "fullDate", "2022-05-26T00:00:00Z");
445 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:placeholder/w:docPart", "val", "DefaultPlaceholder_-1854013437");
446 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dataBinding", "prefixMappings", "xmlns:ns0='http://schemas.microsoft.com/vsto/samples' ");
447 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dataBinding", "xpath", "/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]");
448 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:dataBinding", "storeItemID", "{241A8A02-7FFD-488D-8827-63FBE74E8BC9}");
449 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:color", "val", "008000");
450 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w15:appearance", "val", "hidden");
451 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:alias", "val", "myalias");
452 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tag", "val", "mytag");
453 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:id", "val", "123");
454 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:tabIndex", "val", "-1");
455 assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:lock", "val", "sdtLocked");
458 CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorder)
460 // Given a document with a negative border distance:
461 createSwDoc();
462 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
463 SwDocShell* pDocShell = pTextDoc->GetDocShell();
464 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
465 pWrtShell->Insert("test");
466 uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"),
467 uno::UNO_QUERY);
468 xPageStyle->setPropertyValue("TopMargin", uno::Any(static_cast<sal_Int32>(501)));
469 table::BorderLine2 aBorder;
470 aBorder.LineWidth = 159;
471 aBorder.OuterLineWidth = 159;
472 xPageStyle->setPropertyValue("TopBorder", uno::Any(aBorder));
473 sal_Int32 nTopBorderDistance = -646;
474 xPageStyle->setPropertyValue("TopBorderDistance", uno::Any(nTopBorderDistance));
476 // When exporting to DOCX:
477 save("Office Open XML Text");
479 // Then make sure that the page edge -> border space is correct:
480 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
481 assertXPath(pXmlDoc, "//w:pgMar", "top", "284");
482 assertXPath(pXmlDoc, "//w:pgBorders/w:top", "sz", "36");
483 // Without the fix in place, this test would have failed with:
484 // - Expected: 28
485 // - Actual : 0
486 // i.e. editeng::BorderDistancesToWord() mis-handled negative border distances.
487 assertXPath(pXmlDoc, "//w:pgBorders/w:top", "space", "28");
490 CPPUNIT_TEST_FIXTURE(Test, testTdf148494)
492 loadAndSave("tdf148494.docx");
494 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
496 // Without the fix in place, this test would have failed with
497 // - Expected: MACROBUTTON AllCaps Hello World
498 // - Actual : MACROBUTTONAllCaps Hello World
499 assertXPathContent(pXmlDoc, "/w:document/w:body/w:p/w:r[3]/w:instrText", " MACROBUTTON AllCaps Hello World ");
502 DECLARE_OOXMLEXPORT_TEST(testTdf137466, "tdf137466.docx")
504 if (!isExported())
505 return; // initial import, no further checks
506 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
508 // Ensure that we have <w:placeholder><w:docPart v:val="xxxx"/></w:placeholder>
509 OUString sDocPart = getXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w:placeholder/w:docPart", "val");
510 CPPUNIT_ASSERT_EQUAL(OUString("DefaultPlaceholder_-1854013440"), sDocPart);
512 // Ensure that we have <w15:color v:val="xxxx"/>
513 OUString sColor = getXPath(pXmlDoc, "/w:document/w:body/w:p/w:sdt/w:sdtPr/w15:color", "val");
514 CPPUNIT_ASSERT_EQUAL(OUString("FF0000"), sColor);
517 DECLARE_OOXMLEXPORT_TEST(testParaListRightIndent, "testParaListRightIndent.docx")
519 CPPUNIT_ASSERT_EQUAL(1, getPages());
521 CPPUNIT_ASSERT_EQUAL(sal_Int32(2000), getProperty<sal_Int32>(getParagraph(1), "ParaRightMargin"));
522 CPPUNIT_ASSERT_EQUAL(sal_Int32(5001), getProperty<sal_Int32>(getParagraph(2), "ParaRightMargin"));
525 CPPUNIT_TEST_FIXTURE(Test, testDontAddNewStyles)
527 // Given a document that lacks builtin styles, and addition of them is disabled:
529 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
530 comphelper::ConfigurationChanges::create());
531 officecfg::Office::Common::Load::DisableBuiltinStyles::set(true, pBatch);
532 pBatch->commit();
534 comphelper::ScopeGuard g([] {
535 std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
536 comphelper::ConfigurationChanges::create());
537 officecfg::Office::Common::Load::DisableBuiltinStyles::set(false, pBatch);
538 pBatch->commit();
541 // When saving that document:
542 loadAndSave("dont-add-new-styles.docx");
544 // Then make sure that export doesn't have additional styles, Caption was one of them:
545 xmlDocUniquePtr pXmlDoc = parseExport("word/styles.xml");
546 // Without the accompanying fix in place, this test would have failed with:
547 // - Expected: 0
548 // - Actual : 1
549 // i.e. builtin styles were added to the export result, even if we opted out.
550 assertXPath(pXmlDoc, "/w:styles/w:style[@w:styleId='Caption']", 0);
553 DECLARE_OOXMLEXPORT_TEST(TestWPGZOrder, "testWPGZOrder.docx")
555 // Check if the load failed.
556 CPPUNIT_ASSERT(mxComponent);
558 // Get the WPG
559 uno::Reference<drawing::XShapes> xGroup(getShape(1), uno::UNO_QUERY_THROW);
560 uno::Reference<beans::XPropertySet> xGroupProperties(xGroup, uno::UNO_QUERY_THROW);
562 // Initialize a queue for subgroups
563 std::queue<uno::Reference<drawing::XShapes>> xGroupList;
564 xGroupList.push(xGroup);
566 // Every textbox shall be visible.
567 while (xGroupList.size())
569 // Get the first group
570 xGroup = xGroupList.front();
571 xGroupList.pop();
572 for (sal_Int32 i = 0; i < xGroup->getCount(); ++i)
574 // Get the child shape
575 uno::Reference<beans::XPropertySet> xChildShapeProperties(xGroup->getByIndex(i),
576 uno::UNO_QUERY_THROW);
577 // Check for textbox
578 if (!xChildShapeProperties->getPropertyValue("TextBox").get<bool>())
580 // Is this a Group Shape? Put it into the queue.
581 uno::Reference<drawing::XShapes> xInnerGroup(xGroup->getByIndex(i), uno::UNO_QUERY);
582 if (xInnerGroup)
583 xGroupList.push(xInnerGroup);
584 continue;
587 // Get the textbox properties
588 uno::Reference<beans::XPropertySet> xTextBoxFrameProperties(
589 xChildShapeProperties->getPropertyValue("TextBoxContent"), uno::UNO_QUERY_THROW);
591 // Assert that the textbox ZOrder greater than the groupshape
592 CPPUNIT_ASSERT_GREATER(xGroupProperties->getPropertyValue("ZOrder").get<long>(),
593 xTextBoxFrameProperties->getPropertyValue("ZOrder").get<long>());
594 // Before the fix, this failed because that was less, and the textboxes were covered.
600 CPPUNIT_TEST_FIXTURE(Test, testTdf148720)
602 loadAndReload("tdf148720.odt");
603 const auto& pLayout = parseLayoutDump();
605 const OString sShapeXPaths[] =
607 OString("/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObjGroup/SdrObjList/SdrObject[1]"),
608 OString("/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObjGroup/SdrObjList/SdrObjGroup/SdrObjList/SdrObjGroup/SdrObjList/SdrObject[1]"),
609 OString("/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObjGroup/SdrObjList/SdrObjGroup/SdrObjList/SdrObjGroup/SdrObjList/SdrObject[2]"),
610 OString("/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObjGroup/SdrObjList/SdrObject[2]")
613 const OString sTextXPaths[] =
615 OString("/root/page/body/txt/anchored/fly[1]/infos/bounds"),
616 OString("/root/page/body/txt/anchored/fly[2]/infos/bounds"),
617 OString("/root/page/body/txt/anchored/fly[3]/infos/bounds"),
618 OString("/root/page/body/txt/anchored/fly[4]/infos/bounds")
621 const OString sAttribs[] =
623 OString("left"),
624 OString("top"),
625 OString("width"),
626 OString("height")
629 for (sal_Int32 i = 0; i < 4; ++i)
631 OUString aShapeVals[4];
632 int aTextVals[4] = {0, 0, 0, 0};
634 const auto aOutRect = getXPath(pLayout, sShapeXPaths[i], "aOutRect");
636 sal_uInt16 nCommaPos[4] = {0, 0, 0, 0};
637 nCommaPos[1] = aOutRect.indexOf(",");
638 nCommaPos[2] = aOutRect.indexOf(",", nCommaPos[1] + 1);
639 nCommaPos[3] = aOutRect.indexOf(",", nCommaPos[2] + 1);
642 aShapeVals[0] = aOutRect.copy(nCommaPos[0], nCommaPos[1] - nCommaPos[0]);
643 aShapeVals[1] = aOutRect.copy(nCommaPos[1] + 2, nCommaPos[2] - nCommaPos[1] - 2);
644 aShapeVals[2] = aOutRect.copy(nCommaPos[2] + 2, nCommaPos[3] - nCommaPos[2] - 2);
645 aShapeVals[3] = aOutRect.copy(nCommaPos[3] + 2, aOutRect.getLength() - nCommaPos[3] - 2);
647 for (int ii = 0; ii < 4; ++ii)
649 aTextVals[ii] = getXPath(pLayout, sTextXPaths[i], sAttribs[ii]).toInt32();
652 tools::Rectangle ShapeArea(Point(aShapeVals[0].toInt32(), aShapeVals[1].toInt32()), Size(aShapeVals[2].toInt32() + 5, aShapeVals[3].toInt32() + 5));
654 tools::Rectangle TextArea(Point(aTextVals[0], aTextVals[1]), Size(aTextVals[2], aTextVals[3]));
656 CPPUNIT_ASSERT(ShapeArea.Contains(TextArea));
660 DECLARE_OOXMLEXPORT_TEST(testTdf126287, "tdf126287.docx")
662 CPPUNIT_ASSERT_EQUAL(2, getPages());
665 DECLARE_OOXMLEXPORT_TEST(testTdf123642_BookmarkAtDocEnd, "tdf123642.docx")
667 // get bookmark interface
668 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
669 uno::Reference<container::XIndexAccess> xBookmarksByIdx(xBookmarksSupplier->getBookmarks(), uno::UNO_QUERY);
670 uno::Reference<container::XNameAccess> xBookmarksByName = xBookmarksSupplier->getBookmarks();
672 // check: we have 1 bookmark (previously there were 0)
673 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), xBookmarksByIdx->getCount());
674 CPPUNIT_ASSERT(xBookmarksByName->hasByName("Bookmark1"));
676 // and it is really in exported DOCX (let's ensure)
677 if (!isExported())
678 return; // initial import, no further checks
679 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
681 CPPUNIT_ASSERT_EQUAL(OUString("Bookmark1"), getXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:bookmarkStart[1]", "name"));
684 DECLARE_OOXMLEXPORT_TEST(testTdf148361, "tdf148361.docx")
686 if (isExported())
688 // Block SDT is turned into run SDT on export, so the next import will have this as content
689 // control, not as a field.
690 OUString aActual = getParagraph(1)->getString();
691 // This was "itadmin".
692 CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), aActual);
694 else
696 // Refresh fields and ensure cross-reference to numbered para is okay
697 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
698 uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
700 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
701 CPPUNIT_ASSERT(xFields->hasMoreElements());
703 uno::Reference<text::XTextField> xTextField1(xFields->nextElement(), uno::UNO_QUERY);
704 CPPUNIT_ASSERT_EQUAL(OUString("itadmin"), xTextField1->getPresentation(false));
707 OUString aActual = getParagraph(2)->getString();
708 // This was "itadmin".
709 CPPUNIT_ASSERT_EQUAL(OUString("[Type text]"), aActual);
712 DECLARE_OOXMLEXPORT_TEST(testTdf153082_semicolon, "custom-styles-TOC-semicolon.docx")
714 uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY);
715 uno::Reference<container::XIndexAccess> xIndexes = xIndexSupplier->getDocumentIndexes();
716 uno::Reference<text::XDocumentIndex> xTOC(xIndexes->getByIndex(0), uno::UNO_QUERY);
717 // check styles
718 uno::Reference<container::XIndexAccess> xParaStyles =
719 getProperty<uno::Reference<container::XIndexAccess>>(xTOC, "LevelParagraphStyles");
720 uno::Sequence<OUString> styles;
721 xParaStyles->getByIndex(0) >>= styles;
722 CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{}, styles);
723 xParaStyles->getByIndex(1) >>= styles;
724 CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{}, styles);
725 xParaStyles->getByIndex(2) >>= styles;
726 // the first one is built-in Word style "Intense Quote" that was localised DE "Intensives Zitat" in the file
727 CPPUNIT_ASSERT_EQUAL((uno::Sequence<OUString>{"Intensives Zitat", "Custom1", "_MyStyle0"}), styles);
728 xTOC->update();
729 OUString const tocContent(xTOC->getAnchor()->getString());
730 CPPUNIT_ASSERT(tocContent.startsWith("Table of Contents"));
731 CPPUNIT_ASSERT(tocContent.indexOf("Lorem ipsum dolor sit amet, consectetuer adipiscing elit.") != -1);
732 CPPUNIT_ASSERT(tocContent.indexOf("Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.") != -1);
733 CPPUNIT_ASSERT(tocContent.indexOf("Proin pharetra nonummy pede. Mauris et orci.") != -1);
736 DECLARE_OOXMLEXPORT_TEST(testTdf153082_comma, "custom-styles-TOC-comma.docx")
738 uno::Reference<text::XDocumentIndexesSupplier> xIndexSupplier(mxComponent, uno::UNO_QUERY);
739 uno::Reference<container::XIndexAccess> xIndexes = xIndexSupplier->getDocumentIndexes();
740 uno::Reference<text::XDocumentIndex> xTOC(xIndexes->getByIndex(0), uno::UNO_QUERY);
741 // check styles
742 uno::Reference<container::XIndexAccess> xParaStyles =
743 getProperty<uno::Reference<container::XIndexAccess>>(xTOC, "LevelParagraphStyles");
744 uno::Sequence<OUString> styles;
745 xParaStyles->getByIndex(0) >>= styles;
746 CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{"_MyStyle0"}, styles);
747 xParaStyles->getByIndex(1) >>= styles;
748 CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{"Custom1"}, styles);
749 xParaStyles->getByIndex(2) >>= styles;
750 // the first one is built-in Word style "Intense Quote" that was localised DE "Intensives Zitat" in the file
751 CPPUNIT_ASSERT_EQUAL(uno::Sequence<OUString>{"Intensives Zitat"}, styles);
752 xTOC->update();
753 OUString const tocContent(xTOC->getAnchor()->getString());
754 CPPUNIT_ASSERT(tocContent.startsWith("Table of Contents"));
755 CPPUNIT_ASSERT(tocContent.indexOf("Lorem ipsum dolor sit amet, consectetuer adipiscing elit.") != -1);
756 CPPUNIT_ASSERT(tocContent.indexOf("Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit amet commodo magna eros quis urna.") != -1);
757 CPPUNIT_ASSERT(tocContent.indexOf("Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.") != -1);
760 DECLARE_OOXMLEXPORT_TEST(testTdf142407, "tdf142407.docx")
762 uno::Reference<container::XNameAccess> xPageStyles = getStyles("PageStyles");
763 uno::Reference<beans::XPropertySet> xPageStyle(xPageStyles->getByName("Standard"), uno::UNO_QUERY);
764 sal_Int16 nGridLines;
765 xPageStyle->getPropertyValue("GridLines") >>= nGridLines;
766 CPPUNIT_ASSERT_EQUAL( sal_Int16(36), nGridLines); // was 23, left large space before text.
769 DECLARE_OOXMLEXPORT_TEST(testWPGBodyPr, "WPGbodyPr.docx")
771 // Is load successful?
772 CPPUNIT_ASSERT(mxComponent);
774 // There are a WPG shape and a picture
775 CPPUNIT_ASSERT_EQUAL(2, getShapes());
777 // Get the WPG shape
778 uno::Reference<drawing::XShapes> xGroup(getShape(1), uno::UNO_QUERY);
779 // And the embed WPG
780 uno::Reference<drawing::XShapes> xEmbedGroup(xGroup->getByIndex(1), uno::UNO_QUERY);
782 // Get the properties of the shapes
783 uno::Reference<beans::XPropertySet> xOuterShape(xGroup->getByIndex(0), uno::UNO_QUERY);
784 uno::Reference<beans::XPropertySet> xMiddleShape(xEmbedGroup->getByIndex(0), uno::UNO_QUERY);
785 uno::Reference<beans::XPropertySet> xInnerShape(xEmbedGroup->getByIndex(1), uno::UNO_QUERY);
787 // Get the properties of the textboxes too
788 uno::Reference<beans::XPropertySet> xOuterTextBox(
789 xOuterShape->getPropertyValue("TextBoxContent"), uno::UNO_QUERY);
790 uno::Reference<beans::XPropertySet> xMiddleTextBox(
791 xMiddleShape->getPropertyValue("TextBoxContent"), uno::UNO_QUERY);
792 uno::Reference<beans::XPropertySet> xInnerTextBox(
793 xInnerShape->getPropertyValue("TextBoxContent"), uno::UNO_QUERY);
795 // Check the alignments
796 CPPUNIT_ASSERT_EQUAL(css::drawing::TextVerticalAdjust::TextVerticalAdjust_TOP,
797 xOuterTextBox->getPropertyValue("TextVerticalAdjust")
798 .get<css::drawing::TextVerticalAdjust>());
799 CPPUNIT_ASSERT_EQUAL(css::drawing::TextVerticalAdjust::TextVerticalAdjust_TOP,
800 xMiddleTextBox->getPropertyValue("TextVerticalAdjust")
801 .get<css::drawing::TextVerticalAdjust>());
802 CPPUNIT_ASSERT_EQUAL(css::drawing::TextVerticalAdjust::TextVerticalAdjust_CENTER,
803 xInnerTextBox->getPropertyValue("TextVerticalAdjust")
804 .get<css::drawing::TextVerticalAdjust>());
806 // Check the inset margins, all were 0 before the fix
807 CPPUNIT_ASSERT_EQUAL(sal_Int32(499),
808 xInnerShape->getPropertyValue("TextLowerDistance").get<sal_Int32>());
809 CPPUNIT_ASSERT_EQUAL(sal_Int32(499),
810 xInnerShape->getPropertyValue("TextUpperDistance").get<sal_Int32>());
811 CPPUNIT_ASSERT_EQUAL(sal_Int32(1000),
812 xInnerShape->getPropertyValue("TextLeftDistance").get<sal_Int32>());
813 CPPUNIT_ASSERT_EQUAL(sal_Int32(254),
814 xInnerShape->getPropertyValue("TextRightDistance").get<sal_Int32>());
817 DECLARE_OOXMLEXPORT_TEST(testTdf146851_1, "tdf146851_1.docx")
819 uno::Reference<beans::XPropertySet> xPara;
821 xPara.set(getParagraph(1, "qwerty"), uno::UNO_QUERY);
822 CPPUNIT_ASSERT_EQUAL(OUString("1."), getProperty<OUString>(xPara, "ListLabelString"));
824 xPara.set(getParagraph(2, "asdfg"), uno::UNO_QUERY);
825 CPPUNIT_ASSERT_EQUAL(OUString("1/"), getProperty<OUString>(xPara, "ListLabelString"));
828 DECLARE_OOXMLEXPORT_TEST(testTdf146851_2, "tdf146851_2.docx")
830 // Ensure numbering on second para
831 uno::Reference<beans::XPropertySet> xPara;
832 xPara.set(getParagraph(2, "."), uno::UNO_QUERY);
833 CPPUNIT_ASSERT_EQUAL(OUString("Schedule"), getProperty<OUString>(xPara, "ListLabelString"));
835 // Refresh fields and ensure cross-reference to numbered para is okay
836 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
837 uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
839 uno::Reference<util::XRefreshable>(xFieldsAccess, uno::UNO_QUERY_THROW)->refresh();
841 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
842 CPPUNIT_ASSERT(xFields->hasMoreElements());
843 uno::Reference<text::XTextField> xTextField(xFields->nextElement(), uno::UNO_QUERY);
844 CPPUNIT_ASSERT_EQUAL(OUString("Schedule"), xTextField->getPresentation(false));
847 DECLARE_OOXMLEXPORT_TEST(testTdf148052, "tdf148052.docx")
849 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
850 uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
852 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
853 CPPUNIT_ASSERT(xFields->hasMoreElements());
855 uno::Reference<text::XTextField> xTextField(xFields->nextElement(), uno::UNO_QUERY);
857 // Without the fix in place, this test would have failed with
858 // - Expected: 14. Aug 18
859 // - Actual : 11. Apr 22
860 CPPUNIT_ASSERT_EQUAL(OUString("14. Aug 18"), xTextField->getPresentation(false));
863 DECLARE_OOXMLEXPORT_TEST(testTdf148111, "tdf148111.docx")
865 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
866 uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
868 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
869 std::vector<OUString> aExpectedValues = {
870 // These field values are NOT in order in document: getTextFields did provide
871 // fields in a strange but fixed order
872 "Title", "Placeholder", "Placeholder", "Placeholder",
873 "Placeholder", "Placeholder", "Placeholder", "Placeholder",
874 "Placeholder", "Placeholder", "Placeholder", "Placeholder",
875 "Placeholder", "Placeholder", "Placeholder", "Placeholder",
876 "Placeholder", "Title", "Title", "Title",
877 "Title", "Title", "Title", "Title"
880 sal_uInt16 nIndex = 0;
881 while (xFields->hasMoreElements())
883 uno::Reference<text::XTextField> xTextField(xFields->nextElement(), uno::UNO_QUERY);
884 CPPUNIT_ASSERT_EQUAL(aExpectedValues[nIndex++], xTextField->getPresentation(false));
887 // No more fields
888 CPPUNIT_ASSERT(!xFields->hasMoreElements());
890 if (!isExported())
891 return;
892 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
893 // ShowingPlaceholder should be off for 0, false and "on". (This was 21 before the fix)
894 assertXPath(pXmlDoc,"//w:p/w:sdt/w:sdtPr/w:showingPlcHdr", 12);
897 DECLARE_OOXMLEXPORT_TEST(TestTdf73499, "tdf73499.docx")
899 // Ensure, the bugdoc is opened
900 CPPUNIT_ASSERT(mxComponent);
901 // Get the groupshape
902 uno::Reference<drawing::XShapes> xGroup(getShape(1), uno::UNO_QUERY_THROW);
904 // Get the textboxes of the groupshape
905 uno::Reference<text::XText> xTextBox1(xGroup->getByIndex(0), uno::UNO_QUERY_THROW);
906 uno::Reference<text::XText> xTextBox2(xGroup->getByIndex(1), uno::UNO_QUERY_THROW);
908 // Get the properties of the textboxes
909 uno::Reference<beans::XPropertySet> xTextBox1Properties(xTextBox1, uno::UNO_QUERY_THROW);
910 uno::Reference<beans::XPropertySet> xTextBox2Properties(xTextBox2, uno::UNO_QUERY_THROW);
912 // Get the name of the textboxes
913 uno::Reference<container::XNamed> xTextBox1Name(xTextBox1, uno::UNO_QUERY_THROW);
914 uno::Reference<container::XNamed> xTextBox2Name(xTextBox2, uno::UNO_QUERY_THROW);
916 // Check for the links, before the fix that were missing
917 CPPUNIT_ASSERT_EQUAL_MESSAGE(
918 "Link name missing!", xTextBox2Name->getName(),
919 xTextBox1Properties->getPropertyValue("ChainNextName").get<OUString>());
920 CPPUNIT_ASSERT_EQUAL_MESSAGE(
921 "Link name missing!", xTextBox1Name->getName(),
922 xTextBox2Properties->getPropertyValue("ChainPrevName").get<OUString>());
925 DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx")
927 if (!isExported())
928 return; // initial import, no further checks
929 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
931 // Ensure that we have <w:text w:multiLine="1"/>
932 CPPUNIT_ASSERT_EQUAL(OUString("1"), getXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:sdt/w:sdtPr/w:text", "multiLine"));
934 // Ensure that we have <w:text w:multiLine="0"/>
935 CPPUNIT_ASSERT_EQUAL(OUString("0"), getXPath(pXmlDoc, "/w:document/w:body/w:p[2]/w:sdt/w:sdtPr/w:text", "multiLine"));
937 // Ensure that we have <w:text/>
938 assertXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:sdt/w:sdtPr/w:text");
940 // Ensure that we have no <w:text/> (not quite correct case, but to ensure import/export are okay)
941 assertXPath(pXmlDoc, "/w:document/w:body/w:p[4]/w:sdt/w:sdtPr/w:text", 0);
944 DECLARE_OOXMLEXPORT_TEST(testTdf139948, "tdf139948.docx")
946 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
947 getProperty<table::BorderLine2>(getParagraph(1, "No border"), "TopBorder").LineWidth);
948 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
949 getProperty<table::BorderLine2>(getParagraph(2, "Border below"), "TopBorder").LineWidth);
950 CPPUNIT_ASSERT_EQUAL(sal_uInt32(88),
951 getProperty<table::BorderLine2>(getParagraph(3, "Borders below and above"), "TopBorder").LineWidth);
952 CPPUNIT_ASSERT_EQUAL(sal_uInt32(88),
953 getProperty<table::BorderLine2>(getParagraph(4, "Border above"), "TopBorder").LineWidth);
954 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
955 getProperty<table::BorderLine2>(getParagraph(5, "No border"), "TopBorder").LineWidth);
958 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
959 getProperty<table::BorderLine2>(getParagraph(1), "BottomBorder").LineWidth);
960 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
961 getProperty<table::BorderLine2>(getParagraph(2), "BottomBorder").LineWidth);
962 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
963 getProperty<table::BorderLine2>(getParagraph(3), "BottomBorder").LineWidth);
964 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
965 getProperty<table::BorderLine2>(getParagraph(4), "BottomBorder").LineWidth);
966 CPPUNIT_ASSERT_EQUAL(sal_uInt32(0),
967 getProperty<table::BorderLine2>(getParagraph(5), "BottomBorder").LineWidth);
970 DECLARE_OOXMLEXPORT_TEST(testTdf144563, "tdf144563.docx")
972 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
973 uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
975 // Refresh all cross-reference fields
976 uno::Reference<util::XRefreshable>(xFieldsAccess, uno::UNO_QUERY_THROW)->refresh();
978 // Verify values
979 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
981 std::vector<OUString> aExpectedValues = {
982 // These field values are NOT in order in document: getTextFields did provide
983 // fields in a strange but fixed order
984 "1", "1", "1", "1", "1/", "1/", "1/", "1)", "1)", "1)", "1.)",
985 "1.)", "1.)", "1..", "1..", "1..", "1.", "1.", "1.", "1", "1"
988 sal_uInt16 nIndex = 0;
989 while (xFields->hasMoreElements())
991 uno::Reference<text::XTextField> xTextField(xFields->nextElement(), uno::UNO_QUERY);
992 CPPUNIT_ASSERT_EQUAL(aExpectedValues[nIndex++], xTextField->getPresentation(false));
996 // broken test document?
997 #if !defined(_WIN32)
998 CPPUNIT_TEST_FIXTURE(Test, testTdf146955)
1000 loadAndReload("tdf146955.odt");
1001 // import of a (broken?) DOCX export with dozens of frames raised a SAX exception,
1002 // when the code tried to access to a non-existent footnote
1003 uno::Reference<text::XFootnotesSupplier> xNotes(mxComponent, uno::UNO_QUERY);
1004 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xNotes->getFootnotes()->getCount());
1006 #endif
1008 CPPUNIT_TEST_FIXTURE(Test, testTdf144668)
1010 loadAndReload("tdf144668.odt");
1011 uno::Reference<beans::XPropertySet> xPara1(getParagraph(1, u"level1"), uno::UNO_QUERY);
1012 CPPUNIT_ASSERT_EQUAL(OUString("[0001]"), getProperty<OUString>(xPara1, "ListLabelString"));
1014 uno::Reference<beans::XPropertySet> xPara2(getParagraph(2, u"level2"), uno::UNO_QUERY);
1015 CPPUNIT_ASSERT_EQUAL(OUString("[001]"), getProperty<OUString>(xPara2, "ListLabelString"));
1018 DECLARE_OOXMLEXPORT_TEST(testTdf148455_1, "tdf148455_1.docx")
1020 uno::Reference<beans::XPropertySet> xPara2(getParagraph(3, u"1.1.1"), uno::UNO_QUERY);
1021 CPPUNIT_ASSERT_EQUAL(OUString("1.1.1."), getProperty<OUString>(xPara2, "ListLabelString"));
1024 DECLARE_OOXMLEXPORT_TEST(testTdf148455_2, "tdf148455_2.docx")
1026 if (!isExported())
1027 return; // initial import, no further checks
1028 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
1030 // Find list id for restarted list
1031 sal_Int32 nListId = getXPath(pXmlDoc, "/w:document/w:body/w:p[3]/w:pPr/w:numPr/w:numId", "val").toInt32();
1033 xmlDocUniquePtr pNumberingDoc = parseExport("word/numbering.xml");
1035 // Ensure we have empty lvlOverride for levels 0 - 1
1036 assertXPath(pNumberingDoc, "/w:numbering/w:num[@w:numId='" + OString::number(nListId) +"']/w:lvlOverride[@w:ilvl='0']");
1037 assertXPath(pNumberingDoc, "/w:numbering/w:num[@w:numId='" + OString::number(nListId) +"']/w:lvlOverride[@w:ilvl='1']");
1038 // And normal override for level 2
1039 getXPath(pNumberingDoc, "/w:numbering/w:num[@w:numId='" + OString::number(nListId) +"']/w:lvlOverride[@w:ilvl='2']/w:startOverride", "val");
1042 CPPUNIT_TEST_FIXTURE(Test, testTdf147978enhancedPathABVW)
1044 createSwDoc("tdf147978_enhancedPath_commandABVW.odt");
1045 saveAndReload("Office Open XML Text");
1046 // Make sure the new implemented export for commands A,B,V and W use the correct arc between
1047 // the given two points, here the short one.
1048 for (sal_Int16 i = 1 ; i <= 4; ++i)
1050 uno::Reference<drawing::XShape> xShape = getShape(i);
1051 CPPUNIT_ASSERT_EQUAL(sal_Int32(506), getProperty<awt::Rectangle>(xShape, "BoundRect").Height);
1055 DECLARE_OOXMLEXPORT_TEST(testTdf148132, "tdf148132.docx")
1058 uno::Reference<text::XTextRange> xParagraph = getParagraph(1);
1059 auto xLevels = getProperty< uno::Reference<container::XIndexAccess> >(xParagraph, "NumberingRules");
1060 // Get level 2 char style
1061 comphelper::SequenceAsHashMap levelProps(xLevels->getByIndex(1));
1062 OUString aCharStyleName = levelProps["CharStyleName"].get<OUString>();
1063 // Ensure that numbering in this paragraph is 24pt bold italic
1064 // Previously it got overridden by paragraph properties and became 6pt, no bold, no italic
1065 uno::Reference<beans::XPropertySet> xStyle(getStyles("CharacterStyles")->getByName(aCharStyleName), uno::UNO_QUERY);
1066 CPPUNIT_ASSERT_EQUAL(24.f, getProperty<float>(xStyle, "CharHeight"));
1067 CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xStyle, "CharWeight"));
1068 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, getProperty<awt::FontSlant>(xStyle, "CharPosture"));
1070 // And do the same for second paragraph. Numbering should be identical
1072 uno::Reference<text::XTextRange> xParagraph = getParagraph(2);
1073 auto xLevels = getProperty< uno::Reference<container::XIndexAccess> >(xParagraph, "NumberingRules");
1074 comphelper::SequenceAsHashMap levelProps(xLevels->getByIndex(1));
1075 OUString aCharStyleName = levelProps["CharStyleName"].get<OUString>();
1077 uno::Reference<beans::XPropertySet> xStyle(getStyles("CharacterStyles")->getByName(aCharStyleName), uno::UNO_QUERY);
1078 CPPUNIT_ASSERT_EQUAL(24.f, getProperty<float>(xStyle, "CharHeight"));
1079 CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty<float>(xStyle, "CharWeight"));
1080 CPPUNIT_ASSERT_EQUAL(awt::FontSlant_ITALIC, getProperty<awt::FontSlant>(xStyle, "CharPosture"));
1084 DECLARE_OOXMLEXPORT_TEST(testTdf154481, "tdf154481.docx")
1086 CPPUNIT_ASSERT_EQUAL_MESSAGE("Missing pages!", 7, getPages());
1089 CPPUNIT_TEST_FIXTURE(Test, testTdf149200)
1091 loadAndSave("tdf149200.docx");
1092 CPPUNIT_ASSERT_EQUAL(1, getPages());
1093 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
1095 // Ensure there is no unexpected invalid structure <w14:textFill>
1096 // There is just one run property
1097 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "count(/w:document/w:body/w:p[1]/w:r[1]/w:rPr/*)");
1098 CPPUNIT_ASSERT(pXmlObj);
1099 CPPUNIT_ASSERT_EQUAL(double(1), pXmlObj->floatval);
1100 // And it is a color definition with themeColor
1101 CPPUNIT_ASSERT_EQUAL(OUString("dark1"), getXPath(pXmlDoc, "/w:document/w:body/w:p[1]/w:r[1]/w:rPr/w:color", "themeColor"));
1104 DECLARE_OOXMLEXPORT_TEST(testTdf149313, "tdf149313.docx")
1106 // only 2, but not 3 pages in document
1107 CPPUNIT_ASSERT_EQUAL(2, getPages());
1109 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1110 // And ensure that pages are with correct sections (have correct dimensions)
1111 CPPUNIT_ASSERT_EQUAL(sal_Int32(4989), getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32());
1112 CPPUNIT_ASSERT_EQUAL(sal_Int32(4989), getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "width").toInt32());
1113 CPPUNIT_ASSERT_EQUAL(sal_Int32(4989), getXPath(pXmlDoc, "/root/page[2]/infos/bounds", "height").toInt32());
1114 CPPUNIT_ASSERT_EQUAL(sal_Int32(8000), getXPath(pXmlDoc, "/root/page[2]/infos/bounds", "width").toInt32());
1117 DECLARE_OOXMLEXPORT_TEST(testTdf148360, "tdf148360.docx")
1119 const auto& pLayout = parseLayoutDump();
1121 // Ensure first element is a tab
1122 assertXPath(pLayout, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/child::*[1]", "type", "PortionType::TabLeft");
1123 // and only then goes content
1124 assertXPath(pLayout, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/child::*[2]", "type", "PortionType::Text");
1127 DECLARE_OOXMLEXPORT_TEST(testTdf135923, "tdf135923-min.docx")
1129 uno::Reference<text::XText> xShape(getShape(1), uno::UNO_QUERY);
1130 uno::Reference<text::XTextRange> xParagraph = getParagraphOfText(1, xShape);
1132 CPPUNIT_ASSERT_EQUAL(COL_WHITE, getProperty<Color>(getRun(xParagraph, 1), "CharColor"));
1133 CPPUNIT_ASSERT_EQUAL(COL_BLACK, getProperty<Color>(getRun(xParagraph, 2), "CharColor"));
1136 DECLARE_OOXMLEXPORT_TEST(testTdf148273_sectionBulletFormatLeak, "tdf148273_sectionBulletFormatLeak.docx")
1138 // get a paragraph with bullet point after section break
1139 uno::Reference<text::XTextRange> xParagraph = getParagraph(4);
1140 uno::Reference<beans::XPropertySet> xProps(xParagraph, uno::UNO_QUERY);
1142 // Make sure that the bullet has no ListAutoFormat inherited from
1143 // the empty paragraph before the section break
1144 // Without the accompanying fix in place, this test would have failed with:
1145 // - Expected: 0
1146 // - Actual : 1
1147 // i.e. empty paragraph formats from the first section leaked to the bullet's formatting
1148 uno::Any aValue = xProps->getPropertyValue("ListAutoFormat");
1149 CPPUNIT_ASSERT_EQUAL(false, aValue.hasValue());
1152 DECLARE_OOXMLEXPORT_TEST(testTdf149089, "tdf149089.docx")
1154 uno::Reference<container::XNameAccess> xPageStyles = getStyles("PageStyles");
1155 uno::Reference<beans::XPropertySet> xPageStyle(xPageStyles->getByName("Standard"), uno::UNO_QUERY);
1156 sal_Int16 nGridMode;
1157 xPageStyle->getPropertyValue("GridMode") >>= nGridMode;
1158 CPPUNIT_ASSERT_EQUAL( sal_Int16(text::TextGridMode::LINES), nGridMode); // was LINES_AND_CHARS
1161 CPPUNIT_TEST_FIXTURE(Test, testTdf139128)
1163 loadAndReload("tdf139128.odt");
1164 xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
1165 CPPUNIT_ASSERT(pXmlDoc);
1166 // Without the accompanying fix in place, this test would have failed with:
1167 // - Expected: 2
1168 // - Actual : 0
1169 // i.e. the line break was lost on export.
1170 assertXPath(pXmlDoc, "//w:br", 2);
1173 CPPUNIT_PLUGIN_IMPLEMENT();
1175 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */