sw/qa/extras/unowriter/data/textboxInColumn2.fodt | 39 ++++++++++++++++++++++ sw/qa/extras/unowriter/unowriter.cxx | 18 ++++++++++ sw/source/core/doc/textboxhelper.cxx | 36 +++++++++++++++++--- 3 files changed, 88 insertions(+), 5 deletions(-)
New commits: commit cd740ff560a88a62bc79f5ea5b92bdadf71ba728 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Thu Aug 15 14:53:27 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Aug 15 15:00:28 2024 +0200 tdf#162480: Make sure to use correct anchor point for text box creation In the ODF import, when importing a table, initially a placeholder 1x1 table is created. When this is done from SwView::InsertMedium, frames are created for the table and its single cell at that stage. Then the actual table nodes are created, but frames are not created in parallel, until the table import is finished. Importing a text box, it used to be created anchored at the end of the document, and then the anchor was moved to the correct place. When a text box was anchored to a cell, the process was like this: the text content was inserted in the last paragraph outside of the current table; and then it was moved to the current cell. When this was done from SwView::InsertMedium, creation of the text content also created the frame; then the movement fired client notifications, including the SwFlyAtContentFrame::SwClientNotify, which needs the new anchor frame. With cell other than A1, there was no frames for the new anchor in the table, and that crashed. This change inserts the text content into the correct place from start, which avoids the need to move the anchor later. Co-authored-by: Miklos Vajna <vmik...@collabora.com> Change-Id: I9dd3a2c5527f3c2dd860244456c617558943453a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/171898 Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/extras/unowriter/data/textboxInColumn2.fodt b/sw/qa/extras/unowriter/data/textboxInColumn2.fodt new file mode 100644 index 000000000000..cdd9ba9999ab --- /dev/null +++ b/sw/qa/extras/unowriter/data/textboxInColumn2.fodt @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" office:version="1.3" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:styles> + <style:style style:name="Frame" style:family="graphic"> + <style:graphic-properties style:wrap="parallel" style:number-wrapped-paragraphs="no-limit" style:wrap-contour="false" fo:padding="1.5mm" draw:stroke="solid" svg:stroke-color="#000000" draw:fill="none" draw:textarea-vertical-align="top" draw:auto-grow-height="true" fo:min-height="0mm" fo:min-width="0mm" fo:wrap-option="wrap" style:run-through="foreground" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:flow-with-text="true"/> + </style:style> + </office:styles> + <office:automatic-styles> + <style:style style:name="gr1" style:family="graphic" style:parent-style-name="Frame"> + <style:graphic-properties draw:stroke="solid" svg:stroke-color="#000000" draw:fill="none" draw:textarea-vertical-align="top" draw:auto-grow-height="true" fo:min-height="0mm" fo:min-width="0mm" fo:wrap-option="wrap" style:run-through="foreground" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:flow-with-text="true"/> + </style:style> + </office:automatic-styles> + <office:body> + <office:text> + <table:table> + <table:table-column table:number-columns-repeated="2"/> + <table:table-row> + <table:table-cell/> + <table:table-cell> + <text:p/> + <text:p><draw:custom-shape text:anchor-type="char" draw:z-index="0" draw:name="Text Box 1" draw:style-name="gr1" svg:width="30mm" svg:x="6mm" svg:y="5mm"> + <text:p>hello</text:p> + <draw:enhanced-geometry draw:mirror-horizontal="false" draw:mirror-vertical="false" svg:viewBox="0 0 0 0" draw:text-areas="0 0 ?f3 ?f2" draw:type="ooxml-rect" draw:enhanced-path="M 0 0 L ?f3 0 ?f3 ?f2 0 ?f2 Z N"> + <draw:equation draw:name="f0" draw:formula="logwidth/2"/> + <draw:equation draw:name="f1" draw:formula="logheight/2"/> + <draw:equation draw:name="f2" draw:formula="logheight"/> + <draw:equation draw:name="f3" draw:formula="logwidth"/> + </draw:enhanced-geometry> + </draw:custom-shape></text:p> + <text:p/> + <text:p/> + </table:table-cell> + </table:table-row> + </table:table> + <text:p/> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/sw/qa/extras/unowriter/unowriter.cxx b/sw/qa/extras/unowriter/unowriter.cxx index cf10599b85ad..0179bc60273a 100644 --- a/sw/qa/extras/unowriter/unowriter.cxx +++ b/sw/qa/extras/unowriter/unowriter.cxx @@ -1372,6 +1372,24 @@ CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTdf161035) CPPUNIT_ASSERT(!xRunEnum->hasMoreElements()); // Empty enumeration for empty selection } +CPPUNIT_TEST_FIXTURE(SwUnoWriter, testTdf162480) +{ + createSwDoc(); + + uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({ + { "Name", uno::Any(createFileURL(u"textboxInColumn2.fodt")) }, + }); + + // Inserting a document with text box attached in a table's second column must not crash + dispatchCommand(mxComponent, u".uno:InsertDoc"_ustr, aPropertyValues); + + auto xTextBox = getShape(1).queryThrow<css::text::XTextContent>(); + auto xTable = getParagraphOrTable(2).queryThrow<css::text::XTextTable>(); + auto xAnchorRange = xTextBox->getAnchor(); + auto xCellText = xTable->getCellByName("B1").queryThrow<css::text::XText>(); + CPPUNIT_ASSERT_EQUAL(xCellText, xAnchorRange->getText()); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx index 470fe00a8f75..a9492e6984b3 100644 --- a/sw/source/core/doc/textboxhelper.cxx +++ b/sw/source/core/doc/textboxhelper.cxx @@ -8,6 +8,7 @@ */ #include <textboxhelper.hxx> +#include <dcontact.hxx> #include <fmtcntnt.hxx> #include <fmtanchr.hxx> #include <fmtcnct.hxx> @@ -64,6 +65,7 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo { assert(pShape); assert(pObject); + assert(pShape = ::FindFrameFormat(pObject)); // If TextBox wasn't enabled previously if (pShape->GetOtherTextBoxFormats() && pShape->GetOtherTextBoxFormats()->GetTextBox(pObject)) @@ -88,11 +90,35 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo uno::Reference<text::XTextContent> xTextFrame( SwXServiceProvider::MakeInstance(SwServiceType::TypeTextFrame, *pShape->GetDoc()), uno::UNO_QUERY); - uno::Reference<text::XTextDocument> xTextDocument( - pShape->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY); - uno::Reference<text::XTextContentAppend> xTextContentAppend(xTextDocument->getText(), - uno::UNO_QUERY); - xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>()); + + uno::Reference<text::XTextRange> xAnchor; + uno::Reference<text::XTextContent> xAnchorProvider(pObject->getWeakUnoShape().get(), + uno::UNO_QUERY); + assert(xAnchorProvider.is()); + if (xAnchorProvider.is()) + xAnchor = xAnchorProvider->getAnchor(); + + uno::Reference<text::XTextContentAppend> xTextContentAppend; + if (xAnchor) + xTextContentAppend.set(xAnchor->getText(), uno::UNO_QUERY); + + if (!xTextContentAppend) + { + uno::Reference<text::XTextDocument> xTextDocument( + pShape->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW); + xTextContentAppend.set(xTextDocument->getText(), uno::UNO_QUERY_THROW); + } + + if (xAnchor) + { + // insertTextContentWithProperties would fail if xAnchor is in a different XText + assert(xAnchor->getText() == xTextContentAppend); + xTextContentAppend->insertTextContentWithProperties(xTextFrame, {}, xAnchor); + } + else + { + xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>()); + } // Link FLY and DRAW formats, so it becomes a text box (needed for syncProperty calls). uno::Reference<text::XTextFrame> xRealTextFrame(xTextFrame, uno::UNO_QUERY);