sw/inc/IDocumentContentOperations.hxx                   |    6 +++
 sw/qa/core/doc/doc.cxx                                  |   32 ++++++++++++++++
 sw/source/core/doc/DocumentContentOperationsManager.cxx |   10 +++++
 sw/source/core/doc/extinput.cxx                         |   12 +++++-
 sw/source/core/edit/editsh.cxx                          |    1 
 sw/source/core/inc/DocumentContentOperationsManager.hxx |    6 +++
 6 files changed, 65 insertions(+), 2 deletions(-)

New commits:
commit b8e0b887efb35b0afd85b81349d5f8e2f7d1c359
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Nov 8 08:27:52 2021 +0100
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Nov 9 10:05:16 2021 +0100

    sw: try grouping undo actions of IME-edited text
    
    This is a problem since commit e7760d428bc82ccfcae14f1907b78f9f1013b88c
    (Fix tdf#87500 - Freeze with English/Japanese mixture undo.,
    2015-09-08), that started not grouping IME-edited text completely.
    
    This means that in case you go via SwEditWin::Command() instead of
    SwEditWin::KeyInput() to type a 4 characters word, then it'll create 4
    undo actions.
    
    Fix the problem by tracking who was the last caller of
    sw::DocumentContentOperationsManager::InsertString(), so we can only
    disable grouping switching between IME and non-IME, and we can have
    grouping for a series of IME input.
    
    (cherry picked from commit 6680e51716e383c68bb1ec9cc0a05d698d3b6a3d)
    
    Change-Id: I31bd02db4fe653ab63e41a77c75b8bebfc749ff1
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124834
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/inc/IDocumentContentOperations.hxx 
b/sw/inc/IDocumentContentOperations.hxx
index 14724eae3731..d9a6a8b518e9 100644
--- a/sw/inc/IDocumentContentOperations.hxx
+++ b/sw/inc/IDocumentContentOperations.hxx
@@ -163,6 +163,12 @@ public:
     virtual bool InsertString(const SwPaM &rRg, const OUString&,
               const SwInsertFlags nInsertMode = SwInsertFlags::EMPTYEXPAND ) = 
0;
 
+    /// States that the last inserted string came from IME.
+    virtual void SetIME(bool bIME) = 0;
+
+    /// Did the last inserted string come from IME?
+    virtual bool GetIME() const = 0;
+
     /** change text to Upper/Lower/Hiragana/Katakana/...
      */
     virtual void TransliterateText(const SwPaM& rPaM, 
utl::TransliterationWrapper&) = 0;
diff --git a/sw/qa/core/doc/doc.cxx b/sw/qa/core/doc/doc.cxx
index 14f724328fe0..bda78bda8e48 100644
--- a/sw/qa/core/doc/doc.cxx
+++ b/sw/qa/core/doc/doc.cxx
@@ -18,6 +18,7 @@
 #include <editeng/langitem.hxx>
 #include <sfx2/viewfrm.hxx>
 #include <sfx2/dispatch.hxx>
+#include <vcl/scheduler.hxx>
 
 #include <wrtsh.hxx>
 #include <fmtanchr.hxx>
@@ -29,6 +30,7 @@
 #include <swdtflvr.hxx>
 #include <cmdid.h>
 #include <unotxdoc.hxx>
+#include <UndoManager.hxx>
 
 char const DATA_DIRECTORY[] = "/sw/qa/core/doc/data/";
 
@@ -165,6 +167,36 @@ CPPUNIT_TEST_FIXTURE(SwCoreDocTest, 
testTextBoxMakeFlyFrame)
     assertXPath(pLayout, "/root/page/body/txt/anchored/fly", 1);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreDocTest, testIMEGrouping)
+{
+// TODO figure out why the ext text input in this test code reaches the wrong 
window on
+// non-headless.
+#if !defined MACOSX && !defined _WIN32
+    // Given an empty document:
+    SwDoc* pDoc = createSwDoc();
+    // Make sure no idle is in action, so the ExtTextInput events go to 
SwEditWin.
+    Scheduler::ProcessEventsToIdle();
+
+    // When pressing two keys via IME:
+    SwDocShell* pDocShell = pDoc->GetDocShell();
+    SwEditWin& rEditWin = pDocShell->GetView()->GetEditWin();
+    rEditWin.PostExtTextInputEvent(VclEventId::ExtTextInput, "a");
+    rEditWin.PostExtTextInputEvent(VclEventId::EndExtTextInput, "");
+    rEditWin.PostExtTextInputEvent(VclEventId::ExtTextInput, "b");
+    rEditWin.PostExtTextInputEvent(VclEventId::EndExtTextInput, "");
+
+    // Then make sure that gets grouped together to a single undo action:
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    SwTextNode* pTextNode = pWrtShell->GetCursor()->GetNode().GetTextNode();
+    CPPUNIT_ASSERT_EQUAL(OUString("ab"), pTextNode->GetText());
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 2
+    // i.e. 2 subsequent IME events got their own undo actions.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), 
pDoc->GetUndoManager().GetUndoActionCount());
+#endif
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx 
b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index aefd7feb881e..c3251b6232f2 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -2818,6 +2818,16 @@ bool DocumentContentOperationsManager::InsertString( 
const SwPaM &rRg, const OUS
     return true;
 }
 
+void DocumentContentOperationsManager::SetIME(bool bIME)
+{
+    m_bIME = bIME;
+}
+
+bool DocumentContentOperationsManager::GetIME() const
+{
+    return m_bIME;
+}
+
 void DocumentContentOperationsManager::TransliterateText(
     const SwPaM& rPaM,
     utl::TransliterationWrapper& rTrans )
diff --git a/sw/source/core/doc/extinput.cxx b/sw/source/core/doc/extinput.cxx
index 09f4dba1e016..500f5d157b6c 100644
--- a/sw/source/core/doc/extinput.cxx
+++ b/sw/source/core/doc/extinput.cxx
@@ -61,7 +61,12 @@ SwExtTextInput::~SwExtTextInput()
 
     // Prevent IME edited text being grouped with non-IME edited text.
     bool bKeepGroupUndo = rDoc.GetIDocumentUndoRedo().DoesGroupUndo();
-    rDoc.GetIDocumentUndoRedo().DoGroupUndo(false);
+    bool bWasIME = rDoc.GetIDocumentUndoRedo().GetUndoActionCount() == 0 || 
rDoc.getIDocumentContentOperations().GetIME();
+    if (!bWasIME)
+    {
+        rDoc.GetIDocumentUndoRedo().DoGroupUndo(false);
+    }
+    rDoc.getIDocumentContentOperations().SetIME(true);
     if( nEndCnt < nSttCnt )
     {
         std::swap(nSttCnt, nEndCnt);
@@ -119,7 +124,10 @@ SwExtTextInput::~SwExtTextInput()
 
         pTNd->EraseText( rIdx, nLenghtOfOldString );
     }
-    rDoc.GetIDocumentUndoRedo().DoGroupUndo(bKeepGroupUndo);
+    if (!bWasIME)
+    {
+        rDoc.GetIDocumentUndoRedo().DoGroupUndo(bKeepGroupUndo);
+    }
     if (m_eInputLanguage == LANGUAGE_DONTKNOW)
         return;
 
diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx
index 85c065d60fed..967ce1f2e203 100644
--- a/sw/source/core/edit/editsh.cxx
+++ b/sw/source/core/edit/editsh.cxx
@@ -88,6 +88,7 @@ void SwEditShell::Insert2(const OUString &rStr, const bool 
bForceExpandHints )
         for(SwPaM& rCurrentCursor : getShellCursor( true )->GetRingContainer())
         {
             //OPT: GetSystemCharSet
+            GetDoc()->getIDocumentContentOperations().SetIME(false);
             const bool bSuccess =
                 
GetDoc()->getIDocumentContentOperations().InsertString(rCurrentCursor, rStr, 
nInsertFlags);
             OSL_ENSURE( bSuccess, "Doc->Insert() failed." );
diff --git a/sw/source/core/inc/DocumentContentOperationsManager.hxx 
b/sw/source/core/inc/DocumentContentOperationsManager.hxx
index 3df39532978c..ab5d260bce7f 100644
--- a/sw/source/core/inc/DocumentContentOperationsManager.hxx
+++ b/sw/source/core/inc/DocumentContentOperationsManager.hxx
@@ -61,6 +61,10 @@ public:
     bool InsertString(const SwPaM &rRg, const OUString&,
               const SwInsertFlags nInsertMode = SwInsertFlags::EMPTYEXPAND ) 
override;
 
+    void SetIME(bool bIME) override;
+
+    bool GetIME() const override;
+
     void TransliterateText(const SwPaM& rPaM, utl::TransliterationWrapper&) 
override;
 
     SwFlyFrameFormat* InsertGraphic(const SwPaM &rRg, const OUString& 
rGrfName, const OUString& rFltName, const Graphic* pGraphic,
@@ -159,6 +163,8 @@ public:
 private:
     SwDoc& m_rDoc;
 
+    bool m_bIME = false;
+
     bool DeleteAndJoinImpl(SwPaM&, const bool);
     bool DeleteAndJoinWithRedlineImpl(SwPaM&, const bool unused = false);
     bool DeleteRangeImpl(SwPaM&, const bool unused = false);

Reply via email to