[Libreoffice-commits] core.git: Branch 'libreoffice-7-0' - sw/inc sw/qa sw/source
Michael Stahl (via logerrit)
logerrit at kemper.freedesktop.org
Fri Jun 12 16:09:33 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 9e746242a5dc4fd79ed8214c5508bade60d325ca
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 18:09:03 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>
(cherry picked from commit e1629c210ad78310e3d48c0756723134a27b89df)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/96186
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 1da78ab1d9a4..3a3546c61d55 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