Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / qa / core / unocore / unocore.cxx
blobcb6f52d0fdbb8edc03841e5daba4668b49947e2f
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 <com/sun/star/text/BibliographyDataType.hpp>
13 #include <com/sun/star/text/XTextAppend.hpp>
14 #include <com/sun/star/text/XTextFrame.hpp>
15 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
16 #include <com/sun/star/text/XDependentTextField.hpp>
17 #include <com/sun/star/document/XDocumentInsertable.hpp>
18 #include <com/sun/star/view/XSelectionSupplier.hpp>
19 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
21 #include <comphelper/propertyvalue.hxx>
22 #include <comphelper/sequenceashashmap.hxx>
23 #include <vcl/errinf.hxx>
24 #include <editeng/wghtitem.hxx>
26 #include <wrtsh.hxx>
27 #include <unotextrange.hxx>
28 #include <unotxdoc.hxx>
29 #include <docsh.hxx>
30 #include <ndtxt.hxx>
31 #include <textlinebreak.hxx>
32 #include <textcontentcontrol.hxx>
33 #include <frmmgr.hxx>
34 #include <fmtcntnt.hxx>
36 using namespace ::com::sun::star;
38 /// Covers sw/source/core/unocore/ fixes.
39 class SwCoreUnocoreTest : public SwModelTestBase
41 public:
42 SwCoreUnocoreTest()
43 : SwModelTestBase("/sw/qa/core/unocore/data/")
48 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testTdf119081)
50 // Load a doc with a nested table in it.
51 createSwDoc("tdf119081.odt");
52 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
53 CPPUNIT_ASSERT(pTextDoc);
54 SwDocShell* pDocShell = pTextDoc->GetDocShell();
55 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
57 // Enter outer A1.
58 pWrtShell->Down(/*bSelect=*/false, /*nCount=*/3);
59 // Enter inner A1.
60 pWrtShell->Right(SwCursorSkipMode::Cells, /*bSelect=*/false, /*nCount=*/1, /*bBasicCall=*/false,
61 /*bVisual=*/true);
62 // Enter outer B1.
63 pWrtShell->Down(/*bSelect=*/false, /*nCount=*/2);
65 SwDoc* pDoc = pDocShell->GetDoc();
66 SwPaM& rCursor = pWrtShell->GetCurrentShellCursor();
67 uno::Reference<text::XTextRange> xInsertPosition
68 = SwXTextRange::CreateXTextRange(*pDoc, *rCursor.GetPoint(), nullptr);
69 uno::Reference<text::XTextAppend> xTextAppend(xInsertPosition->getText(), uno::UNO_QUERY);
70 // Without the accompanying fix in place, this test would have failed with:
71 // An uncaught exception of type com.sun.star.uno.RuntimeException
72 xTextAppend->insertTextPortion("x", {}, xInsertPosition);
74 // Verify that the string is indeed inserted.
75 pWrtShell->Left(SwCursorSkipMode::Cells, /*bSelect=*/true, /*nCount=*/1, /*bBasicCall=*/false,
76 /*bVisual=*/true);
77 CPPUNIT_ASSERT_EQUAL(OUString("x"), pWrtShell->GetCurrentShellCursor().GetText());
80 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, flyAtParaAnchor)
82 createSwDoc();
83 uno::Reference<lang::XMultiServiceFactory> const xMSF(mxComponent, uno::UNO_QUERY_THROW);
84 uno::Reference<text::XTextDocument> const xTD(mxComponent, uno::UNO_QUERY_THROW);
85 uno::Reference<text::XTextFrame> const xTextFrame(
86 xMSF->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY_THROW);
87 uno::Reference<beans::XPropertySet> const xFrameProps(xTextFrame, uno::UNO_QUERY_THROW);
88 xFrameProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_PARAGRAPH));
89 auto const xText = xTD->getText();
90 auto const xTextCursor = xText->createTextCursor();
91 CPPUNIT_ASSERT(xTextCursor.is());
92 xText->insertTextContent(xTextCursor, xTextFrame, false);
93 auto const xAnchor = xTextFrame->getAnchor();
94 uno::Reference<text::XTextContent> const xFieldmark(
95 xMSF->createInstance("com.sun.star.text.Fieldmark"), uno::UNO_QUERY_THROW);
96 // this crashed because the anchor didn't have SwContentIndex
97 xText->insertTextContent(xAnchor, xFieldmark, false);
100 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testRtlGutter)
102 createSwDoc();
103 uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"),
104 uno::UNO_QUERY);
105 // Without the accompanying fix in place, this test would have failed with:
106 // - Unknown property: RtlGutter
107 auto bRtlGutter = getProperty<bool>(xPageStyle, "RtlGutter");
108 CPPUNIT_ASSERT(!bRtlGutter);
109 xPageStyle->setPropertyValue("RtlGutter", uno::Any(true));
110 bRtlGutter = getProperty<bool>(xPageStyle, "RtlGutter");
111 CPPUNIT_ASSERT(bRtlGutter);
114 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testBiblioLocalCopy)
116 // Given an empty document:
117 createSwDoc();
119 // When setting the LocalURL of a biblio field:
120 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
121 uno::Reference<beans::XPropertySet> xField(
122 xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY);
123 uno::Sequence<beans::PropertyValue> aFields = {
124 comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW),
125 comphelper::makePropertyValue("Identifier", OUString("ARJ00")),
126 comphelper::makePropertyValue("Author", OUString("Me")),
127 comphelper::makePropertyValue("Title", OUString("mytitle")),
128 comphelper::makePropertyValue("Year", OUString("2020")),
129 comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf")),
130 comphelper::makePropertyValue("LocalURL", OUString("file:///home/me/test.pdf")),
132 xField->setPropertyValue("Fields", uno::Any(aFields));
133 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
134 uno::Reference<text::XText> xText = xTextDocument->getText();
135 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
136 uno::Reference<text::XTextContent> xContent(xField, uno::UNO_QUERY);
137 xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false);
139 // Then make sure we get that LocalURL back:
140 comphelper::SequenceAsHashMap aMap(xField->getPropertyValue("Fields"));
141 // Without the accompanying fix in place, this test would have failed, there was no LocalURL key
142 // in the map.
143 CPPUNIT_ASSERT(aMap.find("LocalURL") != aMap.end());
144 auto aActual = aMap["LocalURL"].get<OUString>();
145 CPPUNIT_ASSERT_EQUAL(OUString("file:///home/me/test.pdf"), aActual);
148 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testLinkedStyles)
150 // Given an empty document:
151 createSwDoc();
153 // When defining a linked style for a para style:
154 uno::Reference<container::XNameAccess> xParaStyles = getStyles("ParagraphStyles");
155 uno::Reference<beans::XPropertySet> xParaStyle(xParaStyles->getByName("Caption"),
156 uno::UNO_QUERY);
157 CPPUNIT_ASSERT_EQUAL(OUString(), getProperty<OUString>(xParaStyle, "LinkStyle"));
158 xParaStyle->setPropertyValue("LinkStyle", uno::Any(OUString("Emphasis")));
159 // Then make sure we get the linked char style back:
160 CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty<OUString>(xParaStyle, "LinkStyle"));
162 // When defining a linked style for a char style:
163 uno::Reference<container::XNameAccess> xCharStyles = getStyles("CharacterStyles");
164 uno::Reference<beans::XPropertySet> xCharStyle(xCharStyles->getByName("Emphasis"),
165 uno::UNO_QUERY);
166 CPPUNIT_ASSERT_EQUAL(OUString(), getProperty<OUString>(xCharStyle, "LinkStyle"));
167 xCharStyle->setPropertyValue("LinkStyle", uno::Any(OUString("Caption")));
168 // Then make sure we get the linked para style back:
169 CPPUNIT_ASSERT_EQUAL(OUString("Caption"), getProperty<OUString>(xCharStyle, "LinkStyle"));
172 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testViewCursorTextFrame)
174 // Given a document with a graphic and holding a reference to that graphic frame:
175 createSwDoc();
176 uno::Sequence<beans::PropertyValue> aInsertArgs
177 = { comphelper::makePropertyValue("FileName", createFileURL(u"graphic.png")) };
178 dispatchCommand(mxComponent, ".uno:InsertGraphic", aInsertArgs);
179 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
180 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
181 xModel->getCurrentController(), uno::UNO_QUERY);
182 uno::Reference<beans::XPropertySet> xViewCursor(xTextViewCursorSupplier->getViewCursor(),
183 uno::UNO_QUERY);
184 uno::Reference<beans::XPropertySet> xFrame;
185 xViewCursor->getPropertyValue("TextFrame") >>= xFrame;
187 // When saving to ODT, then make sure the store doesn't fail:
188 uno::Reference<frame::XStorable> xStorable(xModel, uno::UNO_QUERY);
189 uno::Sequence<beans::PropertyValue> aStoreArgs
190 = { comphelper::makePropertyValue("FilterName", OUString("writer8")) };
191 // Without the accompanying fix in place, this test would have failed with:
192 // uno.RuntimeException: "SwXParagraph: disposed or invalid ..."
193 xStorable->storeToURL(maTempFile.GetURL(), aStoreArgs);
196 /// Fails the test if an error popup would be presented.
197 static void BasicDisplayErrorHandler(const OUString& /*rErr*/, const OUString& /*rAction*/)
199 CPPUNIT_ASSERT(false);
202 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testBrokenEmbeddedObject)
204 // Given a document with a broken embedded object (the XML markup is not well-formed):
205 createSwDoc("broken-embedded-object.odt");
206 uno::Reference<text::XTextEmbeddedObjectsSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
207 uno::Reference<container::XIndexAccess> xObjects(xSupplier->getEmbeddedObjects(),
208 uno::UNO_QUERY);
209 uno::Reference<beans::XPropertySet> xObject(xObjects->getByIndex(0), uno::UNO_QUERY);
210 uno::Reference<lang::XServiceInfo> xEmbeddedObject;
211 // Get the property first, which initializes Draw, which would overwrite our error handler.
212 xObject->getPropertyValue("EmbeddedObject") >>= xEmbeddedObject;
213 ErrorRegistry::RegisterDisplay(&BasicDisplayErrorHandler);
215 // When trying to load that embedded object:
216 xObject->getPropertyValue("EmbeddedObject") >>= xEmbeddedObject;
218 // Then make sure we get a non-empty reference and an error popup it not shown:
219 CPPUNIT_ASSERT(xEmbeddedObject.is());
220 // Without the accompanying fix in place, we got this reference, but first an error popup was
221 // shown to the user.
222 CPPUNIT_ASSERT(
223 xEmbeddedObject->supportsService("com.sun.star.comp.embed.OCommonEmbeddedObject"));
226 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testLineBreakInsert)
228 // Given an empty document:
229 createSwDoc();
230 SwDoc* pDoc = getSwDoc();
232 // When inserting a line-break with properties:
233 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
234 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
235 uno::Reference<text::XTextContent> xLineBreak(
236 xMSF->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY);
237 uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
238 auto eClear = static_cast<sal_Int16>(SwLineBreakClear::ALL);
239 xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear));
240 uno::Reference<text::XText> xText = xTextDocument->getText();
241 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
242 xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false);
244 // Then make sure that both the line break and its matching text attribute is inserted:
245 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
246 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetPointNode().GetIndex();
247 SwTextNode* pTextNode = pDoc->GetNodes()[nIndex]->GetTextNode();
248 // Without the accompanying fix in place, this test would have failed with:
249 // - Expected: "\n" (newline)
250 // - Actual : "" (empty string)
251 // i.e. SwXLineBreak::attach() did not insert the newline + its text attribute.
252 CPPUNIT_ASSERT_EQUAL(OUString("\n"), pTextNode->GetText());
253 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_LINEBREAK);
254 CPPUNIT_ASSERT(pAttr);
255 auto pTextLineBreak = static_cast<SwTextLineBreak*>(pAttr);
256 auto& rFormatLineBreak = static_cast<SwFormatLineBreak&>(pTextLineBreak->GetAttr());
257 CPPUNIT_ASSERT_EQUAL(SwLineBreakClear::ALL, rFormatLineBreak.GetValue());
260 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testLineBreakTextPortionEnum)
262 // Given a document with a clearing break:
263 createSwDoc();
264 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
265 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
266 uno::Reference<text::XTextContent> xLineBreak(
267 xMSF->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY);
268 uno::Reference<beans::XPropertySet> xLineBreakProps(xLineBreak, uno::UNO_QUERY);
269 auto eClear = static_cast<sal_Int16>(SwLineBreakClear::ALL);
270 xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear));
271 uno::Reference<text::XText> xText = xTextDocument->getText();
272 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
273 xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false);
275 // When enumerating the text portions of the only paragraph in the document:
276 uno::Reference<css::text::XTextRange> xTextPortion = getRun(getParagraph(1), 1);
278 // Then make sure that the text portion type is correct + the clear type can be read:
279 auto aPortionType = getProperty<OUString>(xTextPortion, "TextPortionType");
280 // Without the accompanying fix in place, this test would have failed with:
281 // - Expected: LineBreak
282 // - Actual : Text
283 // i.e. a line break with properties was part of the normal Text portion, making it impossible
284 // to get those properties.
285 CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aPortionType);
286 xLineBreak = getProperty<uno::Reference<text::XTextContent>>(xTextPortion, "LineBreak");
287 eClear = getProperty<sal_Int16>(xLineBreak, "Clear");
288 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int16>(SwLineBreakClear::ALL), eClear);
291 CPPUNIT_TEST_FIXTURE(SwModelTestBase, testUserFieldTooltip)
293 // Given a document with a user field:
294 createSwDoc();
295 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
296 uno::Reference<text::XDependentTextField> xField(
297 xFactory->createInstance("com.sun.star.text.TextField.User"), uno::UNO_QUERY);
298 uno::Reference<beans::XPropertySet> xMaster(
299 xFactory->createInstance("com.sun.star.text.FieldMaster.User"), uno::UNO_QUERY);
300 xMaster->setPropertyValue("Name", uno::Any(OUString("a_user_field")));
301 xField->attachTextFieldMaster(xMaster);
302 xField->getTextFieldMaster()->setPropertyValue("Content", uno::Any(OUString("42")));
303 uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY);
304 uno::Reference<text::XText> xText = xDocument->getText();
305 xText->insertTextContent(xText->createTextCursor(), xField, /*bAbsorb=*/false);
306 uno::Reference<beans::XPropertySet> xFieldProps(xField, uno::UNO_QUERY);
308 // When setting a tooltip on the field:
309 OUString aExpected("first line\nsecond line");
310 xFieldProps->setPropertyValue("Title", uno::Any(aExpected));
312 // Then make sure that the tooltip we read back matches the one previously specified:
313 // Without the accompanying fix in place, this test would have failed with:
314 // - the property is of unexpected type or void: Title
315 // i.e. reading of the tooltip was broken.
316 CPPUNIT_ASSERT_EQUAL(aExpected, getProperty<OUString>(xFieldProps, "Title"));
319 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlInsert)
321 // Given an empty document:
322 createSwDoc();
323 SwDoc* pDoc = getSwDoc();
325 // When inserting a content control around one or more text portions:
326 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
327 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
328 uno::Reference<text::XText> xText = xTextDocument->getText();
329 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
330 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
331 xCursor->gotoStart(/*bExpand=*/false);
332 xCursor->gotoEnd(/*bExpand=*/true);
333 uno::Reference<text::XTextContent> xContentControl(
334 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
335 // Set a custom property on the content control:
336 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
337 xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::Any(true));
338 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
340 // Then make sure that the text attribute is inserted:
341 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
342 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetPointNode().GetIndex();
343 SwTextNode* pTextNode = pDoc->GetNodes()[nIndex]->GetTextNode();
344 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
345 // Without the accompanying fix in place, this test would have failed, as the
346 // SwXContentControl::attach() implementation was missing.
347 CPPUNIT_ASSERT(pAttr);
348 // Also verify that the custom property was set:
349 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
350 auto& rFormatContentControl
351 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
352 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
353 CPPUNIT_ASSERT(pContentControl->GetShowingPlaceHolder());
355 // Also verify that setText() and getText() works:
356 uno::Reference<text::XText> xContentControlText(xContentControl, uno::UNO_QUERY);
357 xContentControlText->setString("new");
358 // Without the accompanying fix in place, this test would have failed with:
359 // - Expected: new
360 // - Actual :
361 // i.e. getString() always returned an empty string.
362 CPPUNIT_ASSERT_EQUAL(OUString("new"), xContentControlText->getString());
365 CPPUNIT_TEST_FIXTURE(SwModelTestBase, testImageTooltip)
367 // Given a document with an image and a hyperlink on it:
368 createSwDoc();
369 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
370 uno::Reference<text::XTextDocument> xDocument(mxComponent, uno::UNO_QUERY);
371 uno::Reference<text::XText> xText = xDocument->getText();
372 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
373 uno::Reference<text::XTextContent> xImage(
374 xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
375 xText->insertTextContent(xCursor, xImage, /*bAbsorb=*/false);
376 uno::Reference<beans::XPropertySet> xImageProps(xImage, uno::UNO_QUERY);
377 xImageProps->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://www.example.com")));
379 // When setting a tooltip on the image:
380 OUString aExpected("first line\nsecond line");
381 xImageProps->setPropertyValue("Tooltip", uno::Any(aExpected));
383 // Then make sure that the tooltip we read back matches the one previously specified:
384 // Without the accompanying fix in place, this test would have failed with:
385 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
386 // i.e. reading/writing of the tooltip was broken.
387 CPPUNIT_ASSERT_EQUAL(aExpected, getProperty<OUString>(xImageProps, "Tooltip"));
390 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlTextPortionEnum)
392 // Given a document with a content control around one or more text portions:
393 createSwDoc();
394 SwDoc* pDoc = getSwDoc();
395 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
396 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
397 uno::Reference<text::XText> xText = xTextDocument->getText();
398 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
399 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
400 xCursor->gotoStart(/*bExpand=*/false);
401 xCursor->gotoEnd(/*bExpand=*/true);
402 uno::Reference<text::XTextContent> xContentControl(
403 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
404 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
406 // When enumerating the text portions of the only paragraph in the document:
407 uno::Reference<css::text::XTextRange> xTextPortion = getRun(getParagraph(1), 1);
409 // Then make sure that the text portion type is correct + the content can be read:
410 auto aPortionType = getProperty<OUString>(xTextPortion, "TextPortionType");
411 // Without the accompanying fix in place, this test would have failed with:
412 // - Expected: ContentControl
413 // - Actual : Text
414 // i.e. the content control text attribute was ignored.
415 CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType);
416 xContentControl
417 = getProperty<uno::Reference<text::XTextContent>>(xTextPortion, "ContentControl");
418 uno::Reference<text::XTextRange> xContentControlRange(xContentControl, uno::UNO_QUERY);
419 xText = xContentControlRange->getText();
420 uno::Reference<container::XEnumerationAccess> xContentEnumAccess(xText, uno::UNO_QUERY);
421 uno::Reference<container::XEnumeration> xContentEnum = xContentEnumAccess->createEnumeration();
422 uno::Reference<text::XTextRange> xContent(xContentEnum->nextElement(), uno::UNO_QUERY);
423 CPPUNIT_ASSERT_EQUAL(OUString("test"), xContent->getString());
425 // Also test the generated layout:
426 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
427 assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwFieldPortion", "expand", "");
428 // Without the accompanying fix in place, this test would have failed with:
429 // - Expected: PortionType::ContentControl
430 // - Actual : PortionType::Text
431 // i.e. SwContentControl generated a plain text portion, not a dedicated content control
432 // portion.
433 assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion", "type",
434 "PortionType::ContentControl");
435 assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion", "portion", "test*");
437 // Also test the doc model, make sure that there is a dummy character at the start and end, so
438 // the user can explicitly decide if they want to expand the content control or not:
439 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
440 OUString aText = pWrtShell->GetCursor()->GetPointNode().GetTextNode()->GetText();
441 // Without the accompanying fix in place, this test would have failed with:
442 // - Expected: ^Atest^A
443 // - Actual : ^Atest
444 // i.e. there was no dummy character at the end.
445 CPPUNIT_ASSERT_EQUAL(OUString("\x0001test\x0001"), aText);
448 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlCheckbox)
450 // Given an empty document:
451 createSwDoc();
452 SwDoc* pDoc = getSwDoc();
454 // When inserting a checkbox content control:
455 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
456 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
457 uno::Reference<text::XText> xText = xTextDocument->getText();
458 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
459 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
460 xCursor->gotoStart(/*bExpand=*/false);
461 xCursor->gotoEnd(/*bExpand=*/true);
462 uno::Reference<text::XTextContent> xContentControl(
463 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
464 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
465 // Without the accompanying fix in place, this test would have failed with:
466 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
467 xContentControlProps->setPropertyValue("Checkbox", uno::Any(true));
468 xContentControlProps->setPropertyValue("Checked", uno::Any(true));
469 xContentControlProps->setPropertyValue("CheckedState", uno::Any(OUString(u"☒")));
470 xContentControlProps->setPropertyValue("UncheckedState", uno::Any(OUString(u"☐")));
471 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
473 // Then make sure that the specified properties are set:
474 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
475 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
476 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
477 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
478 auto& rFormatContentControl
479 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
480 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
481 CPPUNIT_ASSERT(pContentControl->GetCheckbox());
482 CPPUNIT_ASSERT(pContentControl->GetChecked());
483 CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), pContentControl->GetCheckedState());
484 CPPUNIT_ASSERT_EQUAL(OUString(u"☐"), pContentControl->GetUncheckedState());
487 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDropdown)
489 // Given an empty document:
490 createSwDoc();
491 SwDoc* pDoc = getSwDoc();
493 // When inserting a dropdown content control:
494 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
495 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
496 uno::Reference<text::XText> xText = xTextDocument->getText();
497 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
498 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
499 xCursor->gotoStart(/*bExpand=*/false);
500 xCursor->gotoEnd(/*bExpand=*/true);
501 uno::Reference<text::XTextContent> xContentControl(
502 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
503 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
505 uno::Sequence<beans::PropertyValues> aListItems = {
507 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))),
508 comphelper::makePropertyValue("Value", uno::Any(OUString("R"))),
511 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))),
512 comphelper::makePropertyValue("Value", uno::Any(OUString("G"))),
515 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))),
516 comphelper::makePropertyValue("Value", uno::Any(OUString("B"))),
519 // Without the accompanying fix in place, this test would have failed with:
520 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
521 xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems));
523 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
525 // Then make sure that the specified properties are set:
526 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
527 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
528 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
529 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
530 auto& rFormatContentControl
531 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
532 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
533 std::vector<SwContentControlListItem> aListItems = pContentControl->GetListItems();
534 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aListItems.size());
535 CPPUNIT_ASSERT_EQUAL(OUString("red"), aListItems[0].m_aDisplayText);
536 CPPUNIT_ASSERT_EQUAL(OUString("R"), aListItems[0].m_aValue);
539 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testInsertFileInContentControlException)
541 // Given a document with a content control:
542 createSwDoc();
543 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
544 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
545 uno::Reference<text::XText> xText = xTextDocument->getText();
546 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
547 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
548 xCursor->gotoStart(/*bExpand=*/false);
549 xCursor->gotoEnd(/*bExpand=*/true);
550 uno::Reference<text::XTextContent> xContentControl(
551 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
552 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
554 // Reject inserting a document inside the content control:
555 xCursor->goLeft(1, false);
556 OUString aURL(createFileURL(u"tdf119081.odt"));
557 uno::Reference<document::XDocumentInsertable> xInsertable(xCursor, uno::UNO_QUERY);
558 CPPUNIT_ASSERT_THROW(xInsertable->insertDocumentFromURL(aURL, {}), uno::RuntimeException);
560 // Accept inserting a document outside the content control:
561 xCursor->goRight(1, false);
562 xInsertable->insertDocumentFromURL(aURL, {});
565 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlPicture)
567 // Given an empty document:
568 createSwDoc();
569 SwDoc* pDoc = getSwDoc();
571 // When inserting a picture content control:
572 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
573 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
574 uno::Reference<text::XText> xText = xTextDocument->getText();
575 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
576 uno::Reference<beans::XPropertySet> xTextGraphic(
577 xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY);
578 xTextGraphic->setPropertyValue("AnchorType",
579 uno::Any(text::TextContentAnchorType_AS_CHARACTER));
580 uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY);
581 xText->insertTextContent(xCursor, xTextContent, false);
582 xCursor->gotoStart(/*bExpand=*/false);
583 xCursor->gotoEnd(/*bExpand=*/true);
584 uno::Reference<text::XTextContent> xContentControl(
585 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
586 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
587 // Without the accompanying fix in place, this test would have failed with:
588 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
589 xContentControlProps->setPropertyValue("Picture", uno::Any(true));
590 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
592 // Then make sure that the specified properties are set:
593 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
594 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
595 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
596 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
597 auto& rFormatContentControl
598 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
599 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
600 CPPUNIT_ASSERT(pContentControl->GetPicture());
603 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate)
605 // Given an empty document:
606 createSwDoc();
607 SwDoc* pDoc = getSwDoc();
609 // When inserting a date content control:
610 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
611 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
612 uno::Reference<text::XText> xText = xTextDocument->getText();
613 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
614 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
615 xCursor->gotoStart(/*bExpand=*/false);
616 xCursor->gotoEnd(/*bExpand=*/true);
617 uno::Reference<text::XTextContent> xContentControl(
618 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
619 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
620 // Without the accompanying fix in place, this test would have failed with:
621 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
622 xContentControlProps->setPropertyValue("Date", uno::Any(true));
623 xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("M/d/yyyy")));
624 xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US")));
625 xContentControlProps->setPropertyValue("CurrentDate",
626 uno::Any(OUString("2022-05-25T00:00:00Z")));
627 xContentControlProps->setPropertyValue("PlaceholderDocPart",
628 uno::Any(OUString("DefaultPlaceholder_-1854013437")));
629 xContentControlProps->setPropertyValue(
630 "DataBindingPrefixMappings",
631 uno::Any(OUString("xmlns:ns0='http://schemas.microsoft.com/vsto/samples' ")));
632 xContentControlProps->setPropertyValue(
633 "DataBindingXpath",
634 uno::Any(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]")));
635 xContentControlProps->setPropertyValue(
636 "DataBindingStoreItemID", uno::Any(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}")));
637 xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000")));
638 xContentControlProps->setPropertyValue("Alias", uno::Any(OUString("myalias")));
639 xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("mytag")));
640 xContentControlProps->setPropertyValue("Id", uno::Any(static_cast<sal_Int32>(123)));
641 xContentControlProps->setPropertyValue("TabIndex", uno::Any(sal_uInt32(1)));
642 xContentControlProps->setPropertyValue("Lock", uno::Any(OUString("sdtContentLocked")));
643 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
645 // Then make sure that the specified properties are set:
646 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
647 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
648 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
649 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
650 auto& rFormatContentControl
651 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
652 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
653 CPPUNIT_ASSERT(pContentControl->GetDate());
654 CPPUNIT_ASSERT_EQUAL(OUString("M/d/yyyy"), pContentControl->GetDateFormat());
655 CPPUNIT_ASSERT_EQUAL(OUString("en-US"), pContentControl->GetDateLanguage());
656 CPPUNIT_ASSERT_EQUAL(OUString("2022-05-25T00:00:00Z"), pContentControl->GetCurrentDate());
657 CPPUNIT_ASSERT_EQUAL(OUString("DefaultPlaceholder_-1854013437"),
658 pContentControl->GetPlaceholderDocPart());
659 CPPUNIT_ASSERT_EQUAL(OUString("xmlns:ns0='http://schemas.microsoft.com/vsto/samples' "),
660 pContentControl->GetDataBindingPrefixMappings());
661 CPPUNIT_ASSERT_EQUAL(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]"),
662 pContentControl->GetDataBindingXpath());
663 CPPUNIT_ASSERT_EQUAL(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}"),
664 pContentControl->GetDataBindingStoreItemID());
665 CPPUNIT_ASSERT_EQUAL(OUString("008000"), pContentControl->GetColor());
666 CPPUNIT_ASSERT_EQUAL(OUString("myalias"), pContentControl->GetAlias());
667 CPPUNIT_ASSERT_EQUAL(OUString("mytag"), pContentControl->GetTag());
668 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(123), pContentControl->GetId());
669 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), pContentControl->GetTabIndex());
670 CPPUNIT_ASSERT_EQUAL(OUString("sdtContentLocked"), pContentControl->GetLock());
673 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlPlainText)
675 // Given an empty document:
676 createSwDoc();
677 SwDoc* pDoc = getSwDoc();
679 // When inserting a plain text content control around a text portion:
680 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
681 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
682 uno::Reference<text::XText> xText = xTextDocument->getText();
683 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
684 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
685 xCursor->gotoStart(/*bExpand=*/false);
686 xCursor->gotoEnd(/*bExpand=*/true);
687 uno::Reference<text::XTextContent> xContentControl(
688 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
689 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
690 xContentControlProps->setPropertyValue("PlainText", uno::Any(true));
691 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
693 // Then make sure that the text attribute is inserted:
694 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
695 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetPointNode().GetIndex();
696 SwTextNode* pTextNode = pDoc->GetNodes()[nIndex]->GetTextNode();
697 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
698 CPPUNIT_ASSERT(pAttr);
699 // Also verify that the type if plain text:
700 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
701 auto& rFormatContentControl
702 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
703 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
704 CPPUNIT_ASSERT(pContentControl->GetPlainText());
706 // Now check if the char index range 2-4 is extended to 0-6 when we apply formatting:
707 pWrtShell->SttEndDoc(/*bStt=*/true);
708 // Select "es" from "<dummy>test<dummy>".
709 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 2, /*bBasicCall=*/false);
710 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 2, /*bBasicCall=*/false);
711 SfxItemSetFixed<RES_CHRATR_WEIGHT, RES_CHRATR_WEIGHT> aSet(pWrtShell->GetAttrPool());
712 SvxWeightItem aItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT);
713 aSet.Put(aItem);
714 pWrtShell->SetAttrSet(aSet);
715 pAttr = pTextNode->GetTextAttrAt(2, RES_TXTATR_AUTOFMT);
716 // Without the accompanying fix in place, this test would have failed with:
717 // - Expected: 0
718 // - Actual : 2
719 // i.e. the plain text content control now had 3 portions (<dummy>t<b>es</b>t<dummy>), instead
720 // of one (<b><dummy>test<dummy></b>).
721 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), pAttr->GetStart());
722 CPPUNIT_ASSERT(pAttr->End());
723 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(6), *pAttr->End());
726 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlComboBox)
728 // Given an empty document:
729 createSwDoc();
730 SwDoc* pDoc = getSwDoc();
732 // When inserting a combobox content control:
733 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
734 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
735 uno::Reference<text::XText> xText = xTextDocument->getText();
736 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
737 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
738 xCursor->gotoStart(/*bExpand=*/false);
739 xCursor->gotoEnd(/*bExpand=*/true);
740 uno::Reference<text::XTextContent> xContentControl(
741 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
742 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
744 uno::Sequence<beans::PropertyValues> aListItems = {
746 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))),
747 comphelper::makePropertyValue("Value", uno::Any(OUString("R"))),
750 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))),
751 comphelper::makePropertyValue("Value", uno::Any(OUString("G"))),
754 comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))),
755 comphelper::makePropertyValue("Value", uno::Any(OUString("B"))),
758 xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems));
759 // Without the accompanying fix in place, this test would have failed with:
760 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
761 xContentControlProps->setPropertyValue("ComboBox", uno::Any(true));
763 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
765 // Then make sure that the specified properties are set:
766 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
767 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
768 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
769 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
770 auto& rFormatContentControl
771 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
772 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
773 std::vector<SwContentControlListItem> aListItems = pContentControl->GetListItems();
774 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aListItems.size());
775 CPPUNIT_ASSERT_EQUAL(OUString("red"), aListItems[0].m_aDisplayText);
776 CPPUNIT_ASSERT_EQUAL(OUString("R"), aListItems[0].m_aValue);
777 CPPUNIT_ASSERT(pContentControl->GetComboBox());
780 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControls)
782 // Given an empty document:
783 createSwDoc();
784 auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
785 uno::Reference<container::XIndexAccess> xContentControls = pXTextDocument->getContentControls();
786 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), xContentControls->getCount());
788 // When inserting content controls:
789 uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY);
790 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
791 uno::Reference<text::XText> xText = xTextDocument->getText();
792 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
793 // First tag1.
794 xText->insertString(xCursor, "test1", /*bAbsorb=*/false);
795 xCursor->gotoStart(/*bExpand=*/false);
796 xCursor->gotoEnd(/*bExpand=*/true);
798 uno::Reference<text::XTextContent> xContentControl(
799 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
800 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
801 xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("tag1")));
802 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
804 xCursor->gotoStart(/*bExpand=*/false);
805 // Then tag2 before tag1.
806 xText->insertString(xCursor, "test2", /*bAbsorb=*/false);
807 xCursor->gotoStart(/*bExpand=*/false);
808 xCursor->goRight(5, /*bExpand=*/true);
810 uno::Reference<text::XTextContent> xContentControl(
811 xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY);
812 uno::Reference<beans::XPropertySet> xContentControlProps(xContentControl, uno::UNO_QUERY);
813 xContentControlProps->setPropertyValue("Tag", uno::Any(OUString("tag2")));
814 xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true);
817 // Then make sure that XContentControls contains the items in a correct order:
818 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(2), xContentControls->getCount());
819 uno::Reference<beans::XPropertySet> xContentControl;
820 xContentControls->getByIndex(0) >>= xContentControl;
821 OUString aTag;
822 xContentControl->getPropertyValue("Tag") >>= aTag;
823 // Without the accompanying fix in place, this test would have failed with:
824 // - Expected: tag2
825 // - Actual : tag1
826 // i.e. the order of the items was sorted by insert time, not by their doc model position.
827 CPPUNIT_ASSERT_EQUAL(OUString("tag2"), aTag);
830 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerODFExport)
832 // Given a document with a red numbering portion, from the paragraph marker's format:
833 createSwDoc("paragraph-marker.docx");
835 // When saving that as ODT + reload:
836 saveAndReload("writer8");
838 // Then make sure that it still has the correct color:
839 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
840 // Without the accompanying fix in place, this test would have failed with:
841 // - Expected: 00ff0000 (COL_LIGHTRED)
842 // - Actual : ffffffff (COL_AUTO)
843 // i.e. the custom "red" color was lost as RES_PARATR_LIST_AUTOFMT was not serialized to ODT.
844 CPPUNIT_ASSERT_EQUAL(
845 OUString("00ff0000"),
846 getXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwFieldPortion/SwFont", "color"));
849 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerFormattedRun)
851 // Given a document with a bold run and non-bold paragraph marker:
852 createSwDoc("paragraph-marker-formatted-run.docx");
854 // When saving that as ODT + reload:
855 saveAndReload("writer8");
857 // Then make sure that the numbering portion is still non-bold, matching Word:
858 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
859 // Without the accompanying fix in place, this test would have failed with:
860 // - Expected: normal
861 // - Actual : bold
862 // i.e. the numbering portion was bold, while its weight should be normal.
863 CPPUNIT_ASSERT_EQUAL(
864 OUString("normal"),
865 getXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwFieldPortion/SwFont", "weight"));
868 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testFlySplit)
870 // Given a document with a fly frame:
871 createSwDoc();
872 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
873 SwFlyFrameAttrMgr aMgr(true, pWrtShell, Frmmgr_Type::TEXT, nullptr);
874 RndStdIds eAnchor = RndStdIds::FLY_AT_PARA;
875 aMgr.InsertFlyFrame(eAnchor, aMgr.GetPos(), aMgr.GetSize());
876 uno::Reference<text::XTextFramesSupplier> xDocument(mxComponent, uno::UNO_QUERY);
877 uno::Reference<beans::XPropertySet> xFrame(xDocument->getTextFrames()->getByName("Frame1"),
878 uno::UNO_QUERY);
879 bool bIsSplitAllowed{};
880 // Without the accompanying fix in place, this test would have failed with:
881 // An uncaught exception of type com.sun.star.beans.UnknownPropertyException
882 // - Unknown property: IsSplitAllowed
883 // i.e. the property was missing.
884 xFrame->getPropertyValue("IsSplitAllowed") >>= bIsSplitAllowed;
885 CPPUNIT_ASSERT(!bIsSplitAllowed);
887 // When marking it as IsSplitAllowed=true:
888 xFrame->setPropertyValue("IsSplitAllowed", uno::Any(true));
890 // Then make sure that IsSplitAllowed is true when asking back:
891 xFrame->getPropertyValue("IsSplitAllowed") >>= bIsSplitAllowed;
892 CPPUNIT_ASSERT(bIsSplitAllowed);
895 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testConvertToTextFrame)
897 // Given a document with 2 non-interesting frames, an inner frame and an outer frame:
898 createSwDoc("floattable-outer-nonsplit-inner.docx");
900 // When checking the anchor of the inner frame:
901 SwDoc* pDoc = getSwDoc();
902 const sw::FrameFormats<sw::SpzFrameFormat*>& rFrames = *pDoc->GetSpzFrameFormats();
903 sw::SpzFrameFormat* pFrame3 = rFrames.FindFrameFormatByName("Frame3");
904 SwNodeIndex aFrame3Anchor = pFrame3->GetAnchor().GetContentAnchor()->nNode;
906 // Then make sure it's anchored in the outer frame's last content node:
907 sw::SpzFrameFormat* pFrame4 = rFrames.FindFrameFormatByName("Frame4");
908 SwPaM aPaM(*pFrame4->GetContent().GetContentIdx()->GetNode().EndOfSectionNode());
909 aPaM.Move(fnMoveBackward, GoInContent);
910 // Without the accompanying fix in place, this test would have failed with:
911 // - Expected: SwNodeIndex (node 27)
912 // - Actual : SwNodeIndex (node 49)
913 // i.e. Frame3 was anchored much later, in the body text, not in Frame4.
914 CPPUNIT_ASSERT_EQUAL(aPaM.GetPoint()->nNode, aFrame3Anchor);
917 namespace
919 /// This selection listener calls XTextRange::getString() on a selection change, which triggered
920 /// a new selection change event by accident, resulting infinite recursion and crash
921 struct SelectionChangeListener : public cppu::WeakImplHelper<view::XSelectionChangeListener>
923 public:
924 SelectionChangeListener();
925 // view::XSelectionChangeListener
926 void SAL_CALL selectionChanged(const lang::EventObject& rEvent) override;
928 // lang::XEventListener
929 void SAL_CALL disposing(const lang::EventObject& rSource) override;
933 SelectionChangeListener::SelectionChangeListener() {}
935 void SelectionChangeListener::selectionChanged(const lang::EventObject& rEvent)
937 uno::Reference<view::XSelectionSupplier> xSelectionSupplier(rEvent.Source, uno::UNO_QUERY);
938 css::uno::Reference<css::container::XIndexAccess> xSelection(xSelectionSupplier->getSelection(),
939 css::uno::UNO_QUERY_THROW);
940 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelection->getCount());
941 css::uno::Reference<css::text::XTextRange> xTextRange(xSelection->getByIndex(0),
942 css::uno::UNO_QUERY_THROW);
943 CPPUNIT_ASSERT(xTextRange->getString().startsWith("test"));
946 void SelectionChangeListener::disposing(const lang::EventObject& /*rSource*/) {}
948 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testTdf155951)
950 createSwDoc();
951 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
952 uno::Reference<text::XText> xText = xTextDocument->getText();
953 uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor();
954 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
956 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
957 uno::Reference<view::XSelectionSupplier> xController(xModel->getCurrentController(),
958 uno::UNO_QUERY);
959 xController->addSelectionChangeListener(new SelectionChangeListener());
961 // This crashed here because of infinite recursion
962 dispatchCommand(mxComponent, ".uno:WordLeftSel", {});
964 // this needs to wait for dispatching (trigger also a second selection change)
965 xText->insertString(xCursor, "test", /*bAbsorb=*/false);
968 CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testCollectFrameAtNodeWithLayout)
970 // Given a document with a floating table on 2 pages, with a calculated layout:
971 createSwDoc("floattable-split.docx");
972 calcLayout();
974 // When saving to ODT:
975 save("writer8");
977 // Then make sure the output is valid and hasa 1 <draw:frame>:
978 // Without the accompanying fix in place, this test would have failed with:
979 // Error: uncompleted content model.
980 // i.e. the output was not valid, the second <draw:frame> has an empty <table:table> as a child
981 // element.
982 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
983 // Also make sure that we don't have multiple <draw:frame> elements in the first place.
984 assertXPath(pXmlDoc, "//draw:frame", 1);
987 CPPUNIT_PLUGIN_IMPLEMENT();
989 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */