From a593c27e8897280871dc310184ff568bf34a6ebe Mon Sep 17 00:00:00 2001 From: Oliver Specht Date: Tue, 10 Sep 2024 12:43:06 +0200 Subject: tdf#162326 remove character formats and styles on style apply Removes the character attributes and character styles when a paragraph or a character style is applied and the Ctrl button is pressed. Change-Id: I8b2809d1a2b91e501ed8a11ac9f3aebec6c12c47 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173154 Reviewed-by: Gabor Kelemen Tested-by: Gabor Kelemen Tested-by: Jenkins --- sw/inc/doc.hxx | 1 + sw/inc/editsh.hxx | 4 +- sw/inc/swtypes.hxx | 6 +- sw/qa/extras/uiwriter/data/tdf162326.odt | Bin 0 -> 10857 bytes sw/qa/extras/uiwriter/uiwriter9.cxx | 65 ++++++++++++++++++++- sw/source/core/crsr/findcoll.cxx | 2 +- .../core/doc/DocumentContentOperationsManager.cxx | 61 ++++++++++++++++++- sw/source/core/doc/docfmt.cxx | 25 ++++++++ sw/source/core/edit/edfcol.cxx | 5 +- .../core/inc/DocumentContentOperationsManager.hxx | 4 +- sw/source/core/txtnode/txtedt.cxx | 2 +- sw/source/uibase/app/docst.cxx | 10 +++- 12 files changed, 172 insertions(+), 13 deletions(-) create mode 100644 sw/qa/extras/uiwriter/data/tdf162326.odt (limited to 'sw') diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index a1bcea1eca4f..6e037f3878c9 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -814,6 +814,7 @@ public: SW_DLLPUBLIC bool SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset = true, const bool bResetListAttrs = false, + const bool bResetAllCharAttrs = false, SwRootFrame const* pLayout = nullptr); SwTextFormatColl* FindTextFormatCollByName( const OUString& rName ) const { return mpTextFormatCollTable->FindFormatByName(rName); } diff --git a/sw/inc/editsh.hxx b/sw/inc/editsh.hxx index 0de62a1d27de..0e9d8064901b 100644 --- a/sw/inc/editsh.hxx +++ b/sw/inc/editsh.hxx @@ -335,7 +335,9 @@ public: // #i62675# /// Add 2nd optional parameter - see also - SW_DLLPUBLIC void SetTextFormatColl(SwTextFormatColl*, const bool bResetListAttrs = false); + SW_DLLPUBLIC void SetTextFormatColl(SwTextFormatColl*, + const bool bResetListAttrs = false, + SetAttrMode nMode = SetAttrMode::DEFAULT); SW_DLLPUBLIC SwTextFormatColl *MakeTextFormatColl(const OUString &rFormatCollName, SwTextFormatColl *pDerivedFrom = nullptr); void FillByEx(SwTextFormatColl*); diff --git a/sw/inc/swtypes.hxx b/sw/inc/swtypes.hxx index 2a528403f2a4..f692dc91a0b1 100644 --- a/sw/inc/swtypes.hxx +++ b/sw/inc/swtypes.hxx @@ -151,11 +151,13 @@ enum class SetAttrMode /// for Undo, translated to SwInsertFlags::NOHINTEXPAND NOHINTEXPAND = 0x0100, /// don't change the cursor position - NO_CURSOR_CHANGE = 0x0200 + NO_CURSOR_CHANGE = 0x0200, + // remove all char attributes and char styles when para/char styles are applied + REMOVE_ALL_ATTR = 0x0400 }; namespace o3tl { - template<> struct typed_flags : is_typed_flags {}; + template<> struct typed_flags : is_typed_flags {}; } namespace sw { diff --git a/sw/qa/extras/uiwriter/data/tdf162326.odt b/sw/qa/extras/uiwriter/data/tdf162326.odt new file mode 100644 index 000000000000..9fb91e41896a Binary files /dev/null and b/sw/qa/extras/uiwriter/data/tdf162326.odt differ diff --git a/sw/qa/extras/uiwriter/uiwriter9.cxx b/sw/qa/extras/uiwriter/uiwriter9.cxx index f7bcf7e2af1a..e0acf8fd8468 100644 --- a/sw/qa/extras/uiwriter/uiwriter9.cxx +++ b/sw/qa/extras/uiwriter/uiwriter9.cxx @@ -14,6 +14,9 @@ #include #include #include + +#include +#include #include #include #include @@ -46,7 +49,6 @@ #include #include #include - #include #include @@ -736,6 +738,67 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf144752) CPPUNIT_ASSERT_EQUAL(u"Word"_ustr, pWrtShell->GetSelText()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest9, testTdf162326_Pargraph) +{ + createSwDoc("tdf162326.odt"); + SwXTextDocument* pDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pDoc); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->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"); + SwXTextDocument* pDoc = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pDoc); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->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)); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/crsr/findcoll.cxx b/sw/source/core/crsr/findcoll.cxx index 31a64aa3313f..2f633bd29186 100644 --- a/sw/source/core/crsr/findcoll.cxx +++ b/sw/source/core/crsr/findcoll.cxx @@ -60,7 +60,7 @@ int SwFindParaFormatColl::DoFind(SwPaM & rCursor, SwMoveFnCollection const & fnM else if( pReplColl ) { rCursor.GetDoc().SetTextFormatColl(rCursor, - const_cast(pReplColl), true, false, m_pLayout); + const_cast(pReplColl), true, false, false, m_pLayout); nRet = FIND_NO_RING; } return nRet; diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx index ce7bb41149dc..0f24abd95bc3 100644 --- a/sw/source/core/doc/DocumentContentOperationsManager.cxx +++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx @@ -230,7 +230,6 @@ namespace } rChgPos.SetContent( nContentPos ); } - } namespace sw @@ -3689,12 +3688,34 @@ bool DocumentContentOperationsManager::InsertPoolItem( SwRootFrame const*const pLayout, SwTextAttr **ppNewTextAttr) { + SwHistory* pHistory = nullptr; SwDataChanged aTmp( rRg ); std::unique_ptr pUndoAttr; if (m_rDoc.GetIDocumentUndoRedo().DoesUndo()) { m_rDoc.GetIDocumentUndoRedo().ClearRedo(); pUndoAttr.reset(new SwUndoAttr( rRg, rHt, nFlags )); + pHistory = &pUndoAttr->GetHistory(); + } + + if (nFlags & SetAttrMode::REMOVE_ALL_ATTR) + { + std::shared_ptr pDelSet = lcl_createDelSet(m_rDoc); + SwPosition aStart(*rRg.GetMark()->GetNode().GetContentNode(), rRg.GetMark()->GetContentIndex()); + SwPosition aEnd(*rRg.GetPoint()->GetNode().GetContentNode(), rRg.GetPoint()->GetContentIndex()); + sw::DocumentContentOperationsManager::ParaRstFormat aPara( + &aStart, &aEnd, pHistory, nullptr, nullptr /* //TODO: is layout required? m_rDoc.GetLayout()*/); + // aPara.pFormatColl = pPara->pFormatColl; + aPara.bReset = true; + // #i62675# + aPara.bResetListAttrs = false; + aPara.bResetAllCharAttrs = true; + aPara.pDelSet = pDelSet.get(); + m_rDoc.GetNodes().ForEach( + aStart.GetNode().GetIndex(), + aEnd.GetNode().GetIndex(), + ::sw::DocumentContentOperationsManager::lcl_RstTextAttr, + &aPara); } SfxItemSet aSet( m_rDoc.GetAttrPool(), rHt.Which(), rHt.Which() ); @@ -4205,6 +4226,44 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl( SwTextBoxHelper::restoreLinks(aSet, aVecSwFrameFormat, aOldTextBoxes); } +/* + create ItemSet to be used in ParaRstFormat +*/ +std::shared_ptr DocumentContentOperationsManager::lcl_createDelSet(SwDoc& rDoc) +{ + std::shared_ptr pDelSet(new SfxItemSetFixed(rDoc.GetAttrPool())); + o3tl::sorted_vector aAttribs; + + constexpr std::pair aResetableSetRange[] = { + // tdf#40496: we don't want to change writing direction, so exclude RES_FRAMEDIR: + { RES_TXTATR_CHARFMT,RES_TXTATR_CHARFMT }, + { RES_FRMATR_BEGIN, RES_FRAMEDIR - 1 }, + { RES_FRAMEDIR + 1, RES_FRMATR_END - 1 }, + { RES_CHRATR_BEGIN, RES_CHRATR_LANGUAGE - 1 }, + { RES_CHRATR_LANGUAGE + 1, RES_CHRATR_CJK_LANGUAGE - 1 }, + { RES_CHRATR_CJK_LANGUAGE + 1, RES_CHRATR_CTL_LANGUAGE - 1 }, + { RES_CHRATR_CTL_LANGUAGE + 1, RES_CHRATR_END - 1 }, + { RES_PARATR_BEGIN, RES_PARATR_END - 1 }, + { RES_PARATR_LIST_AUTOFMT, RES_PARATR_LIST_AUTOFMT }, + { RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER }, + { RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 1 }, + }; + for (const auto& [nBegin, nEnd] : aResetableSetRange) + { + for (sal_uInt16 i = nBegin; i <= nEnd; ++i) + aAttribs.insert( i ); + } + for( auto it = aAttribs.rbegin(); it != aAttribs.rend(); ++it ) + { + if( POOLATTR_END > *it ) + pDelSet->Put( *GetDfltAttr( *it )); + } + return pDelSet; +} + /* * Reset the text's hard formatting */ diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx index b7f8d4ba7791..8116bb80b424 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -1020,6 +1020,22 @@ static bool lcl_SetTextFormatColl( SwNode* pNode, void* pArgs ) SwTextFormatColl* pFormat = pPara->pFormatColl; if ( pPara->bReset ) { + if (pCNd->IsTextNode() && pPara->bResetAllCharAttrs && pPara->pDelSet && pPara->pDelSet->Count()) + { + //TODO: copy to select the text node completely + SwPosition aStart(*pCNd, 0); + SwPosition aEnd(*pCNd, pCNd->GetTextNode()->GetText().getLength()); + sw::DocumentContentOperationsManager::ParaRstFormat aPara( + &aStart, &aEnd, pPara->pHistory, nullptr, pPara->pLayout); + aPara.pFormatColl = pPara->pFormatColl; + aPara.bReset = pPara->bReset; + // #i62675# + aPara.bResetListAttrs = pPara->bResetListAttrs; + aPara.bResetAllCharAttrs = pPara->bResetAllCharAttrs; + aPara.pDelSet = pPara->pDelSet; + sw::DocumentContentOperationsManager::lcl_RstTextAttr(pCNd, &aPara); + } + lcl_RstAttr(pCNd, pPara); // #i62675# check, if paragraph style has changed @@ -1088,6 +1104,7 @@ bool SwDoc::SetTextFormatColl(const SwPaM &rRg, SwTextFormatColl *pFormat, const bool bReset, const bool bResetListAttrs, + const bool bResetAllCharAttrs, SwRootFrame const*const pLayout) { SwDataChanged aTmp( rRg ); @@ -1104,12 +1121,20 @@ bool SwDoc::SetTextFormatColl(const SwPaM &rRg, GetIDocumentUndoRedo().AppendUndo(std::move(pUndo)); } + std::shared_ptr pDelSet; sw::DocumentContentOperationsManager::ParaRstFormat aPara( pStt, pEnd, pHst, nullptr, pLayout); aPara.pFormatColl = pFormat; aPara.bReset = bReset; // #i62675# aPara.bResetListAttrs = bResetListAttrs; + aPara.bResetAllCharAttrs = bResetAllCharAttrs; + if (bResetAllCharAttrs) + { + o3tl::sorted_vector aAttribs; + pDelSet = sw::DocumentContentOperationsManager::lcl_createDelSet(*this); + aPara.pDelSet = pDelSet.get(); + } GetNodes().ForEach( pStt->GetNodeIndex(), pEnd->GetNodeIndex()+1, lcl_SetTextFormatColl, &aPara ); diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx index c0b1d27c3315..a998f5a51884 100644 --- a/sw/source/core/edit/edfcol.cxx +++ b/sw/source/core/edit/edfcol.cxx @@ -2197,7 +2197,8 @@ void SwEditShell::ClassifyDocPerHighestParagraphClass() // #i62675# void SwEditShell::SetTextFormatColl(SwTextFormatColl *pFormat, - const bool bResetListAttrs) + const bool bResetListAttrs, + SetAttrMode nMode) { SwTextFormatColl *pLocal = pFormat? pFormat: (*GetDoc()->GetTextFormatColls())[0]; StartAllAction(); @@ -2227,7 +2228,7 @@ void SwEditShell::SetTextFormatColl(SwTextFormatColl *pFormat, } // Change the paragraph style to pLocal and remove all direct paragraph formatting. - GetDoc()->SetTextFormatColl(rPaM, pLocal, true, bResetListAttrs, GetLayout()); + GetDoc()->SetTextFormatColl(rPaM, pLocal, true, bResetListAttrs, !!(nMode & SetAttrMode::REMOVE_ALL_ATTR), GetLayout()); // If there are hints on the nodes which cover the whole node, then remove those, too. SwPaM aPaM(*rPaM.Start(), *rPaM.End()); diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx b/sw/source/core/inc/DocumentContentOperationsManager.hxx index 3cb378f00069..62540462bb77 100644 --- a/sw/source/core/inc/DocumentContentOperationsManager.hxx +++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx @@ -127,6 +127,7 @@ public: bool bReset; bool bResetListAttrs; // #i62575# bool bResetAll; + bool bResetAllCharAttrs; bool bInclRefToxMark; /// From the attributes included in the range, delete only the ones which have exactly same range. Don't delete the ones which are simply included in the range. bool bExactRange; @@ -144,13 +145,14 @@ public: , bReset(false) // #i62675# , bResetListAttrs(false) , bResetAll(true) + , bResetAllCharAttrs(false) , bInclRefToxMark(false) , bExactRange(false) { } }; static bool lcl_RstTextAttr( SwNode* pNd, void* pArgs ); //originally from docfmt.cxx - + static std::shared_ptr lcl_createDelSet(SwDoc& rDoc); virtual ~DocumentContentOperationsManager() override; diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx index 24de64a8f9e0..c08d36505730 100644 --- a/sw/source/core/txtnode/txtedt.cxx +++ b/sw/source/core/txtnode/txtedt.cxx @@ -381,7 +381,7 @@ static bool lcl_HaveCommonAttributes( IStyleAccess& rStyleAccess, * * @param nStt starting position * @param nLen length of the deletion - * @param nthat ??? + * @param nWhich ??? * @param pSet ??? * @param bInclRefToxMark ??? */ diff --git a/sw/source/uibase/app/docst.cxx b/sw/source/uibase/app/docst.cxx index eba940a48dfc..65bf850b5b0a 100644 --- a/sw/source/uibase/app/docst.cxx +++ b/sw/source/uibase/app/docst.cxx @@ -1197,8 +1197,12 @@ SfxStyleFamily SwDocShell::ApplyStyles(const OUString &rName, SfxStyleFamily nFa case SfxStyleFamily::Char: { SwFormatCharFormat aFormat(pStyle->GetCharFormat()); - pSh->SetAttrItem( aFormat, (nMode & KEY_SHIFT) ? - SetAttrMode::DONTREPLACE : SetAttrMode::DEFAULT ); + SetAttrMode nFlags = (nMode & KEY_SHIFT) ? + SetAttrMode::DONTREPLACE : SetAttrMode::DEFAULT; + if (nMode & KEY_MOD1) + nFlags |= SetAttrMode::REMOVE_ALL_ATTR; + pSh->SetAttrItem( aFormat, nFlags ); + break; } case SfxStyleFamily::Para: @@ -1215,7 +1219,7 @@ SfxStyleFamily SwDocShell::ApplyStyles(const OUString &rName, SfxStyleFamily nFa // #i62675# // clear also list attributes at affected text nodes, if paragraph // style has the list style attribute set. - pSh->SetTextFormatColl( pStyle->GetCollection(), true ); + pSh->SetTextFormatColl( pStyle->GetCollection(), true, (nMode & KEY_MOD1) ? SetAttrMode::REMOVE_ALL_ATTR : SetAttrMode::DEFAULT); } break; } -- cgit