sw/qa/extras/ooxmlexport/data/tdf73499.docx       |binary
 sw/qa/extras/ooxmlexport/ooxmlexport17.cxx        |   28 ++++++
 writerfilter/source/dmapper/DomainMapper_Impl.cxx |   91 +++++++++++++++++++++-
 3 files changed, 115 insertions(+), 4 deletions(-)

New commits:
commit f81800193a942b3f68c61a5cede634f3eeb47b1f
Author:     Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu>
AuthorDate: Fri Mar 4 08:27:49 2022 +0100
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Tue Mar 29 16:29:39 2022 +0200

    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 <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>

diff --git a/sw/qa/extras/ooxmlexport/data/tdf73499.docx 
b/sw/qa/extras/ooxmlexport/data/tdf73499.docx
new file mode 100644
index 000000000000..605c01e2b3ac
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf73499.docx differ
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!");
     }
 }
 

Reply via email to