include/svx/hdft.hxx                  |    1 
 sc/qa/uitest/calc_tests8/tdf144940.py |    6 ++--
 svx/source/dialog/hdft.cxx            |   50 +++++++++++++++++++++++++---------
 3 files changed, 41 insertions(+), 16 deletions(-)

New commits:
commit 11cd6b2fbc86e28506d5b26a436df1b4b2b5bf09
Author:     Justin Luth <[email protected]>
AuthorDate: Thu Sep 4 11:11:42 2025 -0400
Commit:     Justin Luth <[email protected]>
CommitDate: Sat Sep 6 03:31:33 2025 +0200

    tdf#100287 svx dialog: sync "first header" with "first footer"
    
    When either the header OR the footer wants different first content,
    then (by design) the application applies it to both of them.
    (True for Writer only - not true for Calc!!!)
    
    It is also important (for the user experience) that either one
    is able to stop using first content altogether (for Writer only).
    
    This was already working to some extent,
    but the user experience was not consistent or predictable.
    
    Specifically, the improvements with this patch:
    -provide an appropriate "default" value when turning on a H/F.
    -always visually match the most recent "first content" choice.
    -in Calc, simply visiting the H/F no longer turns on first page.
    
    The prior situation was very "fickle",
    and "first content" could be affected
    without the user even touching that box (for both Writer and Calc).
    
    The underlying reason this patch can work is because of
    SvxHFPage::SvxHFPage SetExchangeSupport().
    That causes SfxTabDialogController::DeactivatePage
    to update the m_xExampleSet which is then passed
    to SvxHFPage::ActivatePage.
    Thus the active tab knows about all the dialog's current settings.
    
    Since Reset() calls ActivatePage,
    it was safe to move the initialization out of Reset.
    
    make -srj1 UITest_calc_tests8 \
        UITEST_TEST_NAME=tdf144940.tdf144940.test_tdf144940 \
        SAL_USE_VCLPLUGIN=gen
    
    Change-Id: Icd6084ca50d244317c807266f04c85dadbba2bb1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/190606
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <[email protected]>

diff --git a/include/svx/hdft.hxx b/include/svx/hdft.hxx
index ec69102f1a91..53d402a0fee5 100644
--- a/include/svx/hdft.hxx
+++ b/include/svx/hdft.hxx
@@ -90,6 +90,7 @@ protected:
 
 private:
     SVX_DLLPRIVATE void         ResetBackground_Impl( const SfxItemSet& rSet );
+    bool m_bIsCalc;
 };
 
 class SVX_DLLPUBLIC SvxHeaderPage final : public SvxHFPage
diff --git a/sc/qa/uitest/calc_tests8/tdf144940.py 
b/sc/qa/uitest/calc_tests8/tdf144940.py
index 9e577bf72815..f2628588ac7b 100644
--- a/sc/qa/uitest/calc_tests8/tdf144940.py
+++ b/sc/qa/uitest/calc_tests8/tdf144940.py
@@ -34,11 +34,11 @@ class tdf144940(UITestCase):
 
                     self.assertEqual("true", 
get_state_as_dict(xCheckHeaderOn)["Selected"])
                     self.assertEqual("true", 
get_state_as_dict(xCheckSameLR)["Selected"])
-                    self.assertEqual("false", 
get_state_as_dict(xCheckSameFP)["Selected"])
+                    self.assertEqual("true", 
get_state_as_dict(xCheckSameFP)["Selected"])
 
                     xCheckSameFP.executeAction("CLICK", tuple())
 
-                    self.assertEqual("true", 
get_state_as_dict(xCheckSameFP)["Selected"])
+                    self.assertEqual("false", 
get_state_as_dict(xCheckSameFP)["Selected"])
 
                 with self.ui_test.execute_dialog_through_command(".uno:Save", 
close_button="open") as xSaveDialog:
                     xFileName = xSaveDialog.getChild("file_name")
@@ -55,7 +55,7 @@ class tdf144940(UITestCase):
                 # AssertionError: False is not true
                 self.assertTrue(xDefaultPageStyle.HeaderOn)
                 self.assertTrue(xDefaultPageStyle.FooterOn)
-                self.assertTrue(xDefaultPageStyle.FirstPageHeaderIsShared)
+                self.assertFalse(xDefaultPageStyle.FirstPageHeaderIsShared)
                 self.assertTrue(xDefaultPageStyle.FirstPageFooterIsShared)
 
 # vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/svx/source/dialog/hdft.cxx b/svx/source/dialog/hdft.cxx
index d66e22276981..b7dfb6b2cc6b 100644
--- a/svx/source/dialog/hdft.cxx
+++ b/svx/source/dialog/hdft.cxx
@@ -143,6 +143,10 @@ SvxHFPage::SvxHFPage(weld::Container* pPage, 
weld::DialogController* pController
     , m_xFrame(m_xBuilder->weld_frame(u"frame1"_ustr))
     , m_xBspWin(new weld::CustomWeld(*m_xBuilder, u"drawingareaPageHF"_ustr, 
m_aBspWin))
 {
+    const SfxPoolItem* pExt1 = GetItem(rSet, SID_ATTR_PAGE_EXT1);
+    const SfxPoolItem* pExt2 = GetItem(rSet, SID_ATTR_PAGE_EXT2);
+    m_bIsCalc = dynamic_cast<const SfxBoolItem*>(pExt1) && dynamic_cast<const 
SfxBoolItem*>(pExt2);
+
     //swap header <-> footer in UI
     if (nId == SID_ATTR_PAGE_FOOTERSET)
     {
@@ -349,9 +353,6 @@ void SvxHFPage::Reset( const SfxItemSet* rSet )
                 rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_DYNAMIC ) );
             const SfxBoolItem& rShared =
                 rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED ) );
-            const SfxBoolItem* pSharedFirst = nullptr;
-            if (rHeaderSet.HasItem(GetWhich(SID_ATTR_PAGE_SHARED_FIRST)))
-                pSharedFirst = static_cast<const 
SfxBoolItem*>(&rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SHARED_FIRST ) ));
             const SvxSizeItem& rSize =
                 rHeaderSet.Get( GetWhich( SID_ATTR_PAGE_SIZE ) );
             const SvxULSpaceItem& rUL = rHeaderSet.Get( GetWhich( 
SID_ATTR_ULSPACE ) );
@@ -379,22 +380,14 @@ void SvxHFPage::Reset( const SfxItemSet* rSet )
             SetMetricValue(*m_xLMEdit, rLR.ResolveLeft({}), eUnit);
             SetMetricValue(*m_xRMEdit, rLR.ResolveRight({}), eUnit);
             m_xCntSharedBox->set_active(rShared.GetValue());
-            if (pSharedFirst)
-                m_xCntSharedFirstBox->set_active(pSharedFirst->GetValue());
         }
         else
             pSetItem = nullptr;
     }
     else
     {
-        bool bIsCalc = false;
-        const SfxPoolItem* pExt1 = GetItem(*rSet, SID_ATTR_PAGE_EXT1);
-        const SfxPoolItem* pExt2 = GetItem(*rSet, SID_ATTR_PAGE_EXT2);
-        if (dynamic_cast<const SfxBoolItem*>(pExt1) && dynamic_cast<const 
SfxBoolItem*>(pExt2) )
-            bIsCalc = true;
-
         // defaults for distance and height
-        tools::Long nDefaultDist = bIsCalc ? DEF_DIST_CALC : DEF_DIST_WRITER;
+        tools::Long nDefaultDist = m_bIsCalc ? DEF_DIST_CALC : DEF_DIST_WRITER;
         SetMetricValue( *m_xDistEdit, nDefaultDist, MapUnit::Map100thMM );
         SetMetricValue( *m_xHeightEdit, 500, MapUnit::Map100thMM );
     }
@@ -404,7 +397,6 @@ void SvxHFPage::Reset( const SfxItemSet* rSet )
         m_xTurnOnBox->set_active(false);
         m_xHeightDynBtn->set_active(true);
         m_xCntSharedBox->set_active(true);
-        m_xCntSharedFirstBox->set_active(true);
     }
 
     TurnOn(nullptr);
@@ -848,6 +840,12 @@ void SvxHFPage::ActivatePage( const SfxItemSet& rSet )
         m_aBspWin.SetSize( rSize.GetSize() );
     }
 
+    // For Writer, either header OR footer can indicate that first H/F will 
have different contents.
+    // Prioritize the non-activated tab's setting (in case the value was 
already changed there).
+    std::optional<bool> oNonActivatedFirstShared; // only used by Writer
+    bool bActivatedFirstShared = true; // default value
+    const sal_uInt16 nSidAttrPageSharedFirst = 
GetWhich(SID_ATTR_PAGE_SHARED_FIRST);
+
     // Evaluate Header attribute
     const SvxSetItem* pSetItem = nullptr;
 
@@ -872,6 +870,17 @@ void SvxHFPage::ActivatePage( const SfxItemSet& rSet )
             m_aBspWin.SetHdLeft(rLR.ResolveLeft({}));
             m_aBspWin.SetHdRight(rLR.ResolveRight({}));
             m_aBspWin.SetHeader( true );
+            const SfxBoolItem* pSharedFirst = nullptr;
+            if (rHeaderSet.HasItem(nSidAttrPageSharedFirst))
+                 pSharedFirst
+                    = static_cast<const 
SfxBoolItem*>(&rHeaderSet.Get(nSidAttrPageSharedFirst));
+            if (pSharedFirst)
+            {
+                if (SID_ATTR_PAGE_HEADERSET == nId || m_bIsCalc)
+                    bActivatedFirstShared = pSharedFirst->GetValue();
+                else
+                    oNonActivatedFirstShared = pSharedFirst->GetValue();
+            }
         }
         else
             pSetItem = nullptr;
@@ -910,6 +919,17 @@ void SvxHFPage::ActivatePage( const SfxItemSet& rSet )
             m_aBspWin.SetFtLeft(rLR.ResolveLeft({}));
             m_aBspWin.SetFtRight(rLR.ResolveRight({}));
             m_aBspWin.SetFooter( true );
+            const SfxBoolItem* pSharedFirst = nullptr;
+            if (rFooterSet.HasItem(nSidAttrPageSharedFirst))
+                 pSharedFirst
+                    = static_cast<const 
SfxBoolItem*>(&rFooterSet.Get(nSidAttrPageSharedFirst));
+            if (pSharedFirst)
+            {
+                if (SID_ATTR_PAGE_FOOTERSET == nId || m_bIsCalc)
+                    bActivatedFirstShared = pSharedFirst->GetValue();
+                else
+                    oNonActivatedFirstShared = pSharedFirst->GetValue();
+            }
         }
         else
             pSetItem = nullptr;
@@ -926,6 +946,10 @@ void SvxHFPage::ActivatePage( const SfxItemSet& rSet )
         }
     }
 
+    // Priority: non-active tab's FirstBox - then this tab's First - otherwise 
default is shared
+    m_xCntSharedFirstBox->set_active(
+        oNonActivatedFirstShared.has_value() ? *oNonActivatedFirstShared : 
bActivatedFirstShared);
+
     pItem = GetItem( rSet, SID_ATTR_PAGE_EXT1 );
 
     if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )

Reply via email to