diff options
author | Attila Bakos (NISZ) <bakos.attilakaroly@nisz.hu> | 2022-03-04 08:27:49 +0100 |
---|---|---|
committer | László Németh <nemeth@numbertext.org> | 2022-03-29 16:29:39 +0200 |
commit | f81800193a942b3f68c61a5cede634f3eeb47b1f (patch) | |
tree | 8eba4e0b09aa2777edaf9bce62a48833a56a5233 | |
parent | c1ee13b11f78026a323fea7f20d82d7b056ae9bb (diff) |
tdf#73499 DOCX import: fix grouped linked textbox
Only ungrouped text boxes were imported correctly.
Grouped textboxes lost their linking, resulting
broken layout. Now the linking is fixed for DrawingML.
Note: in old MSO versions, linking needed grouping.
To import these DOC documents correctly, convert them
to DOCX/DrawingML in MSO before opening them in Writer.
Change-Id: Ib5a8744d783a9c95c42447d204e17891b3aea7bd
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130950
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r-- | sw/qa/extras/ooxmlexport/data/tdf73499.docx | bin | 0 -> 16470 bytes | |||
-rw-r--r-- | sw/qa/extras/ooxmlexport/ooxmlexport17.cxx | 28 | ||||
-rw-r--r-- | writerfilter/source/dmapper/DomainMapper_Impl.cxx | 91 |
3 files changed, 115 insertions, 4 deletions
diff --git a/sw/qa/extras/ooxmlexport/data/tdf73499.docx b/sw/qa/extras/ooxmlexport/data/tdf73499.docx Binary files differnew file mode 100644 index 000000000000..605c01e2b3ac --- /dev/null +++ b/sw/qa/extras/ooxmlexport/data/tdf73499.docx diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx index 486dc6c3d1e9..53e80df5a301 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport17.cxx @@ -346,6 +346,34 @@ DECLARE_OOXMLEXPORT_TEST(testTdf148111, "tdf148111.docx") CPPUNIT_ASSERT(!xFields->hasMoreElements()); } +DECLARE_OOXMLEXPORT_TEST(TestTdf73499, "tdf73499.docx") +{ + // Ensure, the bugdoc is opened + CPPUNIT_ASSERT(mxComponent); + // Get the groupshape + uno::Reference<drawing::XShapes> xGroup(getShape(1), uno::UNO_QUERY_THROW); + + // Get the textboxes of the groupshape + uno::Reference<text::XText> xTextBox1(xGroup->getByIndex(0), uno::UNO_QUERY_THROW); + uno::Reference<text::XText> xTextBox2(xGroup->getByIndex(1), uno::UNO_QUERY_THROW); + + // Get the properties of the textboxes + uno::Reference<beans::XPropertySet> xTextBox1Properties(xTextBox1, uno::UNO_QUERY_THROW); + uno::Reference<beans::XPropertySet> xTextBox2Properties(xTextBox2, uno::UNO_QUERY_THROW); + + // Get the name of the textboxes + uno::Reference<container::XNamed> xTextBox1Name(xTextBox1, uno::UNO_QUERY_THROW); + uno::Reference<container::XNamed> xTextBox2Name(xTextBox2, uno::UNO_QUERY_THROW); + + // Check for the links, before the fix that were missing + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Link name missing!", xTextBox2Name->getName(), + xTextBox1Properties->getPropertyValue("ChainNextName").get<OUString>()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + "Link name missing!", xTextBox1Name->getName(), + xTextBox2Properties->getPropertyValue("ChainPrevName").get<OUString>()); +} + DECLARE_OOXMLEXPORT_TEST(testTdf81507, "tdf81507.docx") { xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx index a3d6a4f69498..f8700faee88c 100644 --- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx +++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx @@ -4634,20 +4634,103 @@ void DomainMapper_Impl::PopTextBoxContent() void DomainMapper_Impl::AttachTextBoxContentToShape(css::uno::Reference<css::drawing::XShape> xShape) { + // Without textbox or shape pointless to continue if (m_xPendingTextBoxFrames.empty() || !xShape) return; uno::Reference< drawing::XShapes >xGroup(xShape, uno::UNO_QUERY); uno::Reference< beans::XPropertySet >xProps(xShape, uno::UNO_QUERY); + // If this is a group go inside if (xGroup) for (sal_Int32 i = 0; i < xGroup->getCount(); ++i) - AttachTextBoxContentToShape(uno::Reference<drawing::XShape>(xGroup->getByIndex(i),uno::UNO_QUERY_THROW)); + AttachTextBoxContentToShape( + uno::Reference<drawing::XShape>(xGroup->getByIndex(i), uno::UNO_QUERY)); - if (xProps->getPropertyValue("TextBox").get<bool>()) + // if this shape has to be a textbox, attach the frame + if (!xProps->getPropertyValue("TextBox").get<bool>()) + return; + + // if this is a textbox there must be a waiting frame + auto xTextBox = m_xPendingTextBoxFrames.front(); + if (!xTextBox) + return; + + // Pop the pending frames + m_xPendingTextBoxFrames.pop(); + + // Attach the textbox to the shape + try + { + xProps->setPropertyValue("TextBoxContent", uno::Any(xTextBox)); + } + catch (...) + { + SAL_WARN("writerfilter.dmapper", "Exception while trying to attach textboxes!"); + return; + } + + // If attaching is successful, then do the linking + try + { + // Get the name of the textbox + OUString sTextBoxName; + uno::Reference<container::XNamed> xName(xTextBox, uno::UNO_QUERY); + if (xName && !xName->getName().isEmpty()) + sTextBoxName = xName->getName(); + + // Try to get the grabbag + uno::Sequence<beans::PropertyValue> aOldGrabBagSeq; + if (xProps->getPropertySetInfo()->hasPropertyByName("InteropGrabBag")) + xProps->getPropertyValue("InteropGrabBag") >>= aOldGrabBagSeq; + + // If the grabbag successfully get... + if (!aOldGrabBagSeq.hasElements()) + return; + + // Check for the existing linking information + bool bSuccess = false; + beans::PropertyValues aNewGrabBagSeq; + const auto& aHasLink = lcl_getGrabBagValue(aOldGrabBagSeq, "TxbxHasLink"); + + // If there must be a link, do it + if (aHasLink.hasValue() && aHasLink.get<bool>()) + { + auto aLinkProp = comphelper::makePropertyValue("LinkChainName", sTextBoxName); + for (sal_uInt32 i = 0; i < aOldGrabBagSeq.size(); ++i) + { + aNewGrabBagSeq.realloc(i + 1); + // If this is the link name replace it + if (!aOldGrabBagSeq[i].Name.isEmpty() && !aLinkProp.Name.isEmpty() + && (aOldGrabBagSeq[i].Name == aLinkProp.Name)) + { + aNewGrabBagSeq.getArray()[i] = aLinkProp; + bSuccess = true; + } + // else copy + else + aNewGrabBagSeq.getArray()[i] = aOldGrabBagSeq[i]; + } + + // If there was no replacement, append the linking data + if (!bSuccess) + { + aNewGrabBagSeq.realloc(aNewGrabBagSeq.size() + 1); + aNewGrabBagSeq.getArray()[aNewGrabBagSeq.size() - 1] = aLinkProp; + bSuccess = true; + } + } + + // If the linking changed the grabbag, apply the modifications + if (aNewGrabBagSeq.hasElements() && bSuccess) + { + xProps->setPropertyValue("InteropGrabBag", uno::Any(aNewGrabBagSeq)); + m_vTextFramesForChaining.push_back(xShape); + } + } + catch (...) { - xProps->setPropertyValue("TextBoxContent", uno::Any(m_xPendingTextBoxFrames.front())); - m_xPendingTextBoxFrames.pop(); + SAL_WARN("writerfilter.dmapper", "Exception while trying to link textboxes!"); } } |