sw/inc/doc.hxx | 8 +- sw/qa/extras/uiwriter/uiwriter8.cxx | 46 ++++++++++++- sw/source/core/doc/DocumentContentOperationsManager.cxx | 11 ++- sw/source/core/doc/docnum.cxx | 55 +++++++++++++++- 4 files changed, 109 insertions(+), 11 deletions(-)
New commits: commit 2bcaa374ea418cd81f9dbf62cd7e896f5977992a Author: Michael Stahl <michael.st...@allotropia.de> AuthorDate: Fri May 17 13:58:41 2024 +0200 Commit: Michael Stahl <michael.st...@allotropia.de> CommitDate: Fri May 17 19:24:29 2024 +0200 tdf#161137 sw: AutoText or Paste should copy paragraph indents for lists The first commit made the start and end node of the paste look like the list it was inserted into, but the middle nodes may have different paragraph styles and may have different left margin / first line indent. In addition to the SwNumRule, also copy any left margin or first line indent if it is effective on the node that the SwNumRule was taken from. Now all the list labels should be in the same place. Change-Id: Ia5794687ea0ff542f23289b1ca63ea99dae85bc3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/167777 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.st...@allotropia.de> diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index 659af3ba1e91..b1b68bec2dba 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -1073,7 +1073,9 @@ public: const SwNumRule&, SetNumRuleMode mode, SwRootFrame const* pLayout = nullptr, - const OUString& sContinuedListId = OUString()); + const OUString& sContinuedListId = OUString(), + SvxTextLeftMarginItem const* pTextLeftMarginToPropagate = nullptr, + SvxFirstLineIndentItem const* pFirstLineIndentToPropagate = nullptr); void SetCounted(const SwPaM&, bool bCounted, SwRootFrame const* pLayout); void MakeUniqueNumRules(const SwPaM & rPaM); @@ -1151,7 +1153,9 @@ public: int nNonEmptyAllowed, OUString& sListId, SwRootFrame const* pLayout, - const bool bInvestigateStartNode = false ); + const bool bInvestigateStartNode = false, + SvxTextLeftMarginItem const** o_ppTextLeftMargin = nullptr, + SvxFirstLineIndentItem const** o_ppFirstLineIndent = nullptr); // Paragraphs without numbering but with indents. bool NoNum( const SwPaM& ); diff --git a/sw/qa/extras/uiwriter/uiwriter8.cxx b/sw/qa/extras/uiwriter/uiwriter8.cxx index 2ff8bc3472b6..e1924b16a512 100644 --- a/sw/qa/extras/uiwriter/uiwriter8.cxx +++ b/sw/qa/extras/uiwriter/uiwriter8.cxx @@ -25,6 +25,7 @@ #include <frameformats.hxx> #include <tools/json_writer.hxx> #include <unotools/streamwrap.hxx> +#include <editeng/lrspitem.hxx> #include <sfx2/linkmgr.hxx> #include <wrtsh.hxx> @@ -877,7 +878,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) pWrtShell->FwdPara(); pWrtShell->EndPara(/*bSelect=*/false); // expands autotext (via F3) - pWrtShell->Insert(" dt"); + pWrtShell->Insert(" jacr"); SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_F3); @@ -886,6 +887,10 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) pWrtShell->SttEndDoc(/*bStt=*/true); pWrtShell->FwdPara(); + SwNumRule* pNumRule; + SvxTextLeftMarginItem const* pTextLeftMargin; + SvxFirstLineIndentItem const* pFirstLineIndent; + { SwTextNode& rNode{ *pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode() }; // numrule from paragraph style, but not from direct formatting @@ -902,7 +907,32 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false)); CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, true)); CPPUNIT_ASSERT_EQUAL(u"ListAndIndents"_ustr, rNode.GetTextColl()->GetName()); - CPPUNIT_ASSERT(rNode.GetText().startsWith("Item He heard quiet steps")); + CPPUNIT_ASSERT_EQUAL(u"Item We confirm receipt of your application material."_ustr, + rNode.GetText()); + pNumRule = rNode.GetNumRule(); + pTextLeftMargin = &rNode.GetAttr(RES_MARGIN_TEXTLEFT); + pFirstLineIndent = &rNode.GetAttr(RES_MARGIN_FIRSTLINE); + } + + pWrtShell->FwdPara(); + + { + SwTextNode& rNode{ *pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode() }; + auto pSet{ rNode.GetpSwAttrSet() }; + CPPUNIT_ASSERT(pSet); + // list id was set + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_LIST_ID, false)); + // middle paragraph was pasted - has numrule and indents applied directly + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_PARATR_NUMRULE, false)); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_FIRSTLINE, false)); + CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false)); + CPPUNIT_ASSERT_EQUAL(u"Default Paragraph Style"_ustr, rNode.GetTextColl()->GetName()); + CPPUNIT_ASSERT(rNode.GetText().startsWith("As more applicants applied")); + CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule()); + CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->GetTextLeft(), + rNode.GetAttr(RES_MARGIN_TEXTLEFT).GetTextLeft()); + CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffset(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset()); } pWrtShell->FwdPara(); @@ -923,7 +953,12 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, pSet->GetItemState(RES_MARGIN_TEXTLEFT, false)); CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, true)); CPPUNIT_ASSERT_EQUAL(u"ListAndIndents"_ustr, rNode.GetTextColl()->GetName()); - CPPUNIT_ASSERT_EQUAL(u""_ustr, rNode.GetText()); // this is a new empty paragraph + CPPUNIT_ASSERT(rNode.GetText().endsWith("as soon as we have come to a decision.")); + CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule()); + CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->GetTextLeft(), + rNode.GetAttr(RES_MARGIN_TEXTLEFT).GetTextLeft()); + CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffset(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset()); } pWrtShell->FwdPara(); @@ -945,6 +980,11 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest8, testInsertAutoTextIntoListFromParaStyle) CPPUNIT_ASSERT_EQUAL(SfxItemState::SET, pSet->GetItemState(RES_MARGIN_TEXTLEFT, true)); CPPUNIT_ASSERT_EQUAL(u"ListAndIndents"_ustr, rNode.GetTextColl()->GetName()); CPPUNIT_ASSERT_EQUAL(u"more"_ustr, rNode.GetText()); // pre-exising list item + CPPUNIT_ASSERT_EQUAL(pNumRule, rNode.GetNumRule()); + CPPUNIT_ASSERT_EQUAL(pTextLeftMargin->GetTextLeft(), + rNode.GetAttr(RES_MARGIN_TEXTLEFT).GetTextLeft()); + CPPUNIT_ASSERT_EQUAL(pFirstLineIndent->GetTextFirstLineOffset(), + rNode.GetAttr(RES_MARGIN_FIRSTLINE).GetTextFirstLineOffset()); } } diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx index 1f7857b6e407..0e5e0db06be1 100644 --- a/sw/source/core/doc/DocumentContentOperationsManager.cxx +++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx @@ -5119,12 +5119,16 @@ bool DocumentContentOperationsManager::CopyImplImpl(SwPaM& rPam, SwPosition& rPo // bullet list. // Keep also the <ListId> value for possible propagation. OUString aListIdToPropagate; + SvxTextLeftMarginItem const* pTextLeftMarginToPropagate{nullptr}; + SvxFirstLineIndentItem const* pFirstLineIndentToPropagate{nullptr}; const SwNumRule* pNumRuleToPropagate = - rDoc.SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, nullptr, true ); + rDoc.SearchNumRule(rPos, false, true, false, 0, aListIdToPropagate, nullptr, + true, &pTextLeftMarginToPropagate, &pFirstLineIndentToPropagate); if ( !pNumRuleToPropagate ) { pNumRuleToPropagate = - rDoc.SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, nullptr, true ); + rDoc.SearchNumRule(rPos, false, false, false, 0, aListIdToPropagate, nullptr, + true, &pTextLeftMarginToPropagate, &pFirstLineIndentToPropagate); } // #i86492# // Do not propagate previous found list, if @@ -5524,7 +5528,8 @@ bool DocumentContentOperationsManager::CopyImplImpl(SwPaM& rPam, SwPosition& rPo // the paragraph style, in that case applying it again in mpAttrSet could // override indents, so avoid that. rDoc.SetNumRule(*pCopyPam, *pNumRuleToPropagate, - SwDoc::SetNumRuleMode::DontSetIfAlreadyApplied, nullptr, aListIdToPropagate); + SwDoc::SetNumRuleMode::DontSetIfAlreadyApplied, nullptr, aListIdToPropagate, + pTextLeftMarginToPropagate, pFirstLineIndentToPropagate); } rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx index 59893782fda4..adf0f5b9f699 100644 --- a/sw/source/core/doc/docnum.cxx +++ b/sw/source/core/doc/docnum.cxx @@ -46,6 +46,7 @@ #include <SwNodeNum.hxx> #include <list.hxx> #include <calbck.hxx> +#include <editeng/lrspitem.hxx> #include <comphelper/string.hxx> #include <comphelper/random.hxx> #include <o3tl/safeint.hxx> @@ -862,7 +863,9 @@ OUString SwDoc::SetNumRule( const SwPaM& rPam, const SwNumRule& rRule, SetNumRuleMode eMode, SwRootFrame const*const pLayout, - const OUString& sContinuedListId) + const OUString& sContinuedListId, + SvxTextLeftMarginItem const*const pTextLeftMarginToPropagate, + SvxFirstLineIndentItem const*const pFirstLineIndentToPropagate) { OUString sListId; @@ -982,6 +985,19 @@ OUString SwDoc::SetNumRule( const SwPaM& rPam, getIDocumentContentOperations().InsertPoolItem(temp, SwNumRuleItem(pNewOrChangedNumRule->GetName()), SetAttrMode::DEFAULT, pLayout); + // apply provided margins to get visually same result + if (pTextLeftMarginToPropagate) + { + getIDocumentContentOperations().InsertPoolItem(temp, + *pTextLeftMarginToPropagate, + SetAttrMode::DEFAULT, pLayout); + } + if (pFirstLineIndentToPropagate) + { + getIDocumentContentOperations().InsertPoolItem(temp, + *pFirstLineIndentToPropagate, + SetAttrMode::DEFAULT, pLayout); + } } } } @@ -991,6 +1007,18 @@ OUString SwDoc::SetNumRule( const SwPaM& rPam, getIDocumentContentOperations().InsertPoolItem(aPam, SwNumRuleItem(pNewOrChangedNumRule->GetName()), SetAttrMode::DEFAULT, pLayout); + if (pTextLeftMarginToPropagate) + { + getIDocumentContentOperations().InsertPoolItem(aPam, + *pTextLeftMarginToPropagate, + SetAttrMode::DEFAULT, pLayout); + } + if (pFirstLineIndentToPropagate) + { + getIDocumentContentOperations().InsertPoolItem(aPam, + *pFirstLineIndentToPropagate, + SetAttrMode::DEFAULT, pLayout); + } } } @@ -1648,7 +1676,9 @@ const SwNumRule * SwDoc::SearchNumRule(const SwPosition & rPos, int nNonEmptyAllowed, OUString& sListId, SwRootFrame const* pLayout, - const bool bInvestigateStartNode) + const bool bInvestigateStartNode, + SvxTextLeftMarginItem const** o_ppTextLeftMargin, + SvxFirstLineIndentItem const** o_ppFirstLineIndent) { const SwNumRule * pResult = nullptr; SwTextNode * pTextNd = rPos.GetNode().GetTextNode(); @@ -1685,9 +1715,28 @@ const SwNumRule * SwDoc::SearchNumRule(const SwPosition & rPos, ( ( bNum && pNumRule->Get(0).IsEnumeration()) || ( !bNum && pNumRule->Get(0).IsItemize() ) ) ) // #i22362#, #i29560# { - pResult = pTextNd->GetNumRule(); + pResult = pNumRule; // provide also the list id, to which the text node belongs. sListId = pTextNd->GetListId(); + // also get the margins that override the numrule + int const nListLevel{pTextNd->GetActualListLevel()}; + if ((o_ppTextLeftMargin || o_ppFirstLineIndent) + && 0 <= nListLevel + && pNumRule->Get(o3tl::narrowing<sal_uInt16>(nListLevel)) + .GetPositionAndSpaceMode() == SvxNumberFormat::LABEL_ALIGNMENT) + { + ::sw::ListLevelIndents const indents{pTextNd->AreListLevelIndentsApplicable()}; + if (!(indents & ::sw::ListLevelIndents::LeftMargin) + && o_ppTextLeftMargin) + { + *o_ppTextLeftMargin = &pTextNd->SwContentNode::GetAttr(RES_MARGIN_TEXTLEFT); + } + if (!(indents & ::sw::ListLevelIndents::FirstLine) + && o_ppFirstLineIndent) + { + *o_ppFirstLineIndent = &pTextNd->SwContentNode::GetAttr(RES_MARGIN_FIRSTLINE); + } + } } break;