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)
