summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-06-29 21:05:27 +0200
committerMichael Stahl <michael.stahl@cib.de>2020-07-01 11:11:21 +0200
commit568e2e946b6cb21bd36baff4e3592629431765a0 (patch)
tree968f8ac4bab6082fb910854b7bacf1690aed507b
parent28962153ca3826ca2aba626f8cc8ff9c6dab9eab (diff)
tdf#134099 sw: fix textbox anchors on copy-paste and undo
Regression from commit c7307c77254557646f33017af915f6808a861e29 (fdo#82191 sw::DocumentLayoutManager: copy textbox content of draw formats, 2014-08-15), without which this problem gets hidden, as copy breaks the textbox into 2 pieces, so the textbox codepaths are no longer hit. The direct problem is that SwHistorySetFormat::SetInDoc() uses a raw node index into the nodes array, which is past the end of the nodes array. Root cause is that we have this invariant that actions and their undo has to be in sync, otherwise raw node indexes no longer work. In this case, SwUndoSaveContent::DelContentIndex() did not delete a fly frame format, because it was out of range, as it had a wrong anchor. Fix this in SwTextFlyCnt::SetAnchor(), so that whenever the anchor of a draw format is set via that function, we update its textbox as well. Also fix a related problem when fly formats were copied twice. (cherry picked from commit 682e0488df819c191c13a03758fad0690706e508) Conflicts: sw/qa/core/txtnode/txtnode.cxx Change-Id: I0d6c9069544c405eb20c5fed65fb40423b0adc84 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97515 Tested-by: Jenkins Reviewed-by: Michael Stahl <michael.stahl@cib.de>
-rw-r--r--sw/qa/core/txtnode/data/textbox-copy-anchor.docxbin0 -> 224854 bytes
-rw-r--r--sw/qa/core/txtnode/txtnode.cxx28
-rw-r--r--sw/source/core/doc/DocumentContentOperationsManager.cxx8
-rw-r--r--sw/source/core/txtnode/atrflyin.cxx10
4 files changed, 46 insertions, 0 deletions
diff --git a/sw/qa/core/txtnode/data/textbox-copy-anchor.docx b/sw/qa/core/txtnode/data/textbox-copy-anchor.docx
new file mode 100644
index 000000000000..b835097f1b9b
--- /dev/null
+++ b/sw/qa/core/txtnode/data/textbox-copy-anchor.docx
Binary files differ
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index b6af5230faf8..c23272285569 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -49,6 +49,34 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testBtlrCellChinese)
assertXPath(pXmlDoc, "//font[1]", "vertical", "false");
}
+CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxCopyAnchor)
+{
+ load(DATA_DIRECTORY, "textbox-copy-anchor.docx");
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ SwDocShell* pShell = pTextDoc->GetDocShell();
+ SwWrtShell* pWrtShell = pShell->GetWrtShell();
+ SwDoc aClipboard;
+ pWrtShell->SelAll();
+ pWrtShell->Copy(&aClipboard);
+ pWrtShell->SttEndDoc(/*bStart=*/false);
+ pWrtShell->Paste(&aClipboard);
+
+ const SwFrameFormats& rFormats = *pShell->GetDoc()->GetSpzFrameFormats();
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 4
+ // - Actual : 6
+ // i.e. 2 fly frames were copied twice.
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rFormats.size());
+
+ SwPosition aDrawAnchor1 = *rFormats[0]->GetAnchor().GetContentAnchor();
+ SwPosition aFlyAnchor1 = *rFormats[1]->GetAnchor().GetContentAnchor();
+ CPPUNIT_ASSERT_EQUAL(aFlyAnchor1.nNode, aDrawAnchor1.nNode);
+ SwPosition aDrawAnchor2 = *rFormats[2]->GetAnchor().GetContentAnchor();
+ SwPosition aFlyAnchor2 = *rFormats[3]->GetAnchor().GetContentAnchor();
+ // This also failed, aFlyAnchor2 was wrong, as it got out of sync with aDrawAnchor2.
+ CPPUNIT_ASSERT_EQUAL(aFlyAnchor2.nNode, aDrawAnchor2.nNode);
+}
+
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 08d7eb6f09fa..f62d77352cc9 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -3785,6 +3785,14 @@ void DocumentContentOperationsManager::CopyFlyInFlyImpl(
}
}
+ // Ignore TextBoxes, they are already handled in
+ // sw::DocumentLayoutManager::CopyLayoutFormat().
+ if (SwTextBoxHelper::isTextBox(it->GetFormat(), RES_FLYFRMFMT))
+ {
+ it = aSet.erase(it);
+ continue;
+ }
+
// Copy the format and set the new anchor
aVecSwFrameFormat.push_back( pDest->getIDocumentLayoutAccess().CopyLayoutFormat( *(*it).GetFormat(),
aAnchor, false, true ) );
diff --git a/sw/source/core/txtnode/atrflyin.cxx b/sw/source/core/txtnode/atrflyin.cxx
index 1509c0cf3d40..837c90a1a5a7 100644
--- a/sw/source/core/txtnode/atrflyin.cxx
+++ b/sw/source/core/txtnode/atrflyin.cxx
@@ -35,6 +35,7 @@
#include <objectformatter.hxx>
#include <calbck.hxx>
#include <dcontact.hxx>
+#include <textboxhelper.hxx>
SwFormatFlyCnt::SwFormatFlyCnt( SwFrameFormat *pFrameFormat )
: SfxPoolItem( RES_TXTATR_FLYCNT ),
@@ -202,6 +203,15 @@ void SwTextFlyCnt::SetAnchor( const SwTextNode *pNode )
}
}
pFormat->SetFormatAttr( aAnchor ); // only set the anchor
+
+ // If the draw format has a TextBox, then set its anchor as well.
+ if (SwFrameFormat* pTextBox
+ = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
+ {
+ SwFormatAnchor aTextBoxAnchor(pTextBox->GetAnchor());
+ aTextBoxAnchor.SetAnchor(aAnchor.GetContentAnchor());
+ pTextBox->SetFormatAttr(aTextBoxAnchor);
+ }
}
// The node may have several SwTextFrames - for every SwTextFrame a