sw/inc/crsrsh.hxx                   |   12 ++++++++++++
 sw/inc/viewsh.hxx                   |    7 +++++++
 sw/qa/extras/uiwriter/uiwriter6.cxx |   10 ++--------
 sw/source/core/crsr/crsrsh.cxx      |   21 +++++++++++++++++++++
 sw/source/core/crsr/viscrs.cxx      |   27 ---------------------------
 sw/source/core/inc/txtfrm.hxx       |    2 +-
 sw/source/core/txtnode/txtedt.cxx   |    8 ++++++++
 7 files changed, 51 insertions(+), 36 deletions(-)

New commits:
commit fbe6d3072da81f7b6e1a4f8f8393d1f4c8e0868f
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Jun 5 00:41:03 2024 +0500
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Jun 6 08:51:38 2024 +0200

    tdf#136294: trigger pending spellcheck in SwCursorShell::UpdateCursor
    
    This allows to drop the partial fix created for tdf#124603  (except for unit
    test). The problem solved in commit 4c91e94e892943ef5e031d65f6f42864233cb4cd
    (tdf#92036: sw: fix idle spelling loop,  2015-09-09)  is kept solved; when a
    word is marked pending,  this is signalled  to the viewshell.  SwCursorShell
    stores that as a flag,  which will then start an idle on cursor update,  and
    finally call SwViewShell::LayoutIdle, which does the spell checking.  If the
    cursor is still in the word that is pending the check, the cycle will 
repeat,
    trying spell checks only at cursor update, not as a busy loop.
    
    Change-Id: I5dc77baabffa723e261d553e40d40e5ace4266bc
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168413
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168422
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

diff --git a/sw/inc/crsrsh.hxx b/sw/inc/crsrsh.hxx
index 03afe5006ad6..97248572c762 100644
--- a/sw/inc/crsrsh.hxx
+++ b/sw/inc/crsrsh.hxx
@@ -23,6 +23,7 @@
 
 #include <rtl/ustring.hxx>
 #include <tools/link.hxx>
+#include <vcl/idle.hxx>
 #include <vcl/keycod.hxx>
 #include <o3tl/typed_flags_set.hxx>
 
@@ -243,8 +244,14 @@ private:
 
     bool m_bMacroExecAllowed : 1;
 
+    // SwViewShell::LayoutIdle needs to be called on cursor update to repeat a 
spell check,
+    // because previous attempt marked a word as pending, because the word had 
cursor
+    bool m_bNeedLayoutOnCursorUpdate : 1 = false;
+
     SwFrame* m_oldColFrame;
 
+    Idle m_aLayoutIdle; // An idle to schedule another SwViewShell::LayoutIdle 
call
+
     SAL_DLLPRIVATE void MoveCursorToNum();
 
     SAL_DLLPRIVATE void ParkPams( SwPaM* pDelRg, SwShellCursor** ppDelRing );
@@ -285,6 +292,9 @@ private:
     SAL_DLLPRIVATE const SwRangeRedline* GotoRedline_( 
SwRedlineTable::size_type nArrPos, bool bSelect );
 
     SAL_DLLPRIVATE void sendLOKCursorUpdates();
+
+    DECL_LINK(DoLayoutIdle, Timer*, void); // calls SwViewShell::LayoutIdle
+
 protected:
 
     inline SwMoveFnCollection const & MakeFindRange( SwDocPositions, 
SwDocPositions, SwPaM* ) const;
@@ -308,6 +318,8 @@ protected:
 protected:
     virtual void SwClientNotify(const SwModify&, const SfxHint&) override;
 
+    virtual void OnSpellWrongStatePending() override { 
m_bNeedLayoutOnCursorUpdate = true; }
+
 public:
     SwCursorShell( SwDoc& rDoc, vcl::Window *pWin, const SwViewOption *pOpt );
     // disguised copy constructor
diff --git a/sw/inc/viewsh.hxx b/sw/inc/viewsh.hxx
index fcd697124046..ed3cbfee3b4d 100644
--- a/sw/inc/viewsh.hxx
+++ b/sw/inc/viewsh.hxx
@@ -600,6 +600,13 @@ public:
     void GetFirstLastVisPageNumbers(SwVisiblePageNumbers& rVisiblePageNumbers, 
SwView& rView);
 
     virtual void dumpAsXml(xmlTextWriterPtr pWriter) const;
+
+    // SwTextFrame::AutoSpell_ calls this, to notify the shell, that a word 
has a spelling error,
+    // but that couldn't be drawn, because the cursor was in that word (so 
that the user is not
+    // annoyed while typing). The shell's task is to re-run the spell check 
(i.e., call LayoutIdle,
+    // which internally does the spell check), when the cursor leaves that 
word (implemented in
+    // SwCursorShell).
+    virtual void OnSpellWrongStatePending() {}
 };
 
 // manages global ShellPointer
diff --git a/sw/qa/extras/uiwriter/uiwriter6.cxx 
b/sw/qa/extras/uiwriter/uiwriter6.cxx
index 8e67d26e4652..606728a94f1e 100644
--- a/sw/qa/extras/uiwriter/uiwriter6.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter6.cxx
@@ -2044,16 +2044,9 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf124603)
         bool bPending = !pNode->GetWrong() || !pNode->GetWrong()->Count();
         CPPUNIT_ASSERT(bPending);
 
-        // Move right, leave the bad word
+        // Move right, leave the bad word - since the fix for tdf#136294, this 
triggers the check
 
         pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
-        // tdf#92036 still pending spell checking
-        bPending = !pNode->GetWrong() || !pNode->GetWrong()->Count();
-        CPPUNIT_ASSERT(bPending);
-
-        // Move down to trigger spell checking
-
-        pWrtShell->Down(/*bSelect=*/false, 1);
         Scheduler::ProcessEventsToIdle();
         CPPUNIT_ASSERT(pNode->GetWrong());
         // This was 0 (pending spell checking)
@@ -2102,6 +2095,7 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf45949)
 
         // Move down to trigger spell checking
         pWrtShell->Down(/*bSelect=*/false, 1);
+        Scheduler::ProcessEventsToIdle();
 
         // Without the fix in place, this test would have failed with
         // - Expected: 3
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index 33f11e9a282b..51f675adc9dd 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -1915,6 +1915,15 @@ void SwCursorShell::UpdateCursor( sal_uInt16 eFlags, 
bool bIdleEnd )
         return; // if not then no update
     }
 
+    if (m_bNeedLayoutOnCursorUpdate)
+    {
+        // A previous spell check skipped a word that had a spelling error, 
because that word
+        // had cursor. Now schedule the idle to call SwViewShell::LayoutIdle, 
to repeat the
+        // spell check, in the hope that the cursor has left the word.
+        m_aLayoutIdle.Start();
+        m_bNeedLayoutOnCursorUpdate = false;
+    }
+
 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
     SwNotifyAccAboutInvalidTextSelections aInvalidateTextSelections( *this );
 #endif
@@ -3305,6 +3314,7 @@ SwCursorShell::SwCursorShell( SwCursorShell& rShell, 
vcl::Window *pInitWin )
     , m_eEnhancedTableSel(SwTable::SEARCH_NONE)
     , m_nMarkedListLevel( 0 )
     , m_oldColFrame(nullptr)
+    , m_aLayoutIdle("SwCursorShell m_aLayoutIdle")
 {
     CurrShell aCurr( this );
     // only keep the position of the current cursor of the copy shell
@@ -3320,6 +3330,9 @@ SwCursorShell::SwCursorShell( SwCursorShell& rShell, 
vcl::Window *pInitWin )
     m_bSetCursorInReadOnly = true;
     m_pVisibleCursor = new SwVisibleCursor( this );
     m_bMacroExecAllowed = rShell.IsMacroExecAllowed();
+
+    m_aLayoutIdle.SetPriority(TaskPriority::LOWEST);
+    m_aLayoutIdle.SetInvokeHandler(LINK(this, SwCursorShell, DoLayoutIdle));
 }
 
 /// default constructor
@@ -3342,6 +3355,7 @@ SwCursorShell::SwCursorShell( SwDoc& rDoc, vcl::Window 
*pInitWin,
     , m_eEnhancedTableSel(SwTable::SEARCH_NONE)
     , m_nMarkedListLevel( 0 )
     , m_oldColFrame(nullptr)
+    , m_aLayoutIdle("SwCursorShell m_aLayoutIdle")
 {
     CurrShell aCurr( this );
     // create initial cursor and set it to first content position
@@ -3366,10 +3380,15 @@ SwCursorShell::SwCursorShell( SwDoc& rDoc, vcl::Window 
*pInitWin,
 
     m_pVisibleCursor = new SwVisibleCursor( this );
     m_bMacroExecAllowed = true;
+
+    m_aLayoutIdle.SetPriority(TaskPriority::LOWEST);
+    m_aLayoutIdle.SetInvokeHandler(LINK(this, SwCursorShell, DoLayoutIdle));
 }
 
 SwCursorShell::~SwCursorShell()
 {
+    m_aLayoutIdle.Stop();
+
     // if it is not the last view then at least the field should be updated
     if( !unique() )
         CheckTableBoxContent( m_pCurrentCursor->GetPoint() );
@@ -3398,6 +3417,8 @@ SwCursorShell::~SwCursorShell()
     EndListeningAll();
 }
 
+IMPL_LINK_NOARG(SwCursorShell, DoLayoutIdle, Timer*, void) { LayoutIdle(); }
+
 SwShellCursor* SwCursorShell::getShellCursor( bool bBlock )
 {
     if( m_pTableCursor )
diff --git a/sw/source/core/crsr/viscrs.cxx b/sw/source/core/crsr/viscrs.cxx
index 0385ce85f71c..090d0eb70421 100644
--- a/sw/source/core/crsr/viscrs.cxx
+++ b/sw/source/core/crsr/viscrs.cxx
@@ -1069,33 +1069,6 @@ void SwShellCursor::SaveTableBoxContent( const 
SwPosition* pPos )
 
 bool SwShellCursor::UpDown( bool bUp, sal_uInt16 nCnt )
 {
-    // tdf#124603 trigger pending spell checking of the node
-    if ( nCnt == 1 )
-    {
-        SwTextNode* pNode = GetPoint()->GetNode().GetTextNode();
-        if( pNode && sw::WrongState::PENDING == pNode->GetWrongDirty() )
-        {
-            SwWrtShell* pShell = pNode->GetDoc().GetDocShell()->GetWrtShell();
-            if ( pShell && !pShell->IsSelection() && !pShell->IsSelFrameMode() 
)
-            {
-                const SwViewOption* pVOpt = pShell->GetViewOptions();
-                if ( pVOpt && pVOpt->IsOnlineSpell() )
-                {
-                    const bool bOldViewLock = pShell->IsViewLocked();
-                    pShell->LockView( true );
-
-                    SwTextFrame* pFrame(
-                        
static_cast<SwTextFrame*>(pNode->getLayoutFrame(GetShell()->GetLayout())));
-                    SwRect aRepaint(pFrame->AutoSpell_(*pNode, 0));
-                    if (aRepaint.HasArea())
-                        pShell->InvalidateWindows(aRepaint);
-
-                    pShell->LockView( bOldViewLock );
-                }
-            }
-        }
-    }
-
     return SwCursor::UpDown( bUp, nCnt,
                             &GetPtPos(), GetShell()->GetUpDownX(),
                             *GetShell()->GetLayout());
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index df11ca589bc6..39f47bce4984 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -353,7 +353,7 @@ public:
      */
     void Init();
 
-    /// Is called by DoIdleJob_(), ExecSpellPopup() and UpDown()
+    /// Is called by DoIdleJob_() and ExecSpellPopup()
     SwRect AutoSpell_(SwTextNode &, sal_Int32);
 
     /// Is called by DoIdleJob_()
diff --git a/sw/source/core/txtnode/txtedt.cxx 
b/sw/source/core/txtnode/txtedt.cxx
index 2f3e7aa6db86..a1bfb0c0f3c1 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -1490,6 +1490,14 @@ SwRect SwTextFrame::AutoSpell_(SwTextNode & rNode, 
sal_Int32 nActPos)
                 : sw::WrongState::DONE);
         if( !pNode->GetWrong()->Count() && ! pNode->IsWrongDirty() )
             pNode->ClearWrong();
+
+        if (bPending && getRootFrame())
+        {
+            if (SwViewShell* pViewSh = getRootFrame()->GetCurrShell())
+            {
+                pViewSh->OnSpellWrongStatePending();
+            }
+        }
     }
     else
         pNode->SetWrongDirty(sw::WrongState::DONE);

Reply via email to