sw/inc/textboxhelper.hxx                            |   19 +
 sw/inc/unomid.h                                     |    3 
 sw/inc/unoprnms.hxx                                 |    1 
 sw/qa/extras/layout/data/TextBoxFrame.odt           |binary
 sw/qa/extras/layout/layout2.cxx                     |   41 ++++
 sw/qa/uitest/data/ComplexGroupShapeTest.odt         |binary
 sw/qa/uitest/writer_tests2/ComplexGroupShapeTest.py |  127 ++++++++++++
 sw/source/core/doc/docdraw.cxx                      |   56 ++++-
 sw/source/core/doc/textboxhelper.cxx                |  203 +++++++++++++++++++-
 sw/source/core/draw/dcontact.cxx                    |    6 
 sw/source/core/draw/dview.cxx                       |    9 
 sw/source/core/unocore/unodraw.cxx                  |   77 +++++--
 sw/source/core/unocore/unomap.cxx                   |    3 
 13 files changed, 495 insertions(+), 50 deletions(-)

New commits:
commit d4b87c11b451cb08aa950e09efed3cc6fa1422f3
Author:     Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu>
AuthorDate: Tue Nov 30 15:38:26 2021 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Jan 17 09:24:00 2023 +0000

    tdf#143574 sw: textboxes in group shapes -- part 4
    
    A new UNO property has been added and implemented
    for the filters. This provides the possibility of
    assigning textboxes in the filter at import time via UNO.
    
    Follow-up to commit e5650de86072b9db586a4532b5239acda77598c4
    "tdf#143574 sw: textboxes in group shapes - part 3 take 2".
    
    Change-Id: I58c445cb7f6d865c1d82dbe68f985e4c11ff832e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126162
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143366
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 924b3e6b5c91..1a0cadabc0e9 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -60,6 +60,9 @@ public:
     /// the original text in the shape will be copied to the frame
     /// The textbox is created for the shape given by the pObject parameter.
     static void create(SwFrameFormat* pShape, SdrObject* pObject, bool 
bCopyText = false);
+    /// Sets the given textframe as textbox for the given (group member) shape.
+    static void set(SwFrameFormat* pShape, SdrObject* pObject,
+                    css::uno::Reference<css::text::XTextFrame> xNew);
     /// Destroy a TextBox for a shape. If the format has more textboxes
     /// like group shapes, it will destroy only that textbox what belongs
     /// to the given pObject shape.
diff --git a/sw/inc/unomid.h b/sw/inc/unomid.h
index d249b32fc25a..9f413509ae1c 100644
--- a/sw/inc/unomid.h
+++ b/sw/inc/unomid.h
@@ -151,6 +151,9 @@
 // SwFormatFollowTextFlow
 #define MID_FOLLOW_TEXT_FLOW    0
 
+#define MID_TEXT_BOX            0
+#define MID_TEXT_BOX_CONTENT    1
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 3a8df7c69182..bb3ee1f47b3c 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -74,6 +74,7 @@
 #define UNO_NAME_FOOTER_RIGHT_MARGIN "FooterRightMargin"
 #define UNO_NAME_TEXT_RANGE "TextRange"
 #define UNO_NAME_TEXT_BOX "TextBox"
+#define UNO_NAME_TEXT_BOX_CONTENT "TextBoxContent"
 #define UNO_NAME_NAME "Name"
 #define UNO_NAME_CHAR_STYLE_NAME "CharStyleName"
 #define UNO_NAME_ANCHOR_CHAR_STYLE_NAME "AnchorCharStyleName"
diff --git a/sw/qa/extras/layout/data/TextBoxFrame.odt 
b/sw/qa/extras/layout/data/TextBoxFrame.odt
new file mode 100644
index 000000000000..a6155e34fdfb
Binary files /dev/null and b/sw/qa/extras/layout/data/TextBoxFrame.odt differ
diff --git a/sw/qa/extras/layout/layout2.cxx b/sw/qa/extras/layout/layout2.cxx
index 466f640beeee..9fd595eafefc 100644
--- a/sw/qa/extras/layout/layout2.cxx
+++ b/sw/qa/extras/layout/layout2.cxx
@@ -1647,6 +1647,47 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf141220)
     CPPUNIT_ASSERT_LESS(static_cast<sal_Int32>(15), nTextBoxTop - nShapeTop);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, TestTextBoxChangeViaUNO)
+{
+    CPPUNIT_ASSERT(createSwDoc(DATA_DIRECTORY, "TextBoxFrame.odt"));
+    // this file has a shape and a frame inside. Try to set up
+    // the frame for the shape as textbox. Before this was not
+    // implemented. This will be necesary for proper WPG import.
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("There must be a shape and a frame!", 2, 
getShapes());
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("This must be a custom shape!",
+                                 OUString("com.sun.star.drawing.CustomShape"),
+                                 getShape(1)->getShapeType());
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("This must be a frame shape!", 
OUString("FrameShape"),
+                                 getShape(2)->getShapeType());
+
+    CPPUNIT_ASSERT_MESSAGE("This is not supposed to be a textbox!",
+                           !uno::Reference<beans::XPropertySet>(getShape(1), 
uno::UNO_QUERY_THROW)
+                                ->getPropertyValue("TextBox")
+                                .get<bool>());
+    // Without the fix it will crash at this line:
+    CPPUNIT_ASSERT_MESSAGE("This is not supposed to be a textbox!",
+                           !uno::Reference<beans::XPropertySet>(getShape(1), 
uno::UNO_QUERY_THROW)
+                                ->getPropertyValue("TextBoxContent")
+                                .hasValue());
+
+    // So now set the frame as textbox for the shape!
+    uno::Reference<beans::XPropertySet>(getShape(1), uno::UNO_QUERY_THROW)
+        ->setPropertyValue("TextBoxContent", 
uno::Any(uno::Reference<text::XTextFrame>(
+                                                 getShape(2), 
uno::UNO_QUERY_THROW)));
+
+    CPPUNIT_ASSERT_MESSAGE("This is supposed to be a textbox!",
+                           uno::Reference<beans::XPropertySet>(getShape(1), 
uno::UNO_QUERY_THROW)
+                               ->getPropertyValue("TextBox")
+                               .get<bool>());
+
+    CPPUNIT_ASSERT_MESSAGE("This is supposed to be a textbox!",
+                           uno::Reference<beans::XPropertySet>(getShape(1), 
uno::UNO_QUERY_THROW)
+                               ->getPropertyValue("TextBoxContent")
+                               .hasValue());
+}
+
 CPPUNIT_TEST_FIXTURE(SwLayoutWriter2, testTdf121509)
 {
     auto pDoc = createSwDoc(DATA_DIRECTORY, "Tdf121509.odt");
diff --git a/sw/source/core/doc/textboxhelper.cxx 
b/sw/source/core/doc/textboxhelper.cxx
index 7889fd443b89..1b9155f9b6e8 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -199,6 +199,127 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, 
SdrObject* pObject, bool bCo
     }
 }
 
+void SwTextBoxHelper::set(SwFrameFormat* pShapeFormat, SdrObject* pObj,
+                          uno::Reference<text::XTextFrame> xNew)
+{
+    // Do not set invalid data
+    assert(pShapeFormat && pObj && xNew);
+    // Firstly find the format of the new textbox.
+    SwFrameFormat* pFormat = nullptr;
+    if (auto pTextFrame = dynamic_cast<SwXTextFrame*>(xNew.get()))
+        pFormat = pTextFrame->GetFrameFormat();
+    if (!pFormat)
+        return;
+    std::vector<std::pair<beans::Property, uno::Any>> aOldProps;
+    // If there is a format, check if the shape already has a textbox assigned 
to.
+    if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormat())
+    {
+        // If it has a texbox, destroy it.
+        if (pTextBoxNode->GetTextBox(pObj))
+        {
+            auto xOldFrame
+                = 
pObj->getUnoShape()->queryInterface(cppu::UnoType<text::XTextRange>::get());
+            if (xOldFrame.hasValue())
+            {
+                uno::Reference<beans::XPropertySet> xOldprops(xOldFrame, 
uno::UNO_QUERY);
+                uno::Reference<beans::XPropertyState> 
xOldPropStates(xOldFrame, uno::UNO_QUERY);
+                for (auto& rProp : 
xOldprops->getPropertySetInfo()->getProperties())
+                {
+                    try
+                    {
+                        if (xOldPropStates->getPropertyState(rProp.Name)
+                            == 
beans::PropertyState::PropertyState_DIRECT_VALUE)
+                            aOldProps.push_back(
+                                std::pair(rProp, 
xOldprops->getPropertyValue(rProp.Name)));
+                    }
+                    catch (...)
+                    {
+                    }
+                }
+            }
+            destroy(pShapeFormat, pObj);
+        }
+        // And set the new one.
+        pTextBoxNode->AddTextBox(pObj, pFormat);
+        pFormat->SetOtherTextBoxFormat(pTextBoxNode);
+    }
+    else
+    {
+        // If the shape do not have a texbox node and textbox,
+        // create that for the shape.
+        auto* pTextBox = new SwTextBoxNode(pShapeFormat);
+        pTextBox->AddTextBox(pObj, pFormat);
+        pShapeFormat->SetOtherTextBoxFormat(pTextBox);
+        pFormat->SetOtherTextBoxFormat(pTextBox);
+    }
+    // Initialize its properties
+    uno::Reference<beans::XPropertySet> xPropertySet(xNew, uno::UNO_QUERY);
+    uno::Any aEmptyBorder = uno::makeAny(table::BorderLine2());
+    xPropertySet->setPropertyValue(UNO_NAME_TOP_BORDER, aEmptyBorder);
+    xPropertySet->setPropertyValue(UNO_NAME_BOTTOM_BORDER, aEmptyBorder);
+    xPropertySet->setPropertyValue(UNO_NAME_LEFT_BORDER, aEmptyBorder);
+    xPropertySet->setPropertyValue(UNO_NAME_RIGHT_BORDER, aEmptyBorder);
+    xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, 
uno::makeAny(sal_Int32(100)));
+    xPropertySet->setPropertyValue(UNO_NAME_SIZE_TYPE, 
uno::makeAny(text::SizeType::FIX));
+    xPropertySet->setPropertyValue(UNO_NAME_SURROUND, 
uno::makeAny(text::WrapTextMode_THROUGH));
+    // Add a new name to it
+    uno::Reference<container::XNamed> xNamed(xNew, uno::UNO_QUERY);
+    xNamed->setName(pShapeFormat->GetDoc()->GetUniqueFrameName());
+    // And sync. properties.
+    uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), 
uno::UNO_QUERY);
+    syncProperty(pShapeFormat, RES_FRM_SIZE, MID_FRMSIZE_SIZE, 
uno::makeAny(xShape->getSize()),
+                 pObj);
+    uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, 
uno::UNO_QUERY);
+    syncProperty(pShapeFormat, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
+                 xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE), 
pObj);
+    syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
+                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT), 
pObj);
+    syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
+                 
xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION), pObj);
+    syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
+                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT), 
pObj);
+    syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
+                 
xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION), pObj);
+    syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
+                 
xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION), pObj);
+    syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
+                 
xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION), pObj);
+    syncProperty(pShapeFormat, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
+                 
xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT), pObj);
+    drawing::TextVerticalAdjust aVertAdj = drawing::TextVerticalAdjust_CENTER;
+    if ((uno::Reference<beans::XPropertyState>(xShape, uno::UNO_QUERY_THROW))
+            ->getPropertyState(UNO_NAME_TEXT_VERT_ADJUST)
+        != beans::PropertyState::PropertyState_DEFAULT_VALUE)
+    {
+        aVertAdj = 
xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST)
+                       .get<drawing::TextVerticalAdjust>();
+    }
+    xPropertySet->setPropertyValue(UNO_NAME_TEXT_VERT_ADJUST, 
uno::makeAny(aVertAdj));
+    text::WritingMode eMode;
+    if (xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE) >>= 
eMode)
+        syncProperty(pShapeFormat, RES_FRAMEDIR, 0, 
uno::makeAny(sal_Int16(eMode)), pObj);
+    if (aOldProps.size())
+    {
+        for (auto& rProp : aOldProps)
+        {
+            try
+            {
+                xPropertySet->setPropertyValue(rProp.first.Name, rProp.second);
+            }
+            catch (...)
+            {
+            }
+        }
+    }
+    if (pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
+        && pFormat->GetAnchor().GetPageNum() == 0)
+    {
+        pFormat->SetFormatAttr(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, 1));
+    }
+    // Do sync for the new textframe.
+    synchronizeGroupTextBoxProperty(&changeAnchor, pShapeFormat, pObj);
+}
+
 void SwTextBoxHelper::destroy(const SwFrameFormat* pShape, const SdrObject* 
pObject)
 {
     // If a TextBox was enabled previously
diff --git a/sw/source/core/unocore/unodraw.cxx 
b/sw/source/core/unocore/unodraw.cxx
index 4d0b404e9a1c..1104df24085a 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -1164,18 +1164,29 @@ void SwXShape::setPropertyValue(const OUString& 
rPropertyName, const uno::Any& a
             }
             else if (pEntry->nWID == FN_TEXT_BOX)
             {
-                bool bValue(false);
-                aValue >>= bValue;
-                if (bValue)
-                    SwTextBoxHelper::create(pFormat, 
GetSvxShape()->GetSdrObject());
-                else
-                    SwTextBoxHelper::destroy(pFormat, 
GetSvxShape()->GetSdrObject());
-
+                if (pEntry->nMemberId == MID_TEXT_BOX)
+                {
+                    bool bValue(false);
+                    aValue >>= bValue;
+                    if (bValue)
+                        SwTextBoxHelper::create(pFormat, 
GetSvxShape()->GetSdrObject());
+                    else
+                        SwTextBoxHelper::destroy(pFormat, 
GetSvxShape()->GetSdrObject());
+                }
+                else if (pEntry->nMemberId == MID_TEXT_BOX_CONTENT)
+                {
+                    if (aValue.getValueType() == 
cppu::UnoType<uno::Reference<text::XTextFrame>>::get())
+                        SwTextBoxHelper::set(pFormat, 
GetSvxShape()->GetSdrObject(),
+                                             
aValue.get<uno::Reference<text::XTextFrame>>());
+                    else
+                        SAL_WARN( "sw.uno", "This is not a TextFrame!" );
+                }
             }
             else if (pEntry->nWID == RES_CHAIN)
             {
                 if (pEntry->nMemberId == MID_CHAIN_NEXTNAME || 
pEntry->nMemberId == MID_CHAIN_PREVNAME)
-                    SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, 
pEntry->nMemberId, aValue);
+                    SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, 
pEntry->nMemberId, aValue,
+                                                  
SdrObject::getSdrObjectFromXShape(mxShape));
             }
             // #i28749#
             else if ( FN_SHAPE_POSITION_LAYOUT_DIR == pEntry->nWID )
@@ -1346,7 +1357,8 @@ void SwXShape::setPropertyValue(const OUString& 
rPropertyName, const uno::Any& a
                     pFormat->SetFormatAttr(aSet);
             }
             // We have a pFormat and a pEntry as well: try to sync TextBox 
property.
-            SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, 
pEntry->nMemberId, aValue);
+            SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, 
pEntry->nMemberId, aValue,
+                                          
SdrObject::getSdrObjectFromXShape(mxShape));
         }
         else
         {
@@ -1436,7 +1448,8 @@ void SwXShape::setPropertyValue(const OUString& 
rPropertyName, const uno::Any& a
         if (pFormat)
         {
             // We have a pFormat (but no pEntry): try to sync TextBox property.
-            SwTextBoxHelper::syncProperty(pFormat, rPropertyName, aValue);
+            SwTextBoxHelper::syncProperty(pFormat, rPropertyName, aValue,
+                                          
SdrObject::getSdrObjectFromXShape(mxShape));
         }
 
         // #i31698# - restore object position, if caption point is set.
@@ -1517,12 +1530,25 @@ uno::Any SwXShape::getPropertyValue(const OUString& 
rPropertyName)
                 }
                 else if (pEntry->nWID == FN_TEXT_BOX)
                 {
-                    auto pSvxShape = GetSvxShape();
-                    bool bValue = SwTextBoxHelper::isTextBox(
-                        pFormat, RES_DRAWFRMFMT,
-                        ((pSvxShape && pSvxShape->GetSdrObject()) ? 
pSvxShape->GetSdrObject()
-                                                                  : 
pFormat->FindRealSdrObject()));
-                    aRet <<= bValue;
+                    if (pEntry->nMemberId == MID_TEXT_BOX)
+                    {
+                        auto pSvxShape = GetSvxShape();
+                        bool bValue = SwTextBoxHelper::isTextBox(
+                            pFormat, RES_DRAWFRMFMT,
+                            ((pSvxShape && pSvxShape->GetSdrObject()) ? 
pSvxShape->GetSdrObject()
+                                : pFormat->FindRealSdrObject()));
+                        aRet <<= bValue;
+                    }
+                    else if (pEntry->nMemberId == MID_TEXT_BOX_CONTENT)
+                    {
+                        auto pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+                        auto xRange = SwTextBoxHelper::queryInterface(
+                            pFormat, cppu::UnoType<text::XText>::get(),
+                            pObj ? pObj : pFormat->FindRealSdrObject());
+                        uno::Reference<text::XTextFrame> xFrame(xRange, 
uno::UNO_QUERY);
+                        if (xFrame.is())
+                            aRet <<= xFrame;
+                    }
                 }
                 else if (pEntry->nWID == RES_CHAIN)
                 {
@@ -1803,7 +1829,9 @@ uno::Sequence< beans::PropertyState > 
SwXShape::getPropertyStates(
             else if (pEntry->nWID == FN_TEXT_BOX)
             {
                 // The TextBox property is set, if we can find a textbox for 
this shape.
-                if (pFormat && SwTextBoxHelper::isTextBox(pFormat, 
RES_DRAWFRMFMT))
+                if (pFormat
+                    && SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT,
+                                                  
SdrObject::getSdrObjectFromXShape(mxShape)))
                     pRet[nProperty] = beans::PropertyState_DIRECT_VALUE;
                 else
                     pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE;
diff --git a/sw/source/core/unocore/unomap.cxx 
b/sw/source/core/unocore/unomap.cxx
index abad86f1ce65..db62cc990d69 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -291,7 +291,8 @@ const SfxItemPropertyMapEntry* 
SwUnoPropertyMapProvider::GetPropertyMapEntries(s
                     { u"" UNO_NAME_RELATIVE_HEIGHT_RELATION, RES_FRM_SIZE, 
cppu::UnoType<sal_Int16>::get(),      PROPERTY_NONE, 
MID_FRMSIZE_REL_HEIGHT_RELATION },
                     { u"" UNO_NAME_RELATIVE_WIDTH, RES_FRM_SIZE,      
cppu::UnoType<sal_Int16>::get()  ,         PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH 
 },
                     { u"" UNO_NAME_RELATIVE_WIDTH_RELATION, RES_FRM_SIZE, 
cppu::UnoType<sal_Int16>::get(),       PROPERTY_NONE, 
MID_FRMSIZE_REL_WIDTH_RELATION },
-                    { u"" UNO_NAME_TEXT_BOX, FN_TEXT_BOX, 
cppu::UnoType<bool>::get(), PROPERTY_NONE, 0},
+                    { u"" UNO_NAME_TEXT_BOX, FN_TEXT_BOX, 
cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TEXT_BOX},
+                    { u"" UNO_NAME_TEXT_BOX_CONTENT, FN_TEXT_BOX, 
cppu::UnoType<text::XTextFrame>::get(), PROPERTY_NONE, MID_TEXT_BOX_CONTENT},
                     { u"" UNO_NAME_CHAIN_NEXT_NAME, RES_CHAIN,                
cppu::UnoType<OUString>::get(),            PropertyAttribute::MAYBEVOID 
,MID_CHAIN_NEXTNAME},
                     { u"" UNO_NAME_CHAIN_PREV_NAME, RES_CHAIN,                
cppu::UnoType<OUString>::get(),            PropertyAttribute::MAYBEVOID 
,MID_CHAIN_PREVNAME},
                     { u"" UNO_NAME_CHAIN_NAME,      RES_CHAIN,                
cppu::UnoType<OUString>::get(),            PropertyAttribute::MAYBEVOID 
,MID_CHAIN_NAME    },
commit d3daa7ed0361785d8667f726340538ada1607937
Author:     Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu>
AuthorDate: Mon Nov 29 14:37:20 2021 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Jan 17 09:23:51 2023 +0000

    tdf#143574 sw: textboxes in group shapes - part 3 take 2
    
    In this part, missing parameters have been fixed, and
    queryInterface method can handle textbox groups now.
    
    A new function, synchronizeGroupTextBoxProperty has been
    introduced to do the sync for all group members. Nested
    group textbox shape handling also has been introduced.
    
    Note: Copy still has issues.
    
    Change-Id: I3d2090fe6a4066edfd2cb417b30bca9dd9acb011
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/126052
    Tested-by: László Németh <nem...@numbertext.org>
    Reviewed-by: László Németh <nem...@numbertext.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/143365
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 2e5b27cfccb0..924b3e6b5c91 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -65,7 +65,8 @@ public:
     /// to the given pObject shape.
     static void destroy(const SwFrameFormat* pShape, const SdrObject* pObject);
     /// Get interface of a shape's TextBox, if there is any.
-    static css::uno::Any queryInterface(const SwFrameFormat* pShape, const 
css::uno::Type& rType);
+    static css::uno::Any queryInterface(const SwFrameFormat* pShape, const 
css::uno::Type& rType,
+                                        SdrObject* pObj);
 
     /// Sync property of TextBox with the one of the shape.
     static void syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 
nMemberID,
@@ -107,6 +108,9 @@ public:
     /// this function, and returns true in that case too.
     static std::optional<bool> isAnchorTypeDifferent(const SwFrameFormat* 
pShape);
 
+    /// Sets the correct size of textframe depending on the given SdrObject.
+    static bool syncTextBoxSize(SwFrameFormat* pShape, SdrObject* pObj);
+
     /// Returns true if the given shape has a valid textframe.
     static bool isTextBoxShapeHasValidTextFrame(const SwFrameFormat* pShape);
 
@@ -177,6 +181,14 @@ public:
     /// Undo the effect of saveLinks() + individual resetLink() calls.
     static void restoreLinks(std::set<ZSortFly>& rOld, 
std::vector<SwFrameFormat*>& rNew,
                              SavedLink& rSavedLinks);
+
+    /// Calls the method given by pFunc with every textboxes of the group 
given by pFormat.
+    static void synchronizeGroupTextBoxProperty(bool pFunc(SwFrameFormat*, 
SdrObject*),
+                                                SwFrameFormat* pFormat, 
SdrObject* pObj);
+    /// Collect all textboxes of the group given by the pGoupObj Parameter. 
Returns with a
+    /// vector filled with the textboxes.
+    static std::vector<SwFrameFormat*> CollectTextBoxes(SdrObject* 
pGroupObject,
+                                                        SwFrameFormat* 
pFormat);
 };
 
 /// Textboxes are basically textframe + shape pairs. This means one shape has 
one frame.
@@ -242,6 +254,8 @@ public:
     SwFrameFormat* GetOwnerShape() { return m_pOwnerShapeFormat; };
     // This will give the current number of textboxes.
     size_t GetTextBoxCount() const { return m_pTextBoxes.size(); };
+    // Returns with a const collection of textboxes owned by this node.
+    std::map<SdrObject*, SwFrameFormat*> GetAllTextBoxes() const;
 };
 
 #endif // INCLUDED_SW_INC_TEXTBOXHELPER_HXX
diff --git a/sw/qa/uitest/data/ComplexGroupShapeTest.odt 
b/sw/qa/uitest/data/ComplexGroupShapeTest.odt
new file mode 100644
index 000000000000..8fe093203690
Binary files /dev/null and b/sw/qa/uitest/data/ComplexGroupShapeTest.odt differ
diff --git a/sw/qa/uitest/writer_tests2/ComplexGroupShapeTest.py 
b/sw/qa/uitest/writer_tests2/ComplexGroupShapeTest.py
new file mode 100644
index 000000000000..7e219d8d7976
--- /dev/null
+++ b/sw/qa/uitest/writer_tests2/ComplexGroupShapeTest.py
@@ -0,0 +1,127 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+from uitest.framework import UITestCase
+from uitest.uihelper.common import get_state_as_dict
+from uitest.uihelper.common import select_pos
+from uitest.uihelper.common import get_url_for_data_file
+from libreoffice.uno.propertyvalue import mkPropertyValues
+import time
+
+class ComplexGroupShapeTest(UITestCase):
+    def test_ComplexGroupShape(self):
+        with 
self.ui_test.load_file(get_url_for_data_file("ComplexGroupShapeTest.odt")):
+            xWriterDoc = self.xUITest.getTopFocusWindow()
+            xWriterEdit = xWriterDoc.getChild("writer_edit")
+            document = self.ui_test.get_component()
+
+            # check the shape type
+            self.assertEqual("com.sun.star.drawing.GroupShape", 
document.DrawPage.getByIndex(1).ShapeType)
+
+            # select the shape
+            self.xUITest.executeCommand(".uno:JumpToNextFrame")
+            self.ui_test.wait_until_child_is_available('metricfield')
+
+            # go inside the group
+            self.xUITest.executeCommand(".uno:EnterGroup")
+
+            # select a shape in the group
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+
+            # add a textbox to this subshape
+            self.xUITest.executeCommand(".uno:AddTextBox")
+
+            # select the next shape in the group
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+
+            # add a textbox to this subshape
+            self.xUITest.executeCommand(".uno:AddTextBox")
+
+            # leave the groupshape
+            self.xUITest.executeCommand(".uno:LeaveGroup")
+
+            # select the other shape
+            self.xUITest.executeCommand(".uno:JumpToNextFrame")
+            self.ui_test.wait_until_child_is_available('metricfield')
+
+            # get the current selection
+            ShapeCollection = document.getCurrentSelection()
+
+            # extend the selection with the grouped shape
+            ShapeCollection.add(document.DrawPage.getByIndex(0))
+            ShapeCollection.add(document.DrawPage.getByIndex(1))
+
+            # select these shapes
+            document.getCurrentController().select(ShapeCollection)
+
+            # do ungroup
+            self.xUITest.executeCommand(".uno:FormatGroup")
+
+            # deselect
+            xWriterEdit.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"ESC"}))
+            time.sleep(0.1)
+
+            # select the group
+            self.xUITest.executeCommand(".uno:JumpToNextFrame")
+            self.ui_test.wait_until_child_is_available('metricfield')
+
+            # move it down
+            for i in range(1, 30):
+                xWriterEdit.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"DOWN"}))
+                time.sleep(0.1)
+
+            # select again
+            self.xUITest.executeCommand(".uno:JumpToNextFrame")
+            self.ui_test.wait_until_child_is_available('metricfield')
+
+            # do ungroup
+            self.xUITest.executeCommand(".uno:FormatUngroup")
+
+            # deselect everything
+            xWriterEdit.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"ESC"}))
+            time.sleep(0.1)
+
+            # select the first ex-group member shape
+            self.xUITest.executeCommand(".uno:JumpToNextFrame")
+            self.ui_test.wait_until_child_is_available('metricfield')
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+
+            # check if it is a textbox
+            
self.assertEqual(True,document.getCurrentSelection().getByIndex(0).TextBox)
+
+            # go to the other one
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+
+            # this is still a group, so it cannot be a textbox
+            
self.assertEqual(False,document.getCurrentSelection().getByIndex(0).TextBox)
+
+            # do ungroup
+            self.xUITest.executeCommand(".uno:FormatUngroup")
+
+            # deselect
+            xWriterEdit.executeAction("TYPE", 
mkPropertyValues({"KEYCODE":"ESC"}))
+            time.sleep(0.1)
+
+            # select one shape of the last group
+            self.xUITest.executeCommand(".uno:JumpToNextFrame")
+            self.ui_test.wait_until_child_is_available('metricfield')
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+            xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": 
"TAB"}))
+
+            # check if it is a textbox
+            
self.assertEqual(True,document.getCurrentSelection().getByIndex(0).TextBox)
+
+            # Without the fix in place, the following problems occurred during 
this test:
+            # - After the grouping old textbox frames detached from their 
shape before
+            # - Moving caused messed layout
+            # - After ungroup, the shapes in the embed group lost their textbox
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/doc/docdraw.cxx b/sw/source/core/doc/docdraw.cxx
index 0aff4b8993ff..6445ab757a0e 100644
--- a/sw/source/core/doc/docdraw.cxx
+++ b/sw/source/core/doc/docdraw.cxx
@@ -209,7 +209,7 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
             bGroupMembersNotPositioned = pAnchoredDrawObj->NotYetPositioned();
         }
 
-        std::vector<std::pair<SwFrameFormat*, SdrObject*>> vSavedTextBoxes;
+        std::map<const SdrObject*, SwFrameFormat*> vSavedTextBoxes;
         // Destroy ContactObjects and formats.
         for( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
         {
@@ -224,8 +224,10 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
                     "<SwDoc::GroupSelection(..)> - group members have 
different positioning status!" );
 #endif
             // Before the format will be killed, save its textbox for later 
use.
-            if (auto pTextBox = 
SwTextBoxHelper::getOtherTextBoxFormat(pContact->GetFormat(), RES_DRAWFRMFMT, 
pObj))
-                vSavedTextBoxes.push_back(std::pair<SwFrameFormat*, 
SdrObject*>(pTextBox, pObj));
+            if (auto pShapeFormat = pContact->GetFormat())
+                if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormat())
+                    for (const auto& rTextBoxElement : 
pTextBoxNode->GetAllTextBoxes())
+                        vSavedTextBoxes.emplace(rTextBoxElement);
 
             pFormat = static_cast<SwDrawFrameFormat*>(pContact->GetFormat());
             // Deletes itself!
@@ -254,10 +256,11 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
 
         // Add the saved textboxes to the new format.
         auto pTextBoxNode = new SwTextBoxNode(pFormat);
-        for (auto& pTextBoxEntry : vSavedTextBoxes)
+        for (const auto& pTextBoxEntry : vSavedTextBoxes)
         {
-            pTextBoxNode->AddTextBox(pTextBoxEntry.second, 
pTextBoxEntry.first);
-            pTextBoxEntry.first->SetOtherTextBoxFormat(pTextBoxNode);
+            
pTextBoxNode->AddTextBox(const_cast<SdrObject*>(pTextBoxEntry.first),
+                                     pTextBoxEntry.second);
+            pTextBoxEntry.second->SetOtherTextBoxFormat(pTextBoxNode);
         }
         pFormat->SetOtherTextBoxFormat(pTextBoxNode);
         vSavedTextBoxes.clear();
@@ -299,6 +302,27 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
     return pNewContact;
 }
 
+static void lcl_CollectTextBoxesForSubGroupObj(SwFrameFormat* pTargetFormat, 
SwTextBoxNode* pTextBoxNode,
+                                               SdrObject* pSourceObjs)
+{
+    if (auto pChildrenObjs = pSourceObjs->getChildrenOfSdrObject())
+        for (size_t i = 0; i < pChildrenObjs->GetObjCount(); ++i)
+            lcl_CollectTextBoxesForSubGroupObj(pTargetFormat, pTextBoxNode, 
pChildrenObjs->GetObj(i));
+    else
+    {
+        if (auto pTextBox = pTextBoxNode->GetTextBox(pSourceObjs))
+        {
+            if (!pTargetFormat->GetOtherTextBoxFormat())
+            {
+                pTargetFormat->SetOtherTextBoxFormat(new 
SwTextBoxNode(pTargetFormat));
+            }
+            pTargetFormat->GetOtherTextBoxFormat()->AddTextBox(pSourceObjs, 
pTextBox);
+            
pTextBox->SetOtherTextBoxFormat(pTargetFormat->GetOtherTextBoxFormat());
+        }
+    }
+}
+
+
 void SwDoc::UnGroupSelection( SdrView& rDrawView )
 {
     bool const bUndo = GetIDocumentUndoRedo().DoesUndo();
@@ -349,14 +373,22 @@ void SwDoc::UnGroupSelection( SdrView& rDrawView )
                         pFormat->SetFormatAttr( aAnch );
 
                         if (pTextBoxNode)
-                            if (auto pTextBoxFormat = 
pTextBoxNode->GetTextBox(pSubObj))
+                        {
+                            if (!pObj->getChildrenOfSdrObject())
                             {
-                                auto pNewTextBoxNode = new 
SwTextBoxNode(pFormat);
-                                pNewTextBoxNode->AddTextBox(pSubObj, 
pTextBoxFormat);
-                                
pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
-                                
pTextBoxFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
+                                if (auto pTextBoxFormat = 
pTextBoxNode->GetTextBox(pSubObj))
+                                {
+                                    auto pNewTextBoxNode = new 
SwTextBoxNode(pFormat);
+                                    pNewTextBoxNode->AddTextBox(pSubObj, 
pTextBoxFormat);
+                                    
pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
+                                    
pTextBoxFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
+                                }
                             }
-
+                            else
+                            {
+                                lcl_CollectTextBoxesForSubGroupObj(pFormat, 
pTextBoxNode, pSubObj);
+                            }
+                        }
                         // #i36010# - set layout direction of the position
                         pFormat->SetPositionLayoutDir(
                             
text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
diff --git a/sw/source/core/doc/textboxhelper.cxx 
b/sw/source/core/doc/textboxhelper.cxx
index 4cfebf732b1c..7889fd443b89 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -359,7 +359,8 @@ SwFrameFormat* 
SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference<drawing::XS
         return nullptr;
 
     SwFrameFormat* pFormat = pShape->GetFrameFormat();
-    return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT);
+    return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT,
+                                 SdrObject::getSdrObjectFromXShape(xShape));
 }
 
 uno::Reference<text::XTextFrame>
@@ -380,9 +381,11 @@ 
SwTextBoxHelper::getUnoTextFrame(uno::Reference<drawing::XShape> const& xShape)
     return {};
 }
 
-template <typename T> static void lcl_queryInterface(const SwFrameFormat* 
pShape, uno::Any& rAny)
+template <typename T>
+static void lcl_queryInterface(const SwFrameFormat* pShape, uno::Any& rAny, 
SdrObject* pObj)
 {
-    if (SwFrameFormat* pFormat = 
SwTextBoxHelper::getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+    if (SwFrameFormat* pFormat
+        = SwTextBoxHelper::getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
     {
         uno::Reference<T> const xInterface(
             SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), 
uno::UNO_QUERY);
@@ -390,21 +393,22 @@ template <typename T> static void 
lcl_queryInterface(const SwFrameFormat* pShape
     }
 }
 
-uno::Any SwTextBoxHelper::queryInterface(const SwFrameFormat* pShape, const 
uno::Type& rType)
+uno::Any SwTextBoxHelper::queryInterface(const SwFrameFormat* pShape, const 
uno::Type& rType,
+                                         SdrObject* pObj)
 {
     uno::Any aRet;
 
     if (rType == cppu::UnoType<css::text::XTextAppend>::get())
     {
-        lcl_queryInterface<text::XTextAppend>(pShape, aRet);
+        lcl_queryInterface<text::XTextAppend>(pShape, aRet, pObj);
     }
     else if (rType == cppu::UnoType<css::text::XText>::get())
     {
-        lcl_queryInterface<text::XText>(pShape, aRet);
+        lcl_queryInterface<text::XText>(pShape, aRet, pObj);
     }
     else if (rType == cppu::UnoType<css::text::XTextRange>::get())
     {
-        lcl_queryInterface<text::XTextRange>(pShape, aRet);
+        lcl_queryInterface<text::XTextRange>(pShape, aRet, pObj);
     }
 
     return aRet;
@@ -1300,6 +1304,25 @@ std::optional<bool> 
SwTextBoxHelper::isAnchorTypeDifferent(const SwFrameFormat*
     return bRet;
 }
 
+bool SwTextBoxHelper::syncTextBoxSize(SwFrameFormat* pShape, SdrObject* pObj)
+{
+    if (!pShape || !pObj)
+        return false;
+
+    if (auto pTextBox = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
+    {
+        const auto& rSize = getTextRectangle(pObj, false).GetSize();
+        if (!rSize.IsEmpty())
+        {
+            SwFormatFrameSize aSize(pTextBox->GetFrameSize());
+            aSize.SetSize(rSize);
+            return pTextBox->SetFormatAttr(aSize);
+        }
+    }
+
+    return false;
+}
+
 bool SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(const SwFrameFormat* 
pShape)
 {
     if (pShape && pShape->Which() == RES_DRAWFRMFMT)
@@ -1374,6 +1397,41 @@ bool 
SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape, const Sdr
     return false;
 }
 
+void SwTextBoxHelper::synchronizeGroupTextBoxProperty(bool 
pFunc(SwFrameFormat*, SdrObject*),
+                                                      SwFrameFormat* pShape, 
SdrObject* pObj)
+{
+    if (auto pChildren = pObj->getChildrenOfSdrObject())
+    {
+        for (size_t i = 0; i < pChildren->GetObjCount(); ++i)
+            synchronizeGroupTextBoxProperty(pFunc, pShape, 
pChildren->GetObj(i));
+    }
+    else
+    {
+        (*pFunc)(pShape, pObj);
+    }
+}
+
+std::vector<SwFrameFormat*> SwTextBoxHelper::CollectTextBoxes(SdrObject* 
pGroupObject,
+                                                              SwFrameFormat* 
pFormat)
+{
+    std::vector<SwFrameFormat*> vRet;
+    if (auto pChildren = pGroupObject->getChildrenOfSdrObject())
+    {
+        for (size_t i = 0; i < pChildren->GetObjCount(); ++i)
+        {
+            auto pChildTextBoxes = CollectTextBoxes(pChildren->GetObj(i), 
pFormat);
+            for (auto& rChildTextBox : pChildTextBoxes)
+                vRet.push_back(rChildTextBox);
+        }
+    }
+    else
+    {
+        if (isTextBox(pFormat, RES_DRAWFRMFMT, pGroupObject))
+            vRet.push_back(getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT, 
pGroupObject));
+    }
+    return vRet;
+}
+
 SwTextBoxNode::SwTextBoxNode(SwFrameFormat* pOwnerShape)
 {
     assert(pOwnerShape);
@@ -1497,4 +1555,14 @@ void SwTextBoxNode::SetTextBoxInactive(const SdrObject* 
pDrawObject)
 
 bool SwTextBoxNode::IsGroupTextBox() const { return m_pTextBoxes.size() > 1; }
 
+std::map<SdrObject*, SwFrameFormat*> SwTextBoxNode::GetAllTextBoxes() const
+{
+    std::map<SdrObject*, SwFrameFormat*> aRet;
+    for (auto& rElem : m_pTextBoxes)
+    {
+        aRet.emplace(rElem.m_pDrawObject, rElem.m_pTextBoxFormat);
+    }
+    return aRet;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 9af2c7162111..13bc5bd3f338 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1250,10 +1250,8 @@ void SwDrawContact::Changed_( const SdrObject& rObj,
                     // use geometry of drawing object
                     aObjRect = pGroupObj->GetSnapRect();
 
-                    for (size_t i = 0; i < 
pGroupObj->getChildrenOfSdrObject()->GetObjCount(); ++i )
-                    {
-                        SwTextBoxHelper::doTextBoxPositioning(GetFormat(), 
pGroupObj->getChildrenOfSdrObject()->GetObj(i));
-                    }
+                    
SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::changeAnchor,
 GetFormat(), &const_cast<SdrObject&>(rObj));
+                    
SwTextBoxHelper::synchronizeGroupTextBoxProperty(&SwTextBoxHelper::syncTextBoxSize,
 GetFormat(), &const_cast<SdrObject&>(rObj));
 
                 }
                 SwTwips nXPosDiff(0);
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index 510addf10a9c..12b955d04ee5 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -967,12 +967,11 @@ void SwDrawView::DeleteMarked()
         SdrObject *pObject = rMarkList.GetMark(i)->GetMarkedSdrObj();
         SwContact* pContact = GetUserCall(pObject);
         SwFrameFormat* pFormat = pContact->GetFormat();
-        if (auto pChildren = pObject->getChildrenOfSdrObject())
+        if (pObject->getChildrenOfSdrObject())
         {
-            for (size_t it = 0; it < pChildren->GetObjCount(); ++it)
-                if (SwFrameFormat* pTextBox = 
SwTextBoxHelper::getOtherTextBoxFormat(
-                        pFormat, RES_DRAWFRMFMT, pChildren->GetObj(it)))
-                    aTextBoxesToDelete.push_back(pTextBox);
+            auto pChildTextBoxes = SwTextBoxHelper::CollectTextBoxes(pObject, 
pFormat);
+            for (auto& rChildTextBox : pChildTextBoxes)
+                aTextBoxesToDelete.push_back(rChildTextBox);
         }
         else
             if (SwFrameFormat* pTextBox = 
SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
diff --git a/sw/source/core/unocore/unodraw.cxx 
b/sw/source/core/unocore/unodraw.cxx
index 5c5811ee3934..4d0b404e9a1c 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -965,10 +965,19 @@ SwXShape::~SwXShape()
 
 uno::Any SwXShape::queryInterface( const uno::Type& aType )
 {
-    uno::Any aRet = SwTextBoxHelper::queryInterface(GetFrameFormat(), aType);
-    if (aRet.hasValue())
-        return aRet;
+    uno::Any aRet;
+    SdrObject* pObj = nullptr;
+
+    if ((aType == cppu::UnoType<text::XText>::get())
+        || (aType == cppu::UnoType<text::XTextRange>::get())
+        || (aType == cppu::UnoType<text::XTextAppend>::get()))
+    {
+        pObj = SdrObject::getSdrObjectFromXShape(mxShape);
 
+        aRet = SwTextBoxHelper::queryInterface(GetFrameFormat(), aType, pObj);
+        if (aRet.hasValue())
+            return aRet;
+    }
     aRet = SwXShapeBaseClass::queryInterface(aType);
     // #i53320# - follow-up of #i31698#
     // interface drawing::XShape is overloaded. Thus, provide

Reply via email to