sw/inc/pagedesc.hxx                        |    3 +
 sw/source/core/layout/pagedesc.cxx         |   54 +++++++++++++++++++++++++++++
 sw/source/uibase/app/docst.cxx             |    3 +
 sw/source/uibase/app/docstyle.cxx          |    7 ++-
 sw/source/uibase/docvw/HeaderFooterWin.cxx |    8 ++--
 sw/source/uibase/inc/uitool.hxx            |    3 +
 sw/source/uibase/utlui/uitool.cxx          |   35 ++++++++++++------
 7 files changed, 94 insertions(+), 19 deletions(-)

New commits:
commit 7d6bdb4e2aa08a829b0ecb5fbe990d0abdadfd75
Author:     Justin Luth <[email protected]>
AuthorDate: Sat Aug 30 09:48:17 2025 -0400
Commit:     Justin Luth <[email protected]>
CommitDate: Thu Sep 11 01:41:13 2025 +0200

    tdf#168196 sw: copy header properties to all (first, even, odd)
    
    Although a page style can have different CONTENTS
    on left, right, and first pages,
    the other header properties are the same/duplicated.
    
    This patch tries to set up the plumbing,
    and implements it for both the Borders and Background context dialog
    as well as for the general Page Style dialog.
    
    Unfortunately, our current implementation
    does not use an actual shared format,
    so the properties must be duplicated 4 times,
    and yet sadly I couldn't find any existing mechanism
    that attempted to keep them in sync.
    
    Doing it properly doesn't sound like copy/paste,
    so not something that I would attempt.
    
    I don't see any interoperability reasons in DOC/DOCX
    that would force the properties to be kept separate.
    Certainly for ODF, it appears that only Master is exported
    (in terms of the header and footer properties).
    
    tdf#144448 was a nice duplicate report that pointed out the need
    for FillHdFt to be used in order for Height/Spacing
    to also be affected.
    Otherwise SID_ATTR_PAGE_SIZE and SID_ATTR_PAGE_DYNAMIC
    were just ignored as !GetRanges().doesContainWhich(nWhich)
    
    Change-Id: I94f8cdf8bc6006dbea80941a2d6756e162f82411
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190420
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <[email protected]>

diff --git a/sw/inc/pagedesc.hxx b/sw/inc/pagedesc.hxx
index c213b03bf34c..0113371b7de8 100644
--- a/sw/inc/pagedesc.hxx
+++ b/sw/inc/pagedesc.hxx
@@ -244,6 +244,9 @@ public:
     const SwFrameFormat &GetFirstMaster() const { return m_FirstMaster; }
     const SwFrameFormat &GetFirstLeft()   const { return m_FirstLeft; }
 
+    /// Set format properties on all non-shared odd/even/first headers (or 
footers)
+    bool SetFormatAttrOnAll(const SfxItemSet& rSet, const bool bHeader);
+
     /** Reset all attrs of the format but keep the ones a pagedesc
        cannot live without. */
     inline void ResetAllMasterAttr();
diff --git a/sw/source/core/layout/pagedesc.cxx 
b/sw/source/core/layout/pagedesc.cxx
index a65f3332a792..780123d62452 100644
--- a/sw/source/core/layout/pagedesc.cxx
+++ b/sw/source/core/layout/pagedesc.cxx
@@ -28,6 +28,7 @@
 #include <sal/log.hxx>
 #include <fmtclds.hxx>
 #include <fmtfsize.hxx>
+#include <fmthdft.hxx>
 #include <pagefrm.hxx>
 #include <pagedesc.hxx>
 #include <swtable.hxx>
@@ -423,6 +424,59 @@ void SwPageDesc::ChgFirstShare( bool bNew )
         m_eUse &= UseOnPage::NoFirstShare;
 }
 
+bool SwPageDesc::SetFormatAttrOnAll(const SfxItemSet& rSet, const bool bHeader)
+{
+    if( !rSet.Count() )
+        return false;
+
+    // Warning: no attempt is made here to limit rSet to properties that are 
"safe"
+    // to duplicate to all of the different headers/footers.
+    assert(!rSet.HasItem(RES_CNTNT) && "unexpected use of 
SwPageDesc::SetFormatAttrOnAll");
+
+    bool bRet = false;
+    if (bHeader)
+    {
+        auto pHF = 
const_cast<SwFrameFormat*>(GetMaster().GetHeader().GetHeaderFormat());
+        bRet = pHF && pHF->SetFormatAttr(rSet);
+        if (bRet && !IsFirstShared())
+        {
+            pHF = 
const_cast<SwFrameFormat*>(GetFirstMaster().GetHeader().GetHeaderFormat());
+            pHF && pHF->SetFormatAttr(rSet);
+        }
+        if (bRet && !IsHeaderShared())
+        {
+            pHF = 
const_cast<SwFrameFormat*>(GetLeft().GetHeader().GetHeaderFormat());
+            pHF && pHF->SetFormatAttr(rSet);
+            if (!IsFirstShared())
+            {
+                pHF = 
const_cast<SwFrameFormat*>(GetFirstLeft().GetHeader().GetHeaderFormat());
+                pHF && pHF->SetFormatAttr(rSet);
+            }
+        }
+    }
+    else // footer
+    {
+        auto pHF = 
const_cast<SwFrameFormat*>(GetMaster().GetFooter().GetFooterFormat());
+        bRet = pHF && pHF->SetFormatAttr(rSet);
+        if (bRet && !IsFirstShared())
+        {
+            pHF = 
const_cast<SwFrameFormat*>(GetFirstMaster().GetFooter().GetFooterFormat());
+            pHF && pHF->SetFormatAttr(rSet);
+        }
+        if (bRet && !IsFooterShared())
+        {
+            pHF = 
const_cast<SwFrameFormat*>(GetLeft().GetFooter().GetFooterFormat());
+            pHF && pHF->SetFormatAttr(rSet);
+            if (bRet && !IsFirstShared())
+            {
+                pHF= 
const_cast<SwFrameFormat*>(GetFirstLeft().GetFooter().GetFooterFormat());
+                pHF && pHF->SetFormatAttr(rSet);
+            }
+        }
+    }
+    return bRet;
+}
+
 void SwPageDesc::StashFrameFormat(const SwFrameFormat& rFormat, bool bHeader, 
bool bLeft, bool bFirst)
 {
     assert(rFormat.GetRegisteredIn());
diff --git a/sw/source/uibase/app/docst.cxx b/sw/source/uibase/app/docst.cxx
index 989eeaa871ec..24ebdbbd5d03 100644
--- a/sw/source/uibase/app/docst.cxx
+++ b/sw/source/uibase/app/docst.cxx
@@ -657,7 +657,8 @@ IMPL_LINK_NOARG(ApplyStyle, ApplyHdl, LinkParamNone*, void)
             ::ConvertAttrGenToChar(aTmpSet, m_xTmp->GetItemSet());
         }
 
-        m_xTmp->SetItemSet( aTmpSet, false );
+        bool bParam1 = SfxStyleFamily::Page == m_nFamily; // 
bApplyToAllFormatFrames
+        m_xTmp->SetItemSet(aTmpSet, /*bBroadcast=*/ false, bParam1);
 
         if( SfxStyleFamily::Page == m_nFamily && 
SvtCTLOptions::IsCTLFontEnabled() )
         {
diff --git a/sw/source/uibase/app/docstyle.cxx 
b/sw/source/uibase/app/docstyle.cxx
index d03083ac6dd3..73818d9ac2d5 100644
--- a/sw/source/uibase/app/docstyle.cxx
+++ b/sw/source/uibase/app/docstyle.cxx
@@ -1622,8 +1622,7 @@ void SwDocStyleSheet::MergeIndentAttrsOfListStyle( 
SfxItemSet& rSet )
 }
 
 // handling of parameter <bResetIndentAttrsAtParagraphStyle>
-void SwDocStyleSheet::SetItemSet( const SfxItemSet& rSet, const bool 
bBroadcast,
-                                  const bool bResetIndentAttrsAtParagraphStyle 
)
+void SwDocStyleSheet::SetItemSet(const SfxItemSet& rSet, const bool 
bBroadcast, const bool bParam1)
 {
     // if applicable determine format first
     if(!m_bPhysical)
@@ -1715,6 +1714,7 @@ void SwDocStyleSheet::SetItemSet( const SfxItemSet& rSet, 
const bool bBroadcast,
                 m_rDoc.DelTextFormatColl( m_pColl );
                 m_pColl = pCColl;
             }
+            const bool bResetIndentAttrsAtParagraphStyle = bParam1;
             if ( bResetIndentAttrsAtParagraphStyle &&
                  rSet.GetItemState( RES_PARATR_NUMRULE, false ) == 
SfxItemState::SET &&
                  rSet.GetItemState(RES_MARGIN_FIRSTLINE, false) != 
SfxItemState::SET &&
@@ -1892,7 +1892,8 @@ void SwDocStyleSheet::SetItemSet( const SfxItemSet& rSet, 
const bool bBroadcast,
 
         if( pNewDsc )
         {
-            ::ItemSetToPageDesc( aSet, *pNewDsc );
+            const bool bApplyToAllFormatFrames = bParam1;
+            ::ItemSetToPageDesc(aSet, *pNewDsc, bApplyToAllFormatFrames);
             m_rDoc.ChgPageDesc( nPgDscPos, *pNewDsc );
             m_pDesc = &m_rDoc.GetPageDesc( nPgDscPos );
             m_rDoc.PreDelPageDesc(pNewDsc.get()); // #i7983#
diff --git a/sw/source/uibase/docvw/HeaderFooterWin.cxx 
b/sw/source/uibase/docvw/HeaderFooterWin.cxx
index ebad3ae4c3a5..719e609d715c 100644
--- a/sw/source/uibase/docvw/HeaderFooterWin.cxx
+++ b/sw/source/uibase/docvw/HeaderFooterWin.cxx
@@ -488,8 +488,8 @@ void SwHeaderFooterWin::ExecuteCommand(std::u16string_view 
rIdent)
     }
     else if (rIdent == u"borderback")
     {
-        const SwPageDesc* pDesc = pPageFrame->GetPageDesc();
-        const SwFrameFormat& rMaster = pDesc->GetMaster();
+        SwPageDesc& rPageDesc = 
const_cast<SwPageDesc&>(*pPageFrame->GetPageDesc());
+        SwFrameFormat& rMaster = rPageDesc.GetMaster();
         SwFrameFormat* pHFFormat = const_cast< SwFrameFormat* >( 
rMaster.GetFooter().GetFooterFormat() );
         if ( m_bIsHeader )
             pHFFormat = const_cast< SwFrameFormat* >( 
rMaster.GetHeader().GetHeaderFormat() );
@@ -517,7 +517,9 @@ void SwHeaderFooterWin::ExecuteCommand(std::u16string_view 
rIdent)
 
         if (svx::ShowBorderBackgroundDlg( GetFrameWeld(), &aSet ) )
         {
-            pHFFormat->SetFormatAttr( aSet );
+            // Apply the modified format to all (first, even, odd) of the page 
style's FrameFormats
+            aSet.DisableItem(RES_CNTNT); // don't duplicate the content 
though...
+            rPageDesc.SetFormatAttrOnAll(aSet, m_bIsHeader);
             rView.GetDocShell()->SetModified();
         }
     }
diff --git a/sw/source/uibase/inc/uitool.hxx b/sw/source/uibase/inc/uitool.hxx
index d2c7c3b051c0..4b616b95e1cd 100644
--- a/sw/source/uibase/inc/uitool.hxx
+++ b/sw/source/uibase/inc/uitool.hxx
@@ -69,7 +69,8 @@ SW_DLLPUBLIC void ConvertAttrGenToChar(SfxItemSet& rSet, 
const SfxItemSet& rOrig
 void ApplyCharBackground(Color const& rBackgroundColor, model::ComplexColor 
const& rComplexColor, SwWrtShell& rShell);
 
 // SfxItemSets <-> PageDesc
-void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc );
+void ItemSetToPageDesc(const SfxItemSet& rSet, SwPageDesc& rPageDesc,
+                       bool bApplyToAllFormatFrames = false);
 void PageDescToItemSet( const SwPageDesc& rPageDesc, SfxItemSet& rSet);
 
 // fill tabs with default tabs
diff --git a/sw/source/uibase/utlui/uitool.cxx 
b/sw/source/uibase/utlui/uitool.cxx
index e7a79c92f929..5f98464af353 100644
--- a/sw/source/uibase/utlui/uitool.cxx
+++ b/sw/source/uibase/utlui/uitool.cxx
@@ -225,8 +225,20 @@ void ApplyCharBackground(Color const& rBackgroundColor, 
model::ComplexColor cons
 
 // Fill header footer
 
-static void FillHdFt(SwFrameFormat* pFormat, const  SfxItemSet& rSet)
+static void FillHdFt(SfxPoolItem& rFormat, const SfxItemSet& rSet, SwPageDesc& 
rPageDesc,
+                     bool bApplyToAllFormatFrames)
 {
+    auto pHeader = dynamic_cast<SwFormatHeader*>(&rFormat);
+    auto pFooter = dynamic_cast<SwFormatFooter*>(&rFormat);
+    assert(pHeader || pFooter);
+
+    SwFrameFormat* pFormat;
+    if (pHeader)
+        pFormat = pHeader->GetHeaderFormat();
+    else
+        pFormat = pFooter->GetFooterFormat();
+    OSL_ENSURE(pFormat != nullptr, "no header or footer format");
+
     SwAttrSet aSet(pFormat->GetAttrSet());
     aSet.Put(rSet);
 
@@ -238,7 +250,14 @@ static void FillHdFt(SwFrameFormat* pFormat, const  
SfxItemSet& rSet)
                             rSize.GetSize().Width(),
                             rSize.GetSize().Height());
     aSet.Put(aFrameSize);
-    pFormat->SetFormatAttr(aSet);
+    if (bApplyToAllFormatFrames)
+    {
+        // Apply the modified format to all (first, even, odd) of the page 
style's FrameFormats
+        aSet.DisableItem(RES_CNTNT); // don't duplicate the content though...
+        rPageDesc.SetFormatAttrOnAll(aSet, bool(pHeader));
+    }
+    else
+        pFormat->SetFormatAttr(aSet);
 }
 
 /// Convert from UseOnPage to SvxPageUsage.
@@ -273,7 +292,7 @@ static UseOnPage lcl_convertUseFromSvx(SvxPageUsage nUse)
 
 // PageDesc <-> convert into sets and back
 
-void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc )
+void ItemSetToPageDesc(const SfxItemSet& rSet, SwPageDesc& rPageDesc, bool 
bApplyToAllFormatFrames)
 {
     SwFrameFormat& rMaster = rPageDesc.GetMaster();
     bool bFirstShare = false;
@@ -364,10 +383,7 @@ void ItemSetToPageDesc( const SfxItemSet& rSet, 
SwPageDesc& rPageDesc )
 
             // Pick out everything and adapt the header format
             SwFormatHeader aHeaderFormat(rMaster.GetHeader());
-            SwFrameFormat *pHeaderFormat = aHeaderFormat.GetHeaderFormat();
-            OSL_ENSURE(pHeaderFormat != nullptr, "no header format");
-
-            ::FillHdFt(pHeaderFormat, rHeaderSet);
+            ::FillHdFt(aHeaderFormat, rHeaderSet, rPageDesc, 
bApplyToAllFormatFrames);
 
             
rPageDesc.ChgHeaderShare(rHeaderSet.Get(SID_ATTR_PAGE_SHARED).GetValue());
             rPageDesc.ChgFirstShare(static_cast<const SfxBoolItem&>(
@@ -400,10 +416,7 @@ void ItemSetToPageDesc( const SfxItemSet& rSet, 
SwPageDesc& rPageDesc )
 
             // Pick out everything and adapt the footer format
             SwFormatFooter aFooterFormat(rMaster.GetFooter());
-            SwFrameFormat *pFooterFormat = aFooterFormat.GetFooterFormat();
-            OSL_ENSURE(pFooterFormat != nullptr, "no footer format");
-
-            ::FillHdFt(pFooterFormat, rFooterSet);
+            ::FillHdFt(aFooterFormat, rFooterSet, rPageDesc, 
bApplyToAllFormatFrames);
 
             
rPageDesc.ChgFooterShare(rFooterSet.Get(SID_ATTR_PAGE_SHARED).GetValue());
             if (!bFirstShare)

Reply via email to