[Libreoffice-commits] core.git: sw/inc sw/qa sw/source

Michael Stahl (via logerrit) logerrit at kemper.freedesktop.org
Fri Jun 12 13:50:07 UTC 2020


 sw/inc/undobj.hxx                   |    3 
 sw/qa/extras/uiwriter/uiwriter2.cxx |  148 ++++++++++++++++++++++++++++++++++++
 sw/source/core/edit/edlingu.cxx     |    3 
 sw/source/core/undo/undobj.cxx      |    6 -
 sw/source/core/undo/unins.cxx       |   41 ++++-----
 5 files changed, 174 insertions(+), 27 deletions(-)

New commits:
commit e1629c210ad78310e3d48c0756723134a27b89df
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Jun 12 14:17:20 2020 +0200
Commit:     Michael Stahl <michael.stahl at cib.de>
CommitDate: Fri Jun 12 15:49:30 2020 +0200

    tdf#131912 sw: fix spell check correct deleting flys
    
    * SwEditShell::ApplyChangedSentence() should not call
      DeleteAndJoin() + InsertString() but ReplaceRange()
    
    * ReplaceRange() and SwUndoReplace need to set a new flag
      DelContentType::Replace to tell SwUndoSaveContent::DelContentIndex()
      not to delete flys but instead record the previous anchor positions
    
    * SwUndoReplace::UndoImpl() should also not call DeleteAndJoin()
      + InsertString(); instead call ReplaceRange() for the start node
      and then DeleteAndJoin() for any regex "\n" that were inserted
    
    (regression from 28b77c89dfcafae82cf2a6d85731b643ff9290e5)
    
    Change-Id: I485d79510ae233213cb4b208533871934c5e5ec6
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96201
    Tested-by: Jenkins
    Reviewed-by: Michael Stahl <michael.stahl at cib.de>

diff --git a/sw/inc/undobj.hxx b/sw/inc/undobj.hxx
index 8da9b70980b8..91394446ccf7 100644
--- a/sw/inc/undobj.hxx
+++ b/sw/inc/undobj.hxx
@@ -135,12 +135,13 @@ enum class DelContentType : sal_uInt16
     Fly          = 0x02,
     Bkm          = 0x08,
     AllMask      = 0x0b,
+    Replace      = 0x10,
     WriterfilterHack = 0x20,
     ExcludeFlyAtStartEnd = 0x40,
     CheckNoCntnt = 0x80,
 };
 namespace o3tl {
-    template<> struct typed_flags<DelContentType> : is_typed_flags<DelContentType, 0xeb> {};
+    template<> struct typed_flags<DelContentType> : is_typed_flags<DelContentType, 0xfb> {};
 }
 
 /// will DelContentIndex destroy a frame anchored at character at rAnchorPos?
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index 74f6c5e30c22..99f573b139e6 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -313,6 +313,154 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf132236)
     assertXPath(pXmlDoc, "/root/page[1]/body/txt", 1);
 }
 
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf131912)
+{
+    SwDoc* const pDoc = createDoc();
+    SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+
+    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
+
+    sw::UnoCursorPointer pCursor(
+        pDoc->CreateUnoCursor(SwPosition(SwNodeIndex(pDoc->GetNodes().GetEndOfContent(), -1))));
+
+    pDoc->getIDocumentContentOperations().InsertString(*pCursor, "foo");
+
+    {
+        SfxItemSet flySet(pDoc->GetAttrPool(),
+                          svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
+        SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+        pWrtShell->StartOfSection(false);
+        pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+        anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+        flySet.Put(anchor);
+        SwFormatFrameSize size(SwFrameSize::Minimum, 1000, 1000);
+        flySet.Put(size); // set a size, else we get 1 char per line...
+        SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
+        CPPUNIT_ASSERT(pFly != nullptr);
+    }
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+
+    pCursor->SetMark();
+    pCursor->GetMark()->nContent.Assign(pCursor->GetContentNode(), 0);
+    pCursor->GetPoint()->nContent.Assign(pCursor->GetContentNode(), 3);
+
+    // replace with more text
+    pDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, "blahblah", false);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("blahblah"), pCursor->GetNode().GetTextNode()->GetText());
+
+    rUndoManager.Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), pCursor->GetNode().GetTextNode()->GetText());
+
+    rUndoManager.Redo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("blahblah"), pCursor->GetNode().GetTextNode()->GetText());
+
+    rUndoManager.Undo();
+
+    pCursor->GetMark()->nContent.Assign(pCursor->GetContentNode(), 0);
+    pCursor->GetPoint()->nContent.Assign(pCursor->GetContentNode(), 3);
+
+    // replace with less text
+    pDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, "x", false);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("x"), pCursor->GetNode().GetTextNode()->GetText());
+
+    rUndoManager.Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), pCursor->GetNode().GetTextNode()->GetText());
+
+    rUndoManager.Redo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("x"), pCursor->GetNode().GetTextNode()->GetText());
+
+    rUndoManager.Undo();
+
+    pCursor->GetMark()->nContent.Assign(pCursor->GetContentNode(), 0);
+    pCursor->GetPoint()->nContent.Assign(pCursor->GetContentNode(), 3);
+
+    // regex replace with paragraph breaks
+    pDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, "xyz\\n\\nquux\\n", true);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    pWrtShell->StartOfSection(false);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz"),
+                         pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText());
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz\n\nquux\n"), pWrtShell->GetCursor()->GetText());
+
+    rUndoManager.Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), pCursor->GetNode().GetTextNode()->GetText());
+    pWrtShell->StartOfSection(false);
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), pWrtShell->GetCursor()->GetText());
+
+    rUndoManager.Redo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    pWrtShell->StartOfSection(false);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz"),
+                         pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText());
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz\n\nquux\n"), pWrtShell->GetCursor()->GetText());
+
+    // regex replace with paragraph join
+    pWrtShell->StartOfSection(false);
+    pWrtShell->Down(true);
+    pDoc->getIDocumentContentOperations().ReplaceRange(*pWrtShell->GetCursor(), "bar", true);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    pWrtShell->StartOfSection(false);
+    CPPUNIT_ASSERT_EQUAL(OUString("bar"),
+                         pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText());
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("bar\nquux\n"), pWrtShell->GetCursor()->GetText());
+
+    rUndoManager.Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    pWrtShell->StartOfSection(false);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz"),
+                         pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText());
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz\n\nquux\n"), pWrtShell->GetCursor()->GetText());
+
+    rUndoManager.Redo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    pWrtShell->StartOfSection(false);
+    CPPUNIT_ASSERT_EQUAL(OUString("bar"),
+                         pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText());
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("bar\nquux\n"), pWrtShell->GetCursor()->GetText());
+
+    rUndoManager.Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    pWrtShell->StartOfSection(false);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz"),
+                         pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText());
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("xyz\n\nquux\n"), pWrtShell->GetCursor()->GetText());
+
+    rUndoManager.Undo();
+
+    CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc->GetFlyCount(FLYCNTTYPE_FRM));
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), pCursor->GetNode().GetTextNode()->GetText());
+    pWrtShell->StartOfSection(false);
+    pWrtShell->EndOfSection(true);
+    CPPUNIT_ASSERT_EQUAL(OUString("foo"), pWrtShell->GetCursor()->GetText());
+}
+
 CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf54819)
 {
     load(DATA_DIRECTORY, "tdf54819.fodt");
diff --git a/sw/source/core/edit/edlingu.cxx b/sw/source/core/edit/edlingu.cxx
index a2a4adf3b249..15e8532f0ee3 100644
--- a/sw/source/core/edit/edlingu.cxx
+++ b/sw/source/core/edit/edlingu.cxx
@@ -1141,11 +1141,10 @@ void SwEditShell::ApplyChangedSentence(const svx::SpellPortions& rNewPortions, b
             if(aCurrentNewPortion->sText != aCurrentOldPortion->sText)
             {
                 // change text ...
-                mxDoc->getIDocumentContentOperations().DeleteAndJoin(*pCursor);
                 // ... and apply language if necessary
                 if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
                     SetAttrItem( SvxLanguageItem(aCurrentNewPortion->eLanguage, nLangWhichId) );
-                mxDoc->getIDocumentContentOperations().InsertString(*pCursor, aCurrentNewPortion->sText);
+                mxDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, aCurrentNewPortion->sText, false);
             }
             else if(aCurrentNewPortion->eLanguage != aCurrentOldPortion->eLanguage)
             {
diff --git a/sw/source/core/undo/undobj.cxx b/sw/source/core/undo/undobj.cxx
index 0de5562c3c46..cff8a6b758b8 100644
--- a/sw/source/core/undo/undobj.cxx
+++ b/sw/source/core/undo/undobj.cxx
@@ -971,7 +971,8 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
                             if (!m_pHistory)
                                 m_pHistory.reset( new SwHistory );
 
-                            if (IsSelectFrameAnchoredAtPara(*pAPos, *pStt, *pEnd, nDelContentType))
+                            if (!(DelContentType::Replace & nDelContentType)
+                                && IsSelectFrameAnchoredAtPara(*pAPos, *pStt, *pEnd, nDelContentType))
                             {
                                 m_pHistory->AddDeleteFly(*pFormat, nChainInsPos);
                                 // reset n so that no Format is skipped
@@ -1002,7 +1003,8 @@ void SwUndoSaveContent::DelContentIndex( const SwPosition& rMark,
                     {
                         if( !m_pHistory )
                             m_pHistory.reset( new SwHistory );
-                        if (IsDestroyFrameAnchoredAtChar(
+                        if (!(DelContentType::Replace & nDelContentType)
+                            && IsDestroyFrameAnchoredAtChar(
                                 *pAPos, *pStt, *pEnd, nDelContentType))
                         {
                             m_pHistory->AddDeleteFly(*pFormat, nChainInsPos);
diff --git a/sw/source/core/undo/unins.cxx b/sw/source/core/undo/unins.cxx
index 6fb4e82fae56..6e08fb5027e5 100644
--- a/sw/source/core/undo/unins.cxx
+++ b/sw/source/core/undo/unins.cxx
@@ -597,7 +597,7 @@ SwUndoReplace::Impl::Impl(
     OSL_ENSURE( pNd, "Dude, where's my TextNode?" );
 
     m_pHistory.reset( new SwHistory );
-    DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
+    DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(), DelContentType::AllMask | DelContentType::Replace);
 
     m_nSetPos = m_pHistory->Count();
 
@@ -658,42 +658,39 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext)
         pDoc->SetAutoCorrExceptWord( nullptr );
     }
 
-    SwIndex aIdx( pNd, m_nSttCnt );
     // don't look at m_sIns for deletion, maybe it was not completely inserted
     {
         rPam.GetPoint()->nNode = *pNd;
         rPam.GetPoint()->nContent.Assign( pNd, m_nSttCnt );
         rPam.SetMark();
-        rPam.GetPoint()->nNode = m_nEndNd - m_nOffset;
-        rPam.GetPoint()->nContent.Assign( rPam.GetContentNode(), m_nEndCnt );
-        // move it out of the way so it is not registered at deleted node
-        aIdx.Assign(nullptr, 0);
-
-        pDoc->getIDocumentContentOperations().DeleteAndJoin( rPam );
+        rPam.GetPoint()->nNode = m_nSttNd - m_nOffset;
+        rPam.GetPoint()->nContent.Assign(rPam.GetContentNode(), m_nSttNd == m_nEndNd ? m_nEndCnt : pNd->Len());
+
+        // replace only in start node, without regex
+        bool const ret = pDoc->getIDocumentContentOperations().ReplaceRange(rPam, m_sOld, false);
+        assert(ret); (void)ret;
+        if (m_nSttNd != m_nEndNd)
+        {   // in case of regex inserting paragraph breaks, join nodes...
+            assert(rPam.GetMark()->nContent == rPam.GetMark()->nNode.GetNode().GetTextNode()->Len());
+            rPam.GetPoint()->nNode = m_nEndNd - m_nOffset;
+            rPam.GetPoint()->nContent.Assign(rPam.GetContentNode(true), m_nEndCnt);
+            pDoc->getIDocumentContentOperations().DeleteAndJoin(rPam);
+        }
         rPam.DeleteMark();
-        pNd = rPam.GetNode().GetTextNode();
+        pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTextNode();
         OSL_ENSURE( pNd, "Dude, where's my TextNode?" );
-        aIdx.Assign( pNd, m_nSttCnt );
     }
 
     if( m_bSplitNext )
     {
-        SwPosition aPos( *pNd, aIdx );
+        SwPosition aPos(*pNd, pNd->Len());
         pDoc->getIDocumentContentOperations().SplitNode( aPos, false );
         pNd->RestoreMetadata(m_pMetadataUndoEnd);
         pNd = pDoc->GetNodes()[ m_nSttNd - m_nOffset ]->GetTextNode();
-        aIdx.Assign( pNd, m_nSttCnt );
         // METADATA: restore
         pNd->RestoreMetadata(m_pMetadataUndoStart);
     }
 
-    if (!m_sOld.isEmpty())
-    {
-        OUString const ins( pNd->InsertText( m_sOld, aIdx ) );
-        assert(ins.getLength() == m_sOld.getLength()); // must succeed
-        (void) ins;
-    }
-
     if( m_pHistory )
     {
         if( pNd->GetpSwpHints() )
@@ -720,7 +717,7 @@ void SwUndoReplace::Impl::UndoImpl(::sw::UndoRedoContext & rContext)
     }
 
     rPam.GetPoint()->nNode = m_nSttNd;
-    rPam.GetPoint()->nContent = aIdx;
+    rPam.GetPoint()->nContent = m_nSttCnt;
 }
 
 void SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext)
@@ -746,7 +743,7 @@ void SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext)
         auto xSave = std::make_unique<SwHistory>();
         std::swap(m_pHistory, xSave);
 
-        DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
+        DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(), DelContentType::AllMask | DelContentType::Replace);
         m_nSetPos = m_pHistory->Count();
 
         std::swap(xSave, m_pHistory);
@@ -755,7 +752,7 @@ void SwUndoReplace::Impl::RedoImpl(::sw::UndoRedoContext & rContext)
     else
     {
         m_pHistory.reset( new SwHistory );
-        DelContentIndex( *rPam.GetMark(), *rPam.GetPoint() );
+        DelContentIndex(*rPam.GetMark(), *rPam.GetPoint(), DelContentType::AllMask | DelContentType::Replace);
         m_nSetPos = m_pHistory->Count();
         if( !m_nSetPos )
         {


More information about the Libreoffice-commits mailing list