/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; namespace { constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/core/unocore/data/"; } /// Covers sw/source/core/unocore/ fixes. class SwCoreUnocoreTest : public SwModelTestBase { }; CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testTdf119081) { // Load a doc with a nested table in it. load(DATA_DIRECTORY, "tdf119081.odt"); SwXTextDocument* pTextDoc = dynamic_cast(mxComponent.get()); CPPUNIT_ASSERT(pTextDoc); SwDocShell* pDocShell = pTextDoc->GetDocShell(); SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); // Enter outer A1. pWrtShell->Down(/*bSelect=*/false, /*nCount=*/3); // Enter inner A1. pWrtShell->Right(CRSR_SKIP_CELLS, /*bSelect=*/false, /*nCount=*/1, /*bBasicCall=*/false, /*bVisual=*/true); // Enter outer B1. pWrtShell->Down(/*bSelect=*/false, /*nCount=*/2); SwDoc* pDoc = pDocShell->GetDoc(); SwPaM& rCursor = pWrtShell->GetCurrentShellCursor(); uno::Reference xInsertPosition = SwXTextRange::CreateXTextRange(*pDoc, *rCursor.GetPoint(), nullptr); uno::Reference xTextAppend(xInsertPosition->getText(), uno::UNO_QUERY); // Without the accompanying fix in place, this test would have failed with: // An uncaught exception of type com.sun.star.uno.RuntimeException xTextAppend->insertTextPortion("x", {}, xInsertPosition); // Verify that the string is indeed inserted. pWrtShell->Left(CRSR_SKIP_CELLS, /*bSelect=*/true, /*nCount=*/1, /*bBasicCall=*/false, /*bVisual=*/true); CPPUNIT_ASSERT_EQUAL(OUString("x"), pWrtShell->GetCurrentShellCursor().GetText()); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, flyAtParaAnchor) { mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument"); uno::Reference const xMSF(mxComponent, uno::UNO_QUERY_THROW); uno::Reference const xTD(mxComponent, uno::UNO_QUERY_THROW); uno::Reference const xTextFrame( xMSF->createInstance("com.sun.star.text.TextFrame"), uno::UNO_QUERY_THROW); uno::Reference const xFrameProps(xTextFrame, uno::UNO_QUERY_THROW); xFrameProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_PARAGRAPH)); auto const xText = xTD->getText(); auto const xTextCursor = xText->createTextCursor(); CPPUNIT_ASSERT(xTextCursor.is()); xText->insertTextContent(xTextCursor, xTextFrame, false); auto const xAnchor = xTextFrame->getAnchor(); uno::Reference const xFieldmark( xMSF->createInstance("com.sun.star.text.Fieldmark"), uno::UNO_QUERY_THROW); // this crashed because the anchor didn't have SwIndex xText->insertTextContent(xAnchor, xFieldmark, false); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testRtlGutter) { mxComponent = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument"); uno::Reference xPageStyle(getStyles("PageStyles")->getByName("Standard"), uno::UNO_QUERY); // Without the accompanying fix in place, this test would have failed with: // - Unknown property: RtlGutter auto bRtlGutter = getProperty(xPageStyle, "RtlGutter"); CPPUNIT_ASSERT(!bRtlGutter); xPageStyle->setPropertyValue("RtlGutter", uno::Any(true)); bRtlGutter = getProperty(xPageStyle, "RtlGutter"); CPPUNIT_ASSERT(bRtlGutter); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testBiblioLocalCopy) { // Given an empty document: createSwDoc(); // When setting the LocalURL of a biblio field: uno::Reference xFactory(mxComponent, uno::UNO_QUERY); uno::Reference xField( xFactory->createInstance("com.sun.star.text.TextField.Bibliography"), uno::UNO_QUERY); uno::Sequence aFields = { comphelper::makePropertyValue("BibiliographicType", text::BibliographyDataType::WWW), comphelper::makePropertyValue("Identifier", OUString("ARJ00")), comphelper::makePropertyValue("Author", OUString("Me")), comphelper::makePropertyValue("Title", OUString("mytitle")), comphelper::makePropertyValue("Year", OUString("2020")), comphelper::makePropertyValue("URL", OUString("http://www.example.com/test.pdf")), comphelper::makePropertyValue("LocalURL", OUString("file:///home/me/test.pdf")), }; xField->setPropertyValue("Fields", uno::Any(aFields)); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); uno::Reference xContent(xField, uno::UNO_QUERY); xText->insertTextContent(xCursor, xContent, /*bAbsorb=*/false); // Then make sure we get that LocalURL back: comphelper::SequenceAsHashMap aMap(xField->getPropertyValue("Fields")); // Without the accompanying fix in place, this test would have failed, there was no LocalURL key // in the map. CPPUNIT_ASSERT(aMap.find("LocalURL") != aMap.end()); auto aActual = aMap["LocalURL"].get(); CPPUNIT_ASSERT_EQUAL(OUString("file:///home/me/test.pdf"), aActual); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testLinkedStyles) { // Given an empty document: createSwDoc(); // When defining a linked style for a para style: uno::Reference xParaStyles = getStyles("ParagraphStyles"); uno::Reference xParaStyle(xParaStyles->getByName("Caption"), uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(OUString(), getProperty(xParaStyle, "LinkStyle")); xParaStyle->setPropertyValue("LinkStyle", uno::Any(OUString("Emphasis"))); // Then make sure we get the linked char style back: CPPUNIT_ASSERT_EQUAL(OUString("Emphasis"), getProperty(xParaStyle, "LinkStyle")); // When defining a linked style for a char style: uno::Reference xCharStyles = getStyles("CharacterStyles"); uno::Reference xCharStyle(xCharStyles->getByName("Emphasis"), uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(OUString(), getProperty(xCharStyle, "LinkStyle")); xCharStyle->setPropertyValue("LinkStyle", uno::Any(OUString("Caption"))); // Then make sure we get the linked para style back: CPPUNIT_ASSERT_EQUAL(OUString("Caption"), getProperty(xCharStyle, "LinkStyle")); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testViewCursorTextFrame) { // Given a document with a graphic and holding a reference to that graphic frame: createSwDoc(); uno::Sequence aInsertArgs = { comphelper::makePropertyValue( "FileName", m_directories.getURLFromSrc(DATA_DIRECTORY) + "graphic.png") }; dispatchCommand(mxComponent, ".uno:InsertGraphic", aInsertArgs); uno::Reference xModel(mxComponent, uno::UNO_QUERY); uno::Reference xTextViewCursorSupplier( xModel->getCurrentController(), uno::UNO_QUERY); uno::Reference xViewCursor(xTextViewCursorSupplier->getViewCursor(), uno::UNO_QUERY); uno::Reference xFrame; xViewCursor->getPropertyValue("TextFrame") >>= xFrame; // When saving to ODT, then make sure the store doesn't fail: uno::Reference xStorable(xModel, uno::UNO_QUERY); uno::Sequence aStoreArgs = { comphelper::makePropertyValue("FilterName", OUString("writer8")) }; // Without the accompanying fix in place, this test would have failed with: // uno.RuntimeException: "SwXParagraph: disposed or invalid ..." xStorable->storeToURL(maTempFile.GetURL(), aStoreArgs); } /// Fails the test if an error popup would be presented. static void BasicDisplayErrorHandler(const OUString& /*rErr*/, const OUString& /*rAction*/) { CPPUNIT_ASSERT(false); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testBrokenEmbeddedObject) { // Given a document with a broken embedded object (the XML markup is not well-formed): load(DATA_DIRECTORY, "broken-embedded-object.odt"); uno::Reference xSupplier(mxComponent, uno::UNO_QUERY); uno::Reference xObjects(xSupplier->getEmbeddedObjects(), uno::UNO_QUERY); uno::Reference xObject(xObjects->getByIndex(0), uno::UNO_QUERY); uno::Reference xEmbeddedObject; // Get the property first, which initializes Draw, which would overwrite our error handler. xObject->getPropertyValue("EmbeddedObject") >>= xEmbeddedObject; ErrorRegistry::RegisterDisplay(&BasicDisplayErrorHandler); // When trying to load that embedded object: xObject->getPropertyValue("EmbeddedObject") >>= xEmbeddedObject; // Then make sure we get a non-empty reference and an error popup it not shown: CPPUNIT_ASSERT(xEmbeddedObject.is()); // Without the accompanying fix in place, we got this reference, but first an error popup was // shown to the user. CPPUNIT_ASSERT( xEmbeddedObject->supportsService("com.sun.star.comp.embed.OCommonEmbeddedObject")); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testLineBreakInsert) { // Given an empty document: SwDoc* pDoc = createSwDoc(); // When inserting a line-break with properties: uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xLineBreak( xMSF->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); uno::Reference xLineBreakProps(xLineBreak, uno::UNO_QUERY); auto eClear = static_cast(SwLineBreakClear::ALL); xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); // Then make sure that both the line break and its matching text attribute is inserted: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex(); SwTextNode* pTextNode = pDoc->GetNodes()[nIndex]->GetTextNode(); // Without the accompanying fix in place, this test would have failed with: // - Expected: "\n" (newline) // - Actual : "" (empty string) // i.e. SwXLineBreak::attach() did not insert the newline + its text attribute. CPPUNIT_ASSERT_EQUAL(OUString("\n"), pTextNode->GetText()); SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_LINEBREAK); CPPUNIT_ASSERT(pAttr); auto pTextLineBreak = static_cast(pAttr); auto& rFormatLineBreak = static_cast(pTextLineBreak->GetAttr()); CPPUNIT_ASSERT_EQUAL(SwLineBreakClear::ALL, rFormatLineBreak.GetValue()); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testLineBreakTextPortionEnum) { // Given a document with a clearing break: createSwDoc(); uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xLineBreak( xMSF->createInstance("com.sun.star.text.LineBreak"), uno::UNO_QUERY); uno::Reference xLineBreakProps(xLineBreak, uno::UNO_QUERY); auto eClear = static_cast(SwLineBreakClear::ALL); xLineBreakProps->setPropertyValue("Clear", uno::Any(eClear)); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertTextContent(xCursor, xLineBreak, /*bAbsorb=*/false); // When enumerating the text portions of the only paragraph in the document: uno::Reference xTextPortion = getRun(getParagraph(1), 1); // Then make sure that the text portion type is correct + the clear type can be read: auto aPortionType = getProperty(xTextPortion, "TextPortionType"); // Without the accompanying fix in place, this test would have failed with: // - Expected: LineBreak // - Actual : Text // i.e. a line break with properties was part of the normal Text portion, making it impossible // to get those properties. CPPUNIT_ASSERT_EQUAL(OUString("LineBreak"), aPortionType); xLineBreak = getProperty>(xTextPortion, "LineBreak"); eClear = getProperty(xLineBreak, "Clear"); CPPUNIT_ASSERT_EQUAL(static_cast(SwLineBreakClear::ALL), eClear); } CPPUNIT_TEST_FIXTURE(SwModelTestBase, testUserFieldTooltip) { // Given a document with a user field: loadURL("private:factory/swriter", nullptr); uno::Reference xFactory(mxComponent, uno::UNO_QUERY); uno::Reference xField( xFactory->createInstance("com.sun.star.text.TextField.User"), uno::UNO_QUERY); uno::Reference xMaster( xFactory->createInstance("com.sun.star.text.FieldMaster.User"), uno::UNO_QUERY); xMaster->setPropertyValue("Name", uno::Any(OUString("a_user_field"))); xField->attachTextFieldMaster(xMaster); xField->getTextFieldMaster()->setPropertyValue("Content", uno::Any(OUString("42"))); uno::Reference xDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xDocument->getText(); xText->insertTextContent(xText->createTextCursor(), xField, /*bAbsorb=*/false); uno::Reference xFieldProps(xField, uno::UNO_QUERY); // When setting a tooltip on the field: OUString aExpected("first line\nsecond line"); xFieldProps->setPropertyValue("Title", uno::Any(aExpected)); // Then make sure that the tooltip we read back matches the one previously specified: // Without the accompanying fix in place, this test would have failed with: // - the property is of unexpected type or void: Title // i.e. reading of the tooltip was broken. CPPUNIT_ASSERT_EQUAL(aExpected, getProperty(xFieldProps, "Title")); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlInsert) { // Given an empty document: SwDoc* pDoc = createSwDoc(); // When inserting a content control around one or more text portions: uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); // Set a custom property on the content control: uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); xContentControlProps->setPropertyValue("ShowingPlaceHolder", uno::Any(true)); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the text attribute is inserted: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex(); SwTextNode* pTextNode = pDoc->GetNodes()[nIndex]->GetTextNode(); SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); // Without the accompanying fix in place, this test would have failed, as the // SwXContentControl::attach() implementation was missing. CPPUNIT_ASSERT(pAttr); // Also verify that the custom property was set: auto pTextContentControl = static_txtattr_cast(pAttr); auto& rFormatContentControl = static_cast(pTextContentControl->GetAttr()); std::shared_ptr pContentControl = rFormatContentControl.GetContentControl(); CPPUNIT_ASSERT(pContentControl->GetShowingPlaceHolder()); } CPPUNIT_TEST_FIXTURE(SwModelTestBase, testImageTooltip) { // Given a document with an image and a hyperlink on it: loadURL("private:factory/swriter", nullptr); uno::Reference xFactory(mxComponent, uno::UNO_QUERY); uno::Reference xDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); uno::Reference xImage( xFactory->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); xText->insertTextContent(xCursor, xImage, /*bAbsorb=*/false); uno::Reference xImageProps(xImage, uno::UNO_QUERY); xImageProps->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://www.example.com"))); // When setting a tooltip on the image: OUString aExpected("first line\nsecond line"); xImageProps->setPropertyValue("Tooltip", uno::Any(aExpected)); // Then make sure that the tooltip we read back matches the one previously specified: // Without the accompanying fix in place, this test would have failed with: // An uncaught exception of type com.sun.star.beans.UnknownPropertyException // i.e. reading/writing of the tooltip was broken. CPPUNIT_ASSERT_EQUAL(aExpected, getProperty(xImageProps, "Tooltip")); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlTextPortionEnum) { // Given a document with a content control around one or more text portions: SwDoc* pDoc = createSwDoc(); uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // When enumerating the text portions of the only paragraph in the document: uno::Reference xTextPortion = getRun(getParagraph(1), 1); // Then make sure that the text portion type is correct + the content can be read: auto aPortionType = getProperty(xTextPortion, "TextPortionType"); // Without the accompanying fix in place, this test would have failed with: // - Expected: ContentControl // - Actual : Text // i.e. the content control text attribute was ignored. CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType); xContentControl = getProperty>(xTextPortion, "ContentControl"); uno::Reference xContentControlRange(xContentControl, uno::UNO_QUERY); xText = xContentControlRange->getText(); uno::Reference xContentEnumAccess(xText, uno::UNO_QUERY); uno::Reference xContentEnum = xContentEnumAccess->createEnumeration(); uno::Reference xContent(xContentEnum->nextElement(), uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(OUString("test"), xContent->getString()); // Also test the generated layout: xmlDocUniquePtr pXmlDoc = parseLayoutDump(); assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwFieldPortion", "expand", ""); // Without the accompanying fix in place, this test would have failed with: // - Expected: PortionType::ContentControl // - Actual : PortionType::Text // i.e. SwContentControl generated a plain text portion, not a dedicated content control // portion. assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion", "type", "PortionType::ContentControl"); assertXPath(pXmlDoc, "//SwParaPortion/SwLineLayout/SwLinePortion", "portion", "test*"); // Also test the doc model, make sure that there is a dummy character at the start and end, so // the user can explicitly decide if they want to expand the content control or not: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); OUString aText = pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText(); // Without the accompanying fix in place, this test would have failed with: // - Expected: ^Atest^A // - Actual : ^Atest // i.e. there was no dummy character at the end. CPPUNIT_ASSERT_EQUAL(OUString("\x0001test\x0001"), aText); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlCheckbox) { // Given an empty document: SwDoc* pDoc = createSwDoc(); // When inserting a checkbox content control: uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); // Without the accompanying fix in place, this test would have failed with: // An uncaught exception of type com.sun.star.beans.UnknownPropertyException xContentControlProps->setPropertyValue("Checkbox", uno::Any(true)); xContentControlProps->setPropertyValue("Checked", uno::Any(true)); xContentControlProps->setPropertyValue("CheckedState", uno::Any(OUString(u"☒"))); xContentControlProps->setPropertyValue("UncheckedState", uno::Any(OUString(u"☐"))); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the specified properties are set: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode(); SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); auto pTextContentControl = static_txtattr_cast(pAttr); auto& rFormatContentControl = static_cast(pTextContentControl->GetAttr()); std::shared_ptr pContentControl = rFormatContentControl.GetContentControl(); CPPUNIT_ASSERT(pContentControl->GetCheckbox()); CPPUNIT_ASSERT(pContentControl->GetChecked()); CPPUNIT_ASSERT_EQUAL(OUString(u"☒"), pContentControl->GetCheckedState()); CPPUNIT_ASSERT_EQUAL(OUString(u"☐"), pContentControl->GetUncheckedState()); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDropdown) { // Given an empty document: SwDoc* pDoc = createSwDoc(); // When inserting a dropdown content control: uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); { uno::Sequence aListItems = { { comphelper::makePropertyValue("DisplayText", uno::Any(OUString("red"))), comphelper::makePropertyValue("Value", uno::Any(OUString("R"))), }, { comphelper::makePropertyValue("DisplayText", uno::Any(OUString("green"))), comphelper::makePropertyValue("Value", uno::Any(OUString("G"))), }, { comphelper::makePropertyValue("DisplayText", uno::Any(OUString("blue"))), comphelper::makePropertyValue("Value", uno::Any(OUString("B"))), }, }; // Without the accompanying fix in place, this test would have failed with: // An uncaught exception of type com.sun.star.beans.UnknownPropertyException xContentControlProps->setPropertyValue("ListItems", uno::Any(aListItems)); } xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the specified properties are set: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode(); SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); auto pTextContentControl = static_txtattr_cast(pAttr); auto& rFormatContentControl = static_cast(pTextContentControl->GetAttr()); std::shared_ptr pContentControl = rFormatContentControl.GetContentControl(); std::vector aListItems = pContentControl->GetListItems(); CPPUNIT_ASSERT_EQUAL(static_cast(3), aListItems.size()); CPPUNIT_ASSERT_EQUAL(OUString("red"), aListItems[0].m_aDisplayText); CPPUNIT_ASSERT_EQUAL(OUString("R"), aListItems[0].m_aValue); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testInsertFileInContentControlException) { // Given a document with a content control: createSwDoc(); uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Reject inserting a document inside the content control: xCursor->goLeft(1, false); OUString aURL(m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf119081.odt"); uno::Reference xInsertable(xCursor, uno::UNO_QUERY); CPPUNIT_ASSERT_THROW(xInsertable->insertDocumentFromURL(aURL, {}), uno::RuntimeException); // Accept inserting a document outside the content control: xCursor->goRight(1, false); xInsertable->insertDocumentFromURL(aURL, {}); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlPicture) { // Given an empty document: SwDoc* pDoc = createSwDoc(); // When inserting a picture content control: uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); uno::Reference xTextGraphic( xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); xTextGraphic->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AS_CHARACTER)); uno::Reference xTextContent(xTextGraphic, uno::UNO_QUERY); xText->insertTextContent(xCursor, xTextContent, false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); // Without the accompanying fix in place, this test would have failed with: // An uncaught exception of type com.sun.star.beans.UnknownPropertyException xContentControlProps->setPropertyValue("Picture", uno::Any(true)); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the specified properties are set: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode(); SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); auto pTextContentControl = static_txtattr_cast(pAttr); auto& rFormatContentControl = static_cast(pTextContentControl->GetAttr()); std::shared_ptr pContentControl = rFormatContentControl.GetContentControl(); CPPUNIT_ASSERT(pContentControl->GetPicture()); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testContentControlDate) { // Given an empty document: SwDoc* pDoc = createSwDoc(); // When inserting a date content control: uno::Reference xMSF(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xCursor = xText->createTextCursor(); xText->insertString(xCursor, "test", /*bAbsorb=*/false); xCursor->gotoStart(/*bExpand=*/false); xCursor->gotoEnd(/*bExpand=*/true); uno::Reference xContentControl( xMSF->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY); uno::Reference xContentControlProps(xContentControl, uno::UNO_QUERY); // Without the accompanying fix in place, this test would have failed with: // An uncaught exception of type com.sun.star.beans.UnknownPropertyException xContentControlProps->setPropertyValue("Date", uno::Any(true)); xContentControlProps->setPropertyValue("DateFormat", uno::Any(OUString("M/d/yyyy"))); xContentControlProps->setPropertyValue("DateLanguage", uno::Any(OUString("en-US"))); xContentControlProps->setPropertyValue("CurrentDate", uno::Any(OUString("2022-05-25T00:00:00Z"))); xContentControlProps->setPropertyValue("PlaceholderDocPart", uno::Any(OUString("DefaultPlaceholder_-1854013437"))); xContentControlProps->setPropertyValue( "DataBindingPrefixMappings", uno::Any(OUString("xmlns:ns0='http://schemas.microsoft.com/vsto/samples' "))); xContentControlProps->setPropertyValue( "DataBindingXpath", uno::Any(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]"))); xContentControlProps->setPropertyValue( "DataBindingStoreItemID", uno::Any(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}"))); xContentControlProps->setPropertyValue("Color", uno::Any(OUString("008000"))); xText->insertTextContent(xCursor, xContentControl, /*bAbsorb=*/true); // Then make sure that the specified properties are set: SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode(); SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL); auto pTextContentControl = static_txtattr_cast(pAttr); auto& rFormatContentControl = static_cast(pTextContentControl->GetAttr()); std::shared_ptr pContentControl = rFormatContentControl.GetContentControl(); CPPUNIT_ASSERT(pContentControl->GetDate()); CPPUNIT_ASSERT_EQUAL(OUString("M/d/yyyy"), pContentControl->GetDateFormat()); CPPUNIT_ASSERT_EQUAL(OUString("en-US"), pContentControl->GetDateLanguage()); CPPUNIT_ASSERT_EQUAL(OUString("2022-05-25T00:00:00Z"), pContentControl->GetCurrentDate()); CPPUNIT_ASSERT_EQUAL(OUString("DefaultPlaceholder_-1854013437"), pContentControl->GetPlaceholderDocPart()); CPPUNIT_ASSERT_EQUAL(OUString("xmlns:ns0='http://schemas.microsoft.com/vsto/samples' "), pContentControl->GetDataBindingPrefixMappings()); CPPUNIT_ASSERT_EQUAL(OUString("/ns0:employees[1]/ns0:employee[1]/ns0:hireDate[1]"), pContentControl->GetDataBindingXpath()); CPPUNIT_ASSERT_EQUAL(OUString("{241A8A02-7FFD-488D-8827-63FBE74E8BC9}"), pContentControl->GetDataBindingStoreItemID()); CPPUNIT_ASSERT_EQUAL(OUString("008000"), pContentControl->GetColor()); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testListIdState) { // Given a document with 3 paragraphs: an outer numbering on para 1 & 3, an inner numbering on // para 2: SwDoc* pDoc = createSwDoc(); SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); { SfxItemSetFixed aSet(pWrtShell->GetAttrPool()); SwNumRuleItem aItem("Numbering ABC"); aSet.Put(aItem); pWrtShell->SetAttrSet(aSet); } pWrtShell->SplitNode(); { SfxItemSetFixed aSet(pWrtShell->GetAttrPool()); SwNumRuleItem aItem("Numbering 123"); aSet.Put(aItem); pWrtShell->SetAttrSet(aSet); } pWrtShell->SplitNode(); { SfxItemSetFixed aSet(pWrtShell->GetAttrPool()); SwNumRuleItem aItem("Numbering ABC"); aSet.Put(aItem); pWrtShell->SetAttrSet(aSet); } // When checking if xml:id="..." needs writing for the first paragraph during ODT export: uno::Reference xPara(getParagraph(1), uno::UNO_QUERY); beans::PropertyState eState = xPara->getPropertyState("ListId"); // Then make sure that xml:id="..." gets written for para 1, as it'll be continued in para 3. // Without the accompanying fix in place, this test would have failed with: // - Expected: 0 (DIRECT_VALUE) // - Actual : 1 (DEFAULT_VALUE) // i.e. para 1 didn't write an xml:id="..." but para 3 referred to it using continue-list="...", // which is inconsistent. CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DIRECT_VALUE, eState); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerODFExport) { // Given a document with a red numbering portion, from the paragraph marker's format: load(DATA_DIRECTORY, "paragraph-marker.docx"); // When saving that as ODT + reload: reload("writer8", nullptr); // Then make sure that it still has the correct color: xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Without the accompanying fix in place, this test would have failed with: // - Expected: 00ff0000 (COL_LIGHTRED) // - Actual : ffffffff (COL_AUTO) // i.e. the custom "red" color was lost as RES_PARATR_LIST_AUTOFMT was not serialized to ODT. CPPUNIT_ASSERT_EQUAL( OUString("00ff0000"), getXPath(pXmlDoc, "//Special[@nType='PortionType::Number']/SwFont", "color")); } CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testParagraphMarkerFormattedRun) { // Given a document with a bold run and non-bold paragraph marker: load(DATA_DIRECTORY, "paragraph-marker-formatted-run.docx"); // When saving that as ODT + reload: reload("writer8", nullptr); // Then make sure that the numbering portion is still non-bold, matching Word: xmlDocUniquePtr pXmlDoc = parseLayoutDump(); // Without the accompanying fix in place, this test would have failed with: // - Expected: normal // - Actual : bold // i.e. the numbering portion was bold, while its weight should be normal. CPPUNIT_ASSERT_EQUAL( OUString("normal"), getXPath(pXmlDoc, "//Special[@nType='PortionType::Number']/SwFont", "weight")); } CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */