sw/inc/doc.hxx                                          |    1 
 sw/inc/editsh.hxx                                       |    4 
 sw/inc/swtypes.hxx                                      |    6 -
 sw/qa/extras/uiwriter/data/tdf162326.odt                |binary
 sw/qa/extras/uiwriter/uiwriter9.cxx                     |   65 +++++++++++++++-
 sw/source/core/crsr/findcoll.cxx                        |    2 
 sw/source/core/doc/DocumentContentOperationsManager.cxx |   61 ++++++++++++++-
 sw/source/core/doc/docfmt.cxx                           |   25 ++++++
 sw/source/core/edit/edfcol.cxx                          |    5 -
 sw/source/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(-)

New commits:
commit a593c27e8897280871dc310184ff568bf34a6ebe
Author:     Oliver Specht <oliver.spe...@cib.de>
AuthorDate: Tue Sep 10 12:43:06 2024 +0200
Commit:     Gabor Kelemen <gabor.kelemen.ext...@allotropia.de>
CommitDate: Mon Sep 23 20:20:28 2024 +0200

    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 <gabor.kelemen.ext...@allotropia.de>
    Tested-by: Gabor Kelemen <gabor.kelemen.ext...@allotropia.de>
    Tested-by: Jenkins

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 <bResetListAttrs> - see also 
<SwDoc::SetTextFormatColl(..)>
-    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<SetAttrMode> : is_typed_flags<SetAttrMode, 
0x3ff> {};
+    template<> struct typed_flags<SetAttrMode> : is_typed_flags<SetAttrMode, 
0x7ff> {};
 }
 
 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 <com/sun/star/embed/XEmbeddedObject.hpp>
 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
 #include <vcl/scheduler.hxx>
+
+#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
 #include <com/sun/star/table/TableBorder2.hpp>
 #include <com/sun/star/text/XDocumentIndex.hpp>
 #include <com/sun/star/text/XTextFrame.hpp>
@@ -46,7 +49,6 @@
 #include <IDocumentLinksAdministration.hxx>
 #include <fmtinfmt.hxx>
 #include <rootfrm.hxx>
-
 #include <svx/svdview.hxx>
 #include <svx/svdmark.hxx>
 
@@ -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<SwXTextDocument*>(mxComponent.get());
+    CPPUNIT_ASSERT(pDoc);
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD,
+                         getProperty<float>(getRun(getParagraph(1), 1), 
u"CharWeight"_ustr));
+    CPPUNIT_ASSERT_EQUAL(
+        awt::FontSlant_ITALIC,
+        getProperty<awt::FontSlant>(getRun(getParagraph(2), 2), 
u"CharPosture"_ustr));
+    CPPUNIT_ASSERT_EQUAL(short(1),
+                         getProperty<short>(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<float>(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<SwXTextDocument*>(mxComponent.get());
+    CPPUNIT_ASSERT(pDoc);
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    CPPUNIT_ASSERT(pWrtShell);
+
+    CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD,
+                         getProperty<float>(getRun(getParagraph(1), 1), 
u"CharWeight"_ustr));
+    CPPUNIT_ASSERT_EQUAL(
+        awt::FontSlant_ITALIC,
+        getProperty<awt::FontSlant>(getRun(getParagraph(2), 2), 
u"CharPosture"_ustr));
+    CPPUNIT_ASSERT_EQUAL(short(1),
+                         getProperty<short>(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<float>(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<short>(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<SwTextFormatColl*>(pReplColl), true, false, m_pLayout);
+            const_cast<SwTextFormatColl*>(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<SwUndoAttr> 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<const SfxItemSet> 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<SfxItemSet> 
DocumentContentOperationsManager::lcl_createDelSet(SwDoc& rDoc)
+{
+    std::shared_ptr<SfxItemSet> pDelSet(new SfxItemSetFixed<RES_CHRATR_BEGIN, 
RES_CHRATR_END - 1,
+                        RES_TXTATR_INETFMT, RES_TXTATR_UNKNOWN_CONTAINER,
+                        RES_PARATR_BEGIN, RES_FRMATR_END - 1,
+                        RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END - 
1>(rDoc.GetAttrPool()));
+    o3tl::sorted_vector<sal_uInt16> aAttribs;
+
+    constexpr std::pair<sal_uInt16, sal_uInt16> 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<SfxItemSet> 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<sal_uInt16> 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<SfxItemSet> 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;
         }

Reply via email to