/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { class SwUiWriterTest9 : public SwModelTestBase { public: SwUiWriterTest9() : SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr) { } }; CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf158785) { // given a document with a hyperlink surrounded by N-dashes (–www.dordt.edu–) createSwDoc("tdf158785_hyperlink.fodt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); // go to the end of the hyperlink pWrtShell->SttEndDoc(/*bStart=*/false); pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); // get last point that will be part of the hyperlink (current position 1pt wide). Point aLogicL(pWrtShell->GetCharRect().Center()); Point aLogicR(aLogicL); // sanity check - we really are right by the hyperlink aLogicL.AdjustX(-1); SwContentAtPos aContentAtPos(IsAttrAtPos::InetAttr); pWrtShell->GetContentAtPos(aLogicL, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::InetAttr, aContentAtPos.eContentAtPos); // The test: the position of the N-dash should not indicate hyperlink properties // cursor pos would NOT be considered part of the hyperlink, but increase for good measure... aLogicR.AdjustX(1); pWrtShell->GetContentAtPos(aLogicR, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos); /* * tdf#111969: the beginning of the hyperlink should allow the right-click menu to remove it */ // move cursor (with no selection) to the start of the hyperlink - after the N-dash pWrtShell->SttEndDoc(/*bStart=*/true); pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); aLogicL = pWrtShell->GetCharRect().Center(); aLogicR = aLogicL; // sanity check - we really are right in front of the hyperlink aLogicL.AdjustX(-1); aContentAtPos = IsAttrAtPos::InetAttr; pWrtShell->GetContentAtPos(aLogicL, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos); aLogicR.AdjustX(1); aContentAtPos = IsAttrAtPos::InetAttr; pWrtShell->GetContentAtPos(aLogicR, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::InetAttr, aContentAtPos.eContentAtPos); // Remove the hyperlink dispatchCommand(mxComponent, u".uno:RemoveHyperlink"_ustr, {}); // The test: was the hyperlink actually removed? aContentAtPos = IsAttrAtPos::InetAttr; pWrtShell->GetContentAtPos(aLogicR, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf111969) { // given a document with a field surrounded by N-dashes (–date–) createSwDoc("tdf111969_field.fodt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); // go to the end of the field pWrtShell->SttEndDoc(/*bStart=*/false); pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); // get last point that will be part of the field (current position 1pt wide). Point aLogicL(pWrtShell->GetCharRect().Center()); Point aLogicR(aLogicL); // sanity check - we really are at the right edge of the field aLogicR.AdjustX(1); SwContentAtPos aContentAtPos(IsAttrAtPos::Field); pWrtShell->GetContentAtPos(aLogicR, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos); aLogicL.AdjustX(-1); aContentAtPos = IsAttrAtPos::Field; pWrtShell->GetContentAtPos(aLogicL, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::Field, aContentAtPos.eContentAtPos); // the test: simulate a right-click of a mouse which sets the cursor and then acts on that pos. pWrtShell->SwCursorShell::SetCursor(aLogicL, false, /*Block=*/false, /*FieldInfo=*/true); CPPUNIT_ASSERT(pWrtShell->GetCurField(true)); /* * An edge case at the start of a field - don't start the field menu on the first N-dash */ // go to the start of the field pWrtShell->SttEndDoc(/*bStart=*/true); pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false); // get first point that will be part of the field (current position 1pt wide). aLogicL = pWrtShell->GetCharRect().Center(); aLogicR = aLogicL; // sanity check - we really are at the left edge of the field aLogicR.AdjustX(1); aContentAtPos = IsAttrAtPos::Field; pWrtShell->GetContentAtPos(aLogicR, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::Field, aContentAtPos.eContentAtPos); aLogicL.AdjustX(-1); aContentAtPos = IsAttrAtPos::Field; pWrtShell->GetContentAtPos(aLogicL, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos); // the test: simulate a right-click of a mouse (at the end-edge of the N-dash) // which sets the cursor and then acts on that pos. pWrtShell->SwCursorShell::SetCursor(aLogicL, false, /*Block=*/false, /*FieldInfo=*/true); CPPUNIT_ASSERT(!pWrtShell->GetCurField(true)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf111969B) { // given a document with a field surrounded by two N-dashes (––date––) createSwDoc("tdf111969_fieldB.fodt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); // go to the start of the field pWrtShell->SttEndDoc(/*bStart=*/true); pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 2, /*bBasicCall=*/false); // get first point that will be part of the field (current position 1pt wide). Point aLogicL(pWrtShell->GetCharRect().Center()); Point aLogicR(aLogicL); // sanity check - we really are at the left edge of the field aLogicR.AdjustX(1); SwContentAtPos aContentAtPos(IsAttrAtPos::Field); pWrtShell->GetContentAtPos(aLogicR, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::Field, aContentAtPos.eContentAtPos); aLogicL.AdjustX(-1); aContentAtPos = IsAttrAtPos::Field; pWrtShell->GetContentAtPos(aLogicL, aContentAtPos); CPPUNIT_ASSERT_EQUAL(IsAttrAtPos::NONE, aContentAtPos.eContentAtPos); // the test: simulate a right-click of a mouse (at the end-edge of the second N-dash) // which sets the cursor and then acts on that pos. pWrtShell->SwCursorShell::SetCursor(aLogicL, false, /*Block=*/false, /*FieldInfo=*/true); CPPUNIT_ASSERT(!pWrtShell->GetCurField(true)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159049) { // The document contains a shape which has a text with a line break. When copying the text to // clipboard the line break was missing in the RTF flavor of the clipboard. createSwDoc("tdf159049_LineBreakRTFClipboard.fodt"); CPPUNIT_ASSERT_EQUAL(1, getShapes()); selectShape(1); // Bring shape into text edit mode SwXTextDocument* pTextDoc = getSwTextDoc(); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_RETURN); Scheduler::ProcessEventsToIdle(); // Copy text dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); dispatchCommand(mxComponent, u".uno:Copy"_ustr, {}); // Deactivate text edit mode ... pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_ESCAPE); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_ESCAPE); Scheduler::ProcessEventsToIdle(); // ... and deselect shape. pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_ESCAPE); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_ESCAPE); Scheduler::ProcessEventsToIdle(); // Paste special as RTF uno::Sequence aArgs(comphelper::InitPropertySequence( { { "SelectedFormat", uno::Any(static_cast(SotClipboardFormatId::RTF)) } })); dispatchCommand(mxComponent, u".uno:ClipboardFormatItems"_ustr, aArgs); // Without fix Actual was "Abreakhere", the line break \n was missing. CPPUNIT_ASSERT_EQUAL(u"Abreak\nhere"_ustr, getParagraph(1)->getString()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf135083) { createSwDoc("tdf135083-simple-text-plus-list.fodt"); dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); dispatchCommand(mxComponent, u".uno:Copy"_ustr, {}); // Paste special as RTF uno::Sequence aArgs(comphelper::InitPropertySequence( { { u"SelectedFormat"_ustr, uno::Any(static_cast(SotClipboardFormatId::RTF)) } })); dispatchCommand(mxComponent, u".uno:ClipboardFormatItems"_ustr, aArgs); auto xLastPara = getParagraph(3); CPPUNIT_ASSERT_EQUAL(u"dolor"_ustr, xLastPara->getString()); // Without the fix in place, the last paragraph would loose its settings. ListId would be empty. CPPUNIT_ASSERT(!getProperty(xLastPara, u"ListId"_ustr).isEmpty()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testHiddenSectionsAroundPageBreak) { createSwDoc("hiddenSectionsAroundPageBreak.fodt"); CPPUNIT_ASSERT_EQUAL(1, getPages()); auto xModel(mxComponent.queryThrow()); auto xTextViewCursorSupplier( xModel->getCurrentController().queryThrow()); auto xCursor(xTextViewCursorSupplier->getViewCursor().queryThrow()); // Make sure that the page style is set correctly xCursor->jumpToFirstPage(); CPPUNIT_ASSERT_EQUAL(u"Landscape"_ustr, getProperty(xCursor, u"PageStyleName"_ustr)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159565) { // Given a document with a hidden section in the beginning, additionally containing a frame createSwDoc("FrameInHiddenSection.fodt"); dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); // Check that the selection covers the whole visible text auto xModel(mxComponent.queryThrow()); auto xSelSupplier(xModel->getCurrentController().queryThrow()); auto xSelections(xSelSupplier->getSelection().queryThrow()); CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSelections->getCount()); auto xSelection(xSelections->getByIndex(0).queryThrow()); // Without the fix, this would fail - there was no selection CPPUNIT_ASSERT_EQUAL(u"" SAL_NEWLINE_STRING SAL_NEWLINE_STRING "ipsum"_ustr, xSelection->getString()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159816) { createSwDoc(); SwDoc* pDoc = getSwDoc(); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); // Add 5 empty paragraphs pWrtShell->SplitNode(); pWrtShell->SplitNode(); pWrtShell->SplitNode(); pWrtShell->SplitNode(); pWrtShell->SplitNode(); // Add a bookmark at the very end IDocumentMarkAccess& rIDMA(*pDoc->getIDocumentMarkAccess()); rIDMA.makeMark(*pWrtShell->GetCursor(), u"Mark"_ustr, IDocumentMarkAccess::MarkType::BOOKMARK, sw::mark::InsertMode::New); // Get coordinates of the end point in the document SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); SwFrame* pPage = pLayout->Lower(); SwFrame* pBody = pPage->GetLower(); SwFrame* pLastPara = pBody->GetLower()->GetNext()->GetNext()->GetNext()->GetNext()->GetNext(); Point ptTo = pLastPara->getFrameArea().BottomRight(); pWrtShell->SelAll(); // Drag-n-drop to its own end rtl::Reference xTransfer = new SwTransferable(*pWrtShell); // Without the fix, this would crash: either in CopyFlyInFlyImpl (tdf#159813): // Assertion failed: !pCopiedPaM || pCopiedPaM->End()->GetNode() == rRg.aEnd.GetNode() // or in BigPtrArray::operator[] (tdf#159816): // Assertion failed: idx < m_nSize xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf34804) { createSwDoc(); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); // Simulate a keyboard shortcut to SID_ATTR_CHAR_COLOR2 (which must use the shared button color) dispatchCommand(mxComponent, u".uno:FontColor"_ustr, {}); pWrtShell->Insert(u"New World!"_ustr); const uno::Reference xRun = getRun(getParagraph(1, "New World!"), 1); // (This test assumes that nothing in the unit tests has modified the app's recent font color) // COL_DEFAULT_FONT is the default red color for the fontColor button on the toolbar. CPPUNIT_ASSERT_EQUAL(COL_DEFAULT_FONT, getProperty(xRun, u"CharColor"_ustr)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf139631) { // Unit test for tdf#139631 // Test to see if preceding space is cut when cutting a word with track changes (redline) on createSwDoc(); SwDoc* pDoc = getSwDoc(); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); pWrtShell->Insert(u"New World!\""_ustr); // Assert that the string, New World!", is inserted correctly into the document CPPUNIT_ASSERT_EQUAL(u"New World!\""_ustr, getParagraph(1)->getString()); // Enable redline dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {}); CPPUNIT_ASSERT(pDoc->getIDocumentRedlineAccess().IsRedlineOn()); // Hide redline changes dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {}); CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines()); pWrtShell->Left(SwCursorSkipMode::Chars, false, 2, false); // Select and cut "World" from string pWrtShell->Left(SwCursorSkipMode::Chars, true, 5, false); dispatchCommand(mxComponent, u".uno:Cut"_ustr, {}); xmlDocUniquePtr pXmlDoc = parseLayoutDump(); pXmlDoc = parseLayoutDump(); // Verifies that the leading space before "World" was also cut assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwParaPortion", "portion", u"New!\""); // Reset to initial string dispatchCommand(mxComponent, u".uno:Undo"_ustr, {}); pXmlDoc = parseLayoutDump(); assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwParaPortion", "portion", u"New World!\""); pWrtShell->EndPara(false); pWrtShell->Left(SwCursorSkipMode::Chars, false, 1, false); // Replace ! with . pWrtShell->Left(SwCursorSkipMode::Chars, true, 1, false); pWrtShell->Delete(); pWrtShell->Insert(u"."_ustr); pXmlDoc = parseLayoutDump(); assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwParaPortion", "portion", u"New World.\""); pWrtShell->Left(SwCursorSkipMode::Chars, false, 1, false); // Select and cut "World" from string pWrtShell->Left(SwCursorSkipMode::Chars, true, 5, false); dispatchCommand(mxComponent, u".uno:Cut"_ustr, {}); pXmlDoc = parseLayoutDump(); // Without the test in place, the leading space before "World" is not also cut. // Expected: New." // Actual: New ." assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/SwParaPortion/SwLineLayout/SwParaPortion", "portion", u"New.\""); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf151710) { createSwDoc(); // Check that the particular setting is turned on by default const SwViewOption* pVwOpt = getSwDocShell()->GetWrtShell()->GetViewOptions(); CPPUNIT_ASSERT(pVwOpt); CPPUNIT_ASSERT(pVwOpt->IsEncloseWithCharactersOn()); // Localized quotation marks SvxAutoCorrect* pACorr = SvxAutoCorrCfg::Get().GetAutoCorrect(); CPPUNIT_ASSERT(pACorr); LanguageType eLang = Application::GetSettings().GetLanguageTag().getLanguageType(); OUString sStartSingleQuote{ pACorr->GetQuote('\'', true, eLang) }; OUString sEndSingleQuote{ pACorr->GetQuote('\'', false, eLang) }; OUString sStartDoubleQuote{ pACorr->GetQuote('\"', true, eLang) }; OUString sEndDoubleQuote{ pACorr->GetQuote('\"', false, eLang) }; // Insert some text to work with uno::Sequence aArgsInsert( comphelper::InitPropertySequence({ { "Text", uno::Any(u"abcd"_ustr) } })); dispatchCommand(mxComponent, u".uno:InsertText"_ustr, aArgsInsert); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); CPPUNIT_ASSERT_EQUAL(u"abcd"_ustr, xTextDocument->getText()->getString()); // Successfully enclose the text; afterwards the selection should exist with the new // enclosed text dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); SwXTextDocument* pTextDoc = getSwTextDoc(); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '(', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"(abcd)"_ustr, xTextDocument->getText()->getString()); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '[', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"[(abcd)]"_ustr, xTextDocument->getText()->getString()); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '{', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"{[(abcd)]}"_ustr, xTextDocument->getText()->getString()); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\'', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(OUString(sStartSingleQuote + "{[(abcd)]}" + sEndSingleQuote), xTextDocument->getText()->getString()); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\"', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(OUString(sStartDoubleQuote + sStartSingleQuote + "{[(abcd)]}" + sEndSingleQuote + sEndDoubleQuote), xTextDocument->getText()->getString()); // Disable the setting and check that enclosing doesn't happen anymore const_cast(pVwOpt)->SetEncloseWithCharactersOn(false); CPPUNIT_ASSERT(!pVwOpt->IsEncloseWithCharactersOn()); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '(', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"("_ustr, xTextDocument->getText()->getString()); dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '[', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"["_ustr, xTextDocument->getText()->getString()); dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '{', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"{"_ustr, xTextDocument->getText()->getString()); dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\'', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(sStartSingleQuote, xTextDocument->getText()->getString()); dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {}); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, '\"', 0); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(sStartDoubleQuote, xTextDocument->getText()->getString()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159054_disableOutlineNumbering) { createSwDoc("tdf159054_disableOutlineNumbering.docx"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); const uno::Reference xPara1 = getParagraph(1, u"Heading A"_ustr); const uno::Reference xPara2 = getParagraph(2, u"Heading B"_ustr); const uno::Reference xPara3 = getParagraph(3, u"Heading C"_ustr); CPPUNIT_ASSERT_EQUAL(u"A."_ustr, getProperty(xPara1, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u"B."_ustr, getProperty(xPara2, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u"C."_ustr, getProperty(xPara3, u"ListLabelString"_ustr)); // select (at least parts) of the first two paragraphs pWrtShell->Down(/*bSelect=*/true, /*nCount=*/1, /*bBasicCall=*/true); // on the selection, simulate pressing the toolbar button to toggle OFF numbering dispatchCommand(mxComponent, u".uno:DefaultNumbering"_ustr, {}); // the selected paragraphs should definitely have the list label removed CPPUNIT_ASSERT_EQUAL(u""_ustr, getProperty(xPara1, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u""_ustr, getProperty(xPara2, u"ListLabelString"_ustr)); // the third paragraph must retain the existing numbering format CPPUNIT_ASSERT_EQUAL(u"A."_ustr, getProperty(xPara3, u"ListLabelString"_ustr)); // on the selection, simulate pressing the toolbar button to toggle ON numbering again dispatchCommand(mxComponent, u".uno:DefaultNumbering"_ustr, {}); // the outline numbering format must be re-applied to the first two paragraphs CPPUNIT_ASSERT_EQUAL(u"A."_ustr, getProperty(xPara1, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u"B."_ustr, getProperty(xPara2, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u"C."_ustr, getProperty(xPara3, u"ListLabelString"_ustr)); // on the selection, simulate a right click - list - No list dispatchCommand(mxComponent, u".uno:RemoveBullets"_ustr, {}); // the selected paragraphs should definitely have the list label removed CPPUNIT_ASSERT_EQUAL(u""_ustr, getProperty(xPara1, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u""_ustr, getProperty(xPara2, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(u"A."_ustr, getProperty(xPara3, u"ListLabelString"_ustr)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf158375_dde_disable) { std::shared_ptr pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Security::Scripting::DisableActiveContent::set(true, pBatch); pBatch->commit(); comphelper::ScopeGuard g([] { std::shared_ptr _pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Security::Scripting::DisableActiveContent::set(false, _pBatch); _pBatch->commit(); }); createSwDoc(); SwDoc* pDoc = getSwDoc(); // force the AppName to enable DDE, it is not there for test runs Application::SetAppName(u"soffice"_ustr); // temp copy for the file that will be used as a reference for DDE link // this file includes a section named "Section1" with text inside createTempCopy(u"tdf158375_dde_reference.fodt"); comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getSwDocShell()->getEmbeddedObjectContainer(); rEmbeddedObjectContainer.setUserAllowsLinkUpdate(true); // create a section with DDE link uno::Reference xFactory(mxComponent, uno::UNO_QUERY); uno::Reference xTextSectionProps( xFactory->createInstance(u"com.sun.star.text.TextSection"_ustr), uno::UNO_QUERY); uno::Sequence aNames{ u"DDECommandFile"_ustr, u"DDECommandType"_ustr, u"DDECommandElement"_ustr, u"IsAutomaticUpdate"_ustr, u"IsProtected"_ustr }; uno::Sequence aValues{ uno::Any(u"soffice"_ustr), uno::Any(maTempFile.GetURL()), uno::Any(u"Section1"_ustr), uno::Any(true), uno::Any(true) }; uno::Reference rMultiPropSet(xTextSectionProps, uno::UNO_QUERY); rMultiPropSet->setPropertyValues(aNames, aValues); // insert the TextSection with DDE link uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xTextRange = xTextDocument->getText(); uno::Reference xText = xTextRange->getText(); uno::Reference xCursor(xText->createTextCursor(), uno::UNO_QUERY); xText->insertTextContent( xCursor, uno::Reference(xTextSectionProps, uno::UNO_QUERY), false); CPPUNIT_ASSERT_EQUAL( size_t(1), pDoc->getIDocumentLinksAdministration().GetLinkManager().GetLinks().size()); pDoc->getIDocumentLinksAdministration().GetLinkManager().UpdateAllLinks(false, false, nullptr, u""_ustr); uno::Reference xTextSectionsSupplier(mxComponent, uno::UNO_QUERY); uno::Reference xSections(xTextSectionsSupplier->getTextSections(), uno::UNO_QUERY); uno::Reference xSection(xSections->getByIndex(0), uno::UNO_QUERY); // make sure there's no text in the section after UpdateAllLinks, since // DisableActiveContent disables DDE links. CPPUNIT_ASSERT_EQUAL(u""_ustr, xSection->getAnchor()->getString()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf158375_ole_object_disable) { std::shared_ptr pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Security::Scripting::DisableActiveContent::set(true, pBatch); pBatch->commit(); comphelper::ScopeGuard g([] { std::shared_ptr _pBatch( comphelper::ConfigurationChanges::create()); officecfg::Office::Common::Security::Scripting::DisableActiveContent::set(false, _pBatch); _pBatch->commit(); }); // Enable LOK mode, otherwise OCommonEmbeddedObject::SwitchStateTo_Impl() will throw when it // finds out that the test runs headless. comphelper::LibreOfficeKit::setActive(); // Load a document with a Draw doc in it. createSwDoc("ole-save-while-edit.odt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); selectShape(1); // attempt to edit the OLE object. pWrtShell->LaunchOLEObj(); // it shouldn't switch because the current configuration // (DisableActiveContent) prohibits OLE objects changing to states other // then LOADED auto xShape = getShape(1); uno::Reference xEmbedSupplier(xShape, uno::UNO_QUERY); auto xEmbeddedObj = xEmbedSupplier->getExtendedControlOverEmbeddedObject(); CPPUNIT_ASSERT_EQUAL(embed::EmbedStates::LOADED, xEmbeddedObj->getCurrentState()); // Dispose the document while LOK is still active to avoid leaks. mxComponent->dispose(); mxComponent.clear(); comphelper::LibreOfficeKit::setActive(false); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf146190) { // Given a document with a number rule at the start of a paragraph and two drawing objects: createSwDoc("tdf146190.odt"); SwDocShell* pDocShell = getSwDocShell(); SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); const SdrMarkList& rMrkList = pWrtShell->GetDrawView()->GetMarkedObjectList(); // Assert the current cursor position has a number rule and is at the start of a paragraph: pWrtShell->SttEndDoc(/*bStt=*/true); CPPUNIT_ASSERT(pWrtShell->GetNumRuleAtCurrCursorPos()); CPPUNIT_ASSERT(pWrtShell->IsSttOfPara()); // Then go to "Shape 1" drawing object using the GotoDrawingObject function: pWrtShell->GotoDrawingObject(u"Shape 1"); CPPUNIT_ASSERT_EQUAL(u"Shape 1"_ustr, rMrkList.GetMark(0)->GetMarkedSdrObj()->GetName()); // Move to the next drawing object by Tab key press: SwXTextDocument* pTextDoc = getSwTextDoc(); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); Scheduler::ProcessEventsToIdle(); // Without the fix in place, this test would have failed with: // equality assertion failed // - Expected: Shape 2 // - Actual : Shape 1 // i.e. Tab did not move to the next drawing object CPPUNIT_ASSERT_EQUAL(u"Shape 2"_ustr, rMrkList.GetMark(0)->GetMarkedSdrObj()->GetName()); // Tab key press should now select 'Shape 1': pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); Scheduler::ProcessEventsToIdle(); CPPUNIT_ASSERT_EQUAL(u"Shape 1"_ustr, rMrkList.GetMark(0)->GetMarkedSdrObj()->GetName()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf160898) { // Given a document with a 1-cell table in another 1-cell table: createSwDoc("table-in-table.fodt"); SwDocShell* pDocShell = getSwDocShell(); SwWrtShell* pWrtShell = pDocShell->GetWrtShell(); // Move to the normally hidden paragraph inside the outer table cell, following the inner table pWrtShell->Down(false, 2); // Without the fix, this would crash: pWrtShell->SelAll(); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf161172) { // Given a paragraph manually made a member of a list: createSwDoc("tdf161172.fodt"); auto para = getParagraph(1); // Check initial state: the first paragraph has "No_list" para style, "Num_1" numbering style, // numbering level 0, and "Num1_lvl1_1" numbering label. CPPUNIT_ASSERT_EQUAL(u"No_list"_ustr, getProperty(para, u"ParaStyleName"_ustr)); CPPUNIT_ASSERT_EQUAL(u"Num_1"_ustr, getProperty(para, u"NumberingStyleName"_ustr)); CPPUNIT_ASSERT_EQUAL(u"Num1_lvl1_1"_ustr, getProperty(para, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty(para, u"NumberingLevel"_ustr)); // Assign "Num_1_lvl2" paragraph style to the first paragraph. The style is associated with // "Num_1" numbering style, level 1. dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, { comphelper::makePropertyValue(u"FamilyName"_ustr, u"ParagraphStyles"_ustr), comphelper::makePropertyValue(u"Style"_ustr, u"Num_1_lvl2"_ustr) }); // Check that the respective properties got correctly applied CPPUNIT_ASSERT_EQUAL(u"Num_1_lvl2"_ustr, getProperty(para, u"ParaStyleName"_ustr)); CPPUNIT_ASSERT_EQUAL(u"Num_1"_ustr, getProperty(para, u"NumberingStyleName"_ustr)); CPPUNIT_ASSERT_EQUAL(u"Num1_lvl2_1"_ustr, getProperty(para, u"ListLabelString"_ustr)); CPPUNIT_ASSERT_EQUAL(sal_Int16(1), getProperty(para, u"NumberingLevel"_ustr)); // Undo dispatchCommand(mxComponent, u".uno:Undo"_ustr, {}); // Check that the numbering properties got correctly restored CPPUNIT_ASSERT_EQUAL(u"No_list"_ustr, getProperty(para, u"ParaStyleName"_ustr)); CPPUNIT_ASSERT_EQUAL(u"Num_1"_ustr, getProperty(para, u"NumberingStyleName"_ustr)); // Without the fix, this would fail with // - Expected: Num1_lvl1_1 // - Actual : Num1_lvl2_1 CPPUNIT_ASSERT_EQUAL(u"Num1_lvl1_1"_ustr, getProperty(para, u"ListLabelString"_ustr)); // Without the fix, this would fail with // - Expected: 0 // - Actual : 1 CPPUNIT_ASSERT_EQUAL(sal_Int16(0), getProperty(para, u"NumberingLevel"_ustr)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf144752) { // Undoing/redoing a replacement must select the new text createSwDoc(); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); emulateTyping(u"Some Text"); CPPUNIT_ASSERT(!pWrtShell->HasSelection()); // Select "Text", and replace with "Word" pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect*/ true, 4, /*bBasicCall*/ false); pWrtShell->Replace(u"Word"_ustr, false); pWrtShell->EndOfSection(); CPPUNIT_ASSERT(!pWrtShell->HasSelection()); // Undo and check, that the "Text" is selected dispatchCommand(mxComponent, u".uno:Undo"_ustr, {}); // Without the fix, this would fail CPPUNIT_ASSERT(pWrtShell->HasSelection()); CPPUNIT_ASSERT_EQUAL(u"Text"_ustr, pWrtShell->GetSelText()); // Redo and check, that the "Word" is selected dispatchCommand(mxComponent, u".uno:Redo"_ustr, {}); CPPUNIT_ASSERT(pWrtShell->HasSelection()); CPPUNIT_ASSERT_EQUAL(u"Word"_ustr, pWrtShell->GetSelText()); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf162326_Pargraph) { createSwDoc("tdf162326.odt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty(getRun(getParagraph(1), 1), u"CharWeight"_ustr)); CPPUNIT_ASSERT_EQUAL( awt::FontSlant_ITALIC, getProperty(getRun(getParagraph(2), 2), u"CharPosture"_ustr)); CPPUNIT_ASSERT_EQUAL(short(1), getProperty(getRun(getParagraph(3), 2), u"CharUnderline"_ustr)); pWrtShell->Down(/*bSelect=*/true, 3); dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, { comphelper::makePropertyValue(u"FamilyName"_ustr, u"ParagraphStyles"_ustr), comphelper::makePropertyValue(u"Style"_ustr, u"Footnote"_ustr), comphelper::makePropertyValue(u"KeyModifier"_ustr, uno::Any(KEY_MOD1)) }); CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty(getRun(getParagraph(1), 1), u"CharWeight"_ustr)); CPPUNIT_ASSERT_THROW(getRun(getParagraph(2), 2), css::container::NoSuchElementException); CPPUNIT_ASSERT_THROW(getRun(getParagraph(3), 2), css::container::NoSuchElementException); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf162326_Character) { createSwDoc("tdf162326.odt"); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); CPPUNIT_ASSERT(pWrtShell); CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD, getProperty(getRun(getParagraph(1), 1), u"CharWeight"_ustr)); CPPUNIT_ASSERT_EQUAL( awt::FontSlant_ITALIC, getProperty(getRun(getParagraph(2), 2), u"CharPosture"_ustr)); CPPUNIT_ASSERT_EQUAL(short(1), getProperty(getRun(getParagraph(3), 2), u"CharUnderline"_ustr)); pWrtShell->Down(/*bSelect=*/true, 3); //add Ctrl/MOD_1 dispatchCommand(mxComponent, u".uno:StyleApply"_ustr, { comphelper::makePropertyValue(u"FamilyName"_ustr, u"CharacterStyles"_ustr), comphelper::makePropertyValue(u"Style"_ustr, u"Definition"_ustr), comphelper::makePropertyValue(u"KeyModifier"_ustr, uno::Any(KEY_MOD1)) }); CPPUNIT_ASSERT_EQUAL(awt::FontWeight::NORMAL, getProperty(getRun(getParagraph(1), 1), u"CharWeight"_ustr)); CPPUNIT_ASSERT_THROW(getRun(getParagraph(2), 2), css::container::NoSuchElementException); //last runs are not changed because the selection ends at the beginning of that paragraph CPPUNIT_ASSERT_EQUAL(short(1), getProperty(getRun(getParagraph(3), 2), u"CharUnderline"_ustr)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf163340) { createSwDoc("tdf163340.odt"); uno::Reference xModel(mxComponent, uno::UNO_QUERY); uno::Reference xTextDocument(mxComponent, uno::UNO_QUERY); uno::Reference xText = xTextDocument->getText(); uno::Reference xSelSupplier(xModel->getCurrentController(), uno::UNO_QUERY_THROW); uno::Reference xParaCursor(xTextDocument->getText()->createTextCursor(), uno::UNO_QUERY); for (int i = 0; i < 14; i++) xParaCursor->gotoNextParagraph(false); xParaCursor->gotoEndOfParagraph(true); xSelSupplier->select(uno::Any(xParaCursor)); CPPUNIT_ASSERT_EQUAL(u"A."_ustr, getProperty(xParaCursor, u"ListLabelString"_ustr)); dispatchCommand(mxComponent, u".uno:Copy"_ustr, {}); xParaCursor = uno::Reference(xText->createTextCursor(), uno::UNO_QUERY); for (int i = 0; i < 3; i++) xParaCursor->gotoNextParagraph(false); xParaCursor->gotoEndOfParagraph(true); CPPUNIT_ASSERT_EQUAL(u"1."_ustr, getProperty(xParaCursor, u"ListLabelString"_ustr)); xSelSupplier->select(uno::Any(xParaCursor)); dispatchCommand(mxComponent, u".uno:Paste"_ustr, {}); CPPUNIT_ASSERT_EQUAL(u"A."_ustr, getProperty(xParaCursor, u"ListLabelString"_ustr)); } CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf159023) { createSwDoc(); SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); SwInsertTableOptions aTableOptions(SwInsertTableFlags::DefaultBorder, 0); pWrtShell->InsertTable(aTableOptions, /*nRows=*/2, /*nCols=*/2); pWrtShell->MoveTable(GotoPrevTable, fnTableStart); dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {}); dispatchCommand(mxComponent, u".uno:Copy"_ustr, {}); pWrtShell->InsertFootnote(u""_ustr); CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote()); dispatchCommand(mxComponent, u".uno:Paste"_ustr, {}); dispatchCommand(mxComponent, u".uno:GoLeft"_ustr, {}); dispatchCommand(mxComponent, u".uno:GoLeft"_ustr, {}); // Without the fix in place, this test would have crashed here CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote()); } } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */