sw/qa/core/txtnode/data/page-crossref-update.odt |binary
 sw/qa/core/txtnode/txtnode.cxx                   |   32 +++++++++++++++++++++++
 sw/source/core/txtnode/atrfld.cxx                |   13 +++++++++
 sw/source/uibase/inc/wrtsh.hxx                   |    5 ++-
 sw/source/uibase/wrtsh/select.cxx                |    4 ++
 5 files changed, 53 insertions(+), 1 deletion(-)

New commits:
commit a05ec67b2481025d8a5b1de79eae5381b1b3acb5
Author:     Miklos Vajna <[email protected]>
AuthorDate: Mon Oct 20 08:43:04 2025 +0200
Commit:     Caolán McNamara <[email protected]>
CommitDate: Mon Oct 20 10:08:23 2025 +0200

    tdf#165472 sw: fix missing page cross-reference update on hidden sect change
    
    Open the bugdoc, change the "book" set variable field's value at the
    document start from 0 to 1, go to the end of the document, the page
    cross-reference field says "page 3", but once you click on it, you end
    up on page 2, which is not correct.
    
    This is a regression from commit
    1dcd3f1b9fc0d888e047e854a20e9ab2e0afd544 (sw: fix not needed
    invalidation of custom field on each keypress, 2021-05-19), where the
    old use-case was that typing in a LOK client resulted in repainting the
    custom fields in the footer on each keystroke, because typing a key
    changes the doc stats (one more character), but then by the time a
    repaint happens, we don't know anymore what field types needs updating,
    so we repaint all doc stat fields.
    
    So repainting those fields on every keystroke is certainly an overkill,
    but at the same time an automatic update of page cross-references on
    section visibility change is also a reasonable request. Fix this by
    separating the "update on idle after any cursor change" old use-case and
    the "close dialog and enter text edit/standard mode" new use-case. Doing
    this wider update of fields is enough to do in the second case, so we
    get page number updates and the typing performance is not back to poor.
    
    This works because the idle case goes via the vcl scheduler, but the
    explicit field update goes via this codepath:
            #23 0x00007ffff2f088b1 in SfxBindings::Update (this=0x4c14b20, 
nId=21185) at sfx2/source/control/bindings.cxx:357
            #24 0x00007fffba614118 in SwWrtShell::Invalidate (this=0x4c5c980) 
at sw/source/uibase/wrtsh/select.cxx:66
            #25 0x00007fffba615fb9 in SwWrtShell::EnterStdMode (this=0x4c5c980) 
at sw/source/uibase/wrtsh/select.cxx:595
            #26 0x00007fff917e1af3 in SwFieldEditDlg::ImplDestroy 
(this=0x4c43a30) at sw/source/ui/fldui/fldedt.cxx:224
            #27 0x00007fff917e1b50 in SwFieldEditDlg::~SwFieldEditDlg 
(this=0x4c43a30, __in_chrg=<optimized out>) at sw/source/ui/fldui/fldedt.cxx:229
    
    Change-Id: I96f48f46f44a1d6d1bde5ede282cd1cf847a6164
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192680
    Tested-by: Jenkins CollaboraOffice <[email protected]>
    Reviewed-by: Caolán McNamara <[email protected]>

diff --git a/sw/qa/core/txtnode/data/page-crossref-update.odt 
b/sw/qa/core/txtnode/data/page-crossref-update.odt
new file mode 100644
index 000000000000..004ea48f3362
Binary files /dev/null and b/sw/qa/core/txtnode/data/page-crossref-update.odt 
differ
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index e537a8b94c8a..48e00c25cba1 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -46,6 +46,7 @@
 #include <docufld.hxx>
 #include <IDocumentFieldsAccess.hxx>
 #include <MarkManager.hxx>
+#include <fldmgr.hxx>
 
 /// Covers sw/source/core/txtnode/ fixes.
 class SwCoreTxtnodeTest : public SwModelTestBase
@@ -642,6 +643,37 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, 
testDOCXCommentImport)
     CPPUNIT_ASSERT(it != pMarkAccess->getAnnotationMarksEnd());
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPageCrossrefUpdate)
+{
+    // Given a document with a "book" document variable set to 0, conditional 
content on pages 1-2,
+    // bookmark on page 3, reference to that bookmark on page 4:
+    createSwDoc("page-crossref-update.odt");
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/true);
+    // Go to the doc variable field.
+    pWrtShell->GoNextBookmark();
+
+    // When performing the equivalent of what SwFieldEditDlg would do to set 
"book" to "1":
+    SwFieldMgr aMgr(pWrtShell);
+    aMgr.UpdateCurField(0, "book", u"1"_ustr);
+    SwDoc* pDoc = getSwDoc();
+    pWrtShell->SetEnteringStdMode(true);
+    pDoc->getIDocumentStatistics().GetUpdatedDocStat(/*bCompleteAsync=*/true, 
/*bFields=*/false);
+    pWrtShell->SetEnteringStdMode(false);
+    Scheduler::ProcessEventsToIdle();
+
+    // Then make sure the reference to the bookmark on (now) page 2 expands to 
the correct value:
+    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
+    OUString aExpand = getXPath(
+        pXmlDoc, 
"/root/page[3]/body/section/txt/SwParaPortion/SwLineLayout/SwFieldPortion",
+        "expand");
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 2
+    // - Actual  : 3
+    // i.e. the reference to that bookmark was not updated for the new page 
number.
+    CPPUNIT_ASSERT_EQUAL(u"2"_ustr, aExpand);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/atrfld.cxx 
b/sw/source/core/txtnode/atrfld.cxx
index 12d72a2cb47d..dd5cbe26a5ea 100644
--- a/sw/source/core/txtnode/atrfld.cxx
+++ b/sw/source/core/txtnode/atrfld.cxx
@@ -42,6 +42,8 @@
 #include <fieldhint.hxx>
 #include <sal/log.hxx>
 #include <osl/diagnose.h>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
 
 
 // constructor for default item in attribute-pool
@@ -391,6 +393,17 @@ void SwFormatField::ForceUpdateTextNode()
     // Force notify was added for conditional text fields,
     // at least the below fields need no forced notify.
     bool bNeedForced = 
lcl_NeedsForcedUpdate(*mpTextField->GetFormatField().GetField());
+    if (!bNeedForced)
+    {
+        // Check if this is an idle update after any doc stat change or an 
explicit UI update.
+        SwDocShell* pDocShell = pTextNd->GetDoc().GetDocShell();
+        SwWrtShell* pWrtShell = pDocShell ? pDocShell->GetWrtShell() : nullptr;
+        if (pWrtShell && pWrtShell->IsEnteringStdMode())
+        {
+            // The UI invoked the update, update even doc info fields.
+            bNeedForced = true;
+        }
+    }
     mpTextField->ExpandTextField(bNeedForced);
 }
 void SwFormatField::UpdateDocPos(const SwTwips nDocPos)
diff --git a/sw/source/uibase/inc/wrtsh.hxx b/sw/source/uibase/inc/wrtsh.hxx
index ba66490b3086..f49c50f57e5f 100644
--- a/sw/source/uibase/inc/wrtsh.hxx
+++ b/sw/source/uibase/inc/wrtsh.hxx
@@ -426,7 +426,7 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
     SW_DLLPUBLIC void GotoMark( const ::sw::mark::MarkBase* const pMark );
     bool GotoMark( const ::sw::mark::MarkBase* const pMark, bool bSelect );
     SW_DLLPUBLIC void GotoMark( const OUString& rName );
-    bool GoNextBookmark(); // true when there still was one
+    SW_DLLPUBLIC bool GoNextBookmark(); // true when there still was one
     bool GoPrevBookmark();
 
     bool GotoFieldmark(::sw::mark::Fieldmark const * const pMark);
@@ -521,6 +521,8 @@ typedef bool (SwWrtShell::*FNSimpleMove)();
     virtual void InfoReadOnlyDialog(bool bAsync) const override;
     virtual bool WarnHiddenSectionDialog() const override;
     virtual bool WarnSwitchToDesignModeDialog() const override;
+    void SetEnteringStdMode(bool bEnteringStdMode) { m_bEnteringStdMode = 
bEnteringStdMode; }
+    bool IsEnteringStdMode() const { return m_bEnteringStdMode; }
 
     std::optional<OString> getLOKPayload(int nType, int nViewId) const;
 
@@ -608,6 +610,7 @@ private:
     bool    m_bIsInClickToEdit:1;
     bool    m_bClearMark      :1;     // don't delete selection for 
ChartAutoPilot
     bool    m_bRetainSelection :1; // Do not remove selections
+    bool m_bEnteringStdMode = false;
 
     Point   m_aStart;
     Link<SwWrtShell&,void>  m_aSelTableLink;
diff --git a/sw/source/uibase/wrtsh/select.cxx 
b/sw/source/uibase/wrtsh/select.cxx
index 2eee5e26a172..3cd721b1d0e1 100644
--- a/sw/source/uibase/wrtsh/select.cxx
+++ b/sw/source/uibase/wrtsh/select.cxx
@@ -48,6 +48,7 @@
 #include <bitmaps.hlst>
 
 #include <svx/svdview.hxx>
+#include <comphelper/scopeguard.hxx>
 
 namespace com::sun::star::util {
     struct SearchOptions2;
@@ -567,6 +568,9 @@ void SwWrtShell::ExtSelLn(const Point *pPt, bool )
 
 void SwWrtShell::EnterStdMode()
 {
+    m_bEnteringStdMode = true;
+    comphelper::ScopeGuard g([this] { m_bEnteringStdMode = false; });
+
     if(m_bAddMode)
         LeaveAddMode();
     if(m_bBlockMode)

Reply via email to