tdf#143574 tdf#144271 sw: textboxes in group shapes - part 2

Sync textboxes with group shapes, adding textboxes to
group shapes, copying textboxes with group shapes,
grouping/ungrouping group shapes with textboxes, removing
textboxes from group shapes.

This patch fixes a memory leak (tdf#144271) introduced
by commit 504d78acb866495fd954fcd6db22ea68f174a5ab
"tdf#143574 sw: textboxes in group shapes - part 1".

Note: AS_CHAR anchoring is far not the best for group
shapes and import/export is still missing.

Change-Id: I7dc3b8d36c4a04f792ae4742fe4a45af9227a17e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121449
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 3cd442e..978cf77 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -69,10 +69,10 @@

    /// Sync property of TextBox with the one of the shape.
    static void syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
                             const css::uno::Any& rValue);
                             const css::uno::Any& rValue, SdrObject* pObj = nullptr);
    /// Does the same, but works on properties which lack an sw-specific WID / MemberID.
    static void syncProperty(SwFrameFormat* pShape, std::u16string_view rPropertyName,
                             const css::uno::Any& rValue);
                             const css::uno::Any& rValue, SdrObject* pObj = nullptr);
    /// Get a property of the underlying TextFrame.
    static void getProperty(SwFrameFormat const* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
                            css::uno::Any& rValue);
@@ -83,7 +83,7 @@
    static css::text::TextContentAnchorType mapAnchorType(const RndStdIds& rAnchorID);

    /// Similar to syncProperty(), but used by the internal API (e.g. for UI purposes).
    static void syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& rSet);
    static void syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& rSet, SdrObject* pObj);

    /// Copy shape attributes to the text frame
    static void updateTextBoxMargin(SdrObject* pObj);
@@ -94,11 +94,11 @@

    /// Sets the anchor of the associated textframe of the given shape, and
    /// returns true on success.
    static bool changeAnchor(SwFrameFormat* pShape);
    static bool changeAnchor(SwFrameFormat* pShape, SdrObject* pObj);

    /// Does the positioning for the associated textframe of the shape, and
    /// returns true on success.
    static bool doTextBoxPositioning(SwFrameFormat* pShape);
    static bool doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pObj);

    /// Returns true if the anchor different for the  given shape, and the
    /// associated textframe of the given shape.
@@ -112,7 +112,7 @@

    // Returns true on success. Synchronize z-order of the text frame of the given textbox
    // by setting it one level higher than the z-order of the shape of the textbox.
    static bool DoTextBoxZOrderCorrection(SwFrameFormat* pShape);
    static bool DoTextBoxZOrderCorrection(SwFrameFormat* pShape, SdrObject* pObj);

    /**
     * If we have an associated TextFrame, then return that.
@@ -134,7 +134,7 @@
    static css::uno::Reference<css::text::XTextFrame>
    getUnoTextFrame(css::uno::Reference<css::drawing::XShape> const& xShape);
    /// Return the textbox rectangle of a draw shape (in twips).
    static tools::Rectangle getTextRectangle(SwFrameFormat* pShape, bool bAbsolute = true);
    static tools::Rectangle getTextRectangle(SdrObject* pShape, bool bAbsolute = true);

    /**
     * Is the frame format a text box?
diff --git a/sw/qa/uitest/writer_tests7/tdf143574.py b/sw/qa/uitest/writer_tests7/tdf143574.py
index 08e59b7..61265e2 100644
--- a/sw/qa/uitest/writer_tests7/tdf143574.py
+++ b/sw/qa/uitest/writer_tests7/tdf143574.py
@@ -33,7 +33,6 @@
            # At this point the Writer crashed here before the fix.
            self.xUITest.executeCommand(".uno:AddTextBox");

            #follow up commit will introduce:
            #self.assertEqual(True, document.DrawPage.getByIndex(0).getByIndex(2).TextBox)
            self.assertEqual(True, document.DrawPage.getByIndex(0).getByIndex(2).TextBox)

# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/doc/DocumentLayoutManager.cxx b/sw/source/core/doc/DocumentLayoutManager.cxx
index 1e071ef..4cee8ad 100644
--- a/sw/source/core/doc/DocumentLayoutManager.cxx
+++ b/sw/source/core/doc/DocumentLayoutManager.cxx
@@ -41,6 +41,7 @@
#include <frameformats.hxx>
#include <com/sun/star/embed/EmbedStates.hpp>
#include <svx/svdobj.hxx>
#include <svx/svdpage.hxx>
#include <osl/diagnose.h>

using namespace ::com::sun::star;
@@ -463,38 +464,64 @@
        pDest->MakeFrames();

    // If the draw format has a TextBox, then copy its fly format as well.
    if (SwFrameFormat* pSourceTextBox = SwTextBoxHelper::getOtherTextBoxFormat(&rSource, RES_DRAWFRMFMT))
    if (rSource.Which() == RES_DRAWFRMFMT && rSource.GetOtherTextBoxFormat())
    {
        SwFormatAnchor boxAnchor(rNewAnchor);
        if (RndStdIds::FLY_AS_CHAR == boxAnchor.GetAnchorId())
        auto pObj = rSource.FindRealSdrObject();
        auto pTextBoxNd = new SwTextBoxNode(pDest);
        pDest->SetOtherTextBoxFormat(pTextBoxNd);

        if (pObj)
        {
            // AS_CHAR *must not* be set on textbox fly-frame
            boxAnchor.SetType(RndStdIds::FLY_AT_CHAR);
            const bool bIsGroupObj = pObj->getChildrenOfSdrObject();
            for (size_t it = 0;
                 it < (bIsGroupObj ? pObj->getChildrenOfSdrObject()->GetObjCount() : 1); it++)
            {
                auto pChild = bIsGroupObj ? pObj->getChildrenOfSdrObject()->GetObj(it)
                                          : const_cast<SdrObject*>(pObj);
                if (auto pSourceTextBox
                    = SwTextBoxHelper::getOtherTextBoxFormat(&rSource, RES_DRAWFRMFMT, pChild))
                {
                    SwFormatAnchor boxAnchor(rNewAnchor);
                    if (RndStdIds::FLY_AS_CHAR == boxAnchor.GetAnchorId())
                    {
                        // AS_CHAR *must not* be set on textbox fly-frame
                        boxAnchor.SetType(RndStdIds::FLY_AT_CHAR);
                    }
                    // presumably these anchors are supported though not sure
                    assert(RndStdIds::FLY_AT_CHAR == boxAnchor.GetAnchorId()
                           || RndStdIds::FLY_AT_PARA == boxAnchor.GetAnchorId()
                           || boxAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE);

                    if (!bMakeFrames && rNewAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
                    {
                        // If the draw format is as-char, then it will be copied with bMakeFrames=false, but
                        // doing the same for the fly format would result in not making fly frames at all.
                        bMakeFrames = true;
                    }
                    SwFrameFormat* pDestTextBox
                        = CopyLayoutFormat(*pSourceTextBox, boxAnchor, bSetTextFlyAtt, bMakeFrames);

                    SwAttrSet aSet(pDest->GetAttrSet());
                    SwFormatContent aContent(
                        pDestTextBox->GetContent().GetContentIdx()->GetNode().GetStartNode());
                    aSet.Put(aContent);
                    pDest->SetFormatAttr(aSet);

                    // Link FLY and DRAW formats, so it becomes a text box
                    SdrObject* pNewObj = pDest->FindRealSdrObject();
                    if (bIsGroupObj && pDest && pDest->FindRealSdrObject()
                        && pDest->FindRealSdrObject()->getChildrenOfSdrObject()
                        && (pDest->FindRealSdrObject()->getChildrenOfSdrObject()->GetObjCount() > it)
                        && pDest->FindRealSdrObject()->getChildrenOfSdrObject()->GetObj(it))
                        pNewObj = pDest->FindRealSdrObject()->getChildrenOfSdrObject()->GetObj(it);
                    pTextBoxNd->AddTextBox(pNewObj, pDestTextBox);
                    pDestTextBox->SetOtherTextBoxFormat(pTextBoxNd);
                }

                if (!bIsGroupObj)
                    break;
            }
        }
        // presumably these anchors are supported though not sure
        assert(RndStdIds::FLY_AT_CHAR == boxAnchor.GetAnchorId() || RndStdIds::FLY_AT_PARA == boxAnchor.GetAnchorId()
        || boxAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE);

        if (!bMakeFrames && rNewAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
        {
            // If the draw format is as-char, then it will be copied with bMakeFrames=false, but
            // doing the same for the fly format would result in not making fly frames at all.
            bMakeFrames = true;
        }

        SwFrameFormat* pDestTextBox = CopyLayoutFormat(*pSourceTextBox,
                boxAnchor, bSetTextFlyAtt, bMakeFrames);
        SwAttrSet aSet(pDest->GetAttrSet());
        SwFormatContent aContent(pDestTextBox->GetContent().GetContentIdx()->GetNode().GetStartNode());
        aSet.Put(aContent);
        pDest->SetFormatAttr(aSet);

        // Link FLY and DRAW formats, so it becomes a text box
        auto pTextBox = new SwTextBoxNode(pDest);
        pTextBox->AddTextBox(pDest->FindRealSdrObject(), pDestTextBox);

        pDest->SetOtherTextBoxFormat(pTextBox);
        pDestTextBox->SetOtherTextBoxFormat(pTextBox);
    }

    if (pDest->GetName().isEmpty())
diff --git a/sw/source/core/doc/docdraw.cxx b/sw/source/core/doc/docdraw.cxx
index 609b174..0aff4b89 100644
--- a/sw/source/core/doc/docdraw.cxx
+++ b/sw/source/core/doc/docdraw.cxx
@@ -208,6 +208,8 @@
                static_cast<SwAnchoredDrawObject*>(pMyContact->GetAnchoredObj( pObj ));
            bGroupMembersNotPositioned = pAnchoredDrawObj->NotYetPositioned();
        }

        std::vector<std::pair<SwFrameFormat*, SdrObject*>> vSavedTextBoxes;
        // Destroy ContactObjects and formats.
        for( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
        {
@@ -221,6 +223,9 @@
            OSL_ENSURE( bGroupMembersNotPositioned == pAnchoredDrawObj->NotYetPositioned(),
                    "<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));

            pFormat = static_cast<SwDrawFrameFormat*>(pContact->GetFormat());
            // Deletes itself!
@@ -247,6 +252,16 @@
        pFormat->SetPositionLayoutDir(
            text::PositionLayoutDir::PositionInLayoutDirOfAnchor );

        // Add the saved textboxes to the new format.
        auto pTextBoxNode = new SwTextBoxNode(pFormat);
        for (auto& pTextBoxEntry : vSavedTextBoxes)
        {
            pTextBoxNode->AddTextBox(pTextBoxEntry.second, pTextBoxEntry.first);
            pTextBoxEntry.first->SetOtherTextBoxFormat(pTextBoxNode);
        }
        pFormat->SetOtherTextBoxFormat(pTextBoxNode);
        vSavedTextBoxes.clear();

        rDrawView.GroupMarked();
        OSL_ENSURE( rMrkList.GetMarkCount() == 1, "GroupMarked more or none groups." );

@@ -311,6 +326,11 @@
                if ( auto pObjGroup = dynamic_cast<SdrObjGroup*>(pObj) )
                {
                    SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));

                    SwTextBoxNode* pTextBoxNode = nullptr;
                    if (auto pGroupFormat = pContact->GetFormat())
                        pTextBoxNode = pGroupFormat->GetOtherTextBoxFormat();

                    SwFormatAnchor aAnch( pContact->GetFormat()->GetAnchor() );
                    SdrObjList *pLst = pObjGroup->GetSubList();

@@ -327,6 +347,16 @@
                        SwDrawFrameFormat *pFormat = MakeDrawFrameFormat( GetUniqueShapeName(),
                                                            GetDfltFrameFormat() );
                        pFormat->SetFormatAttr( aAnch );

                        if (pTextBoxNode)
                            if (auto pTextBoxFormat = pTextBoxNode->GetTextBox(pSubObj))
                            {
                                auto pNewTextBoxNode = new SwTextBoxNode(pFormat);
                                pNewTextBoxNode->AddTextBox(pSubObj, pTextBoxFormat);
                                pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
                                pTextBoxFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
                            }

                        // #i36010# - set layout direction of the position
                        pFormat->SetPositionLayoutDir(
                            text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
diff --git a/sw/source/core/doc/docfly.cxx b/sw/source/core/doc/docfly.cxx
index 6ff9bf9..d8fe293c 100644
--- a/sw/source/core/doc/docfly.cxx
+++ b/sw/source/core/doc/docfly.cxx
@@ -577,7 +577,7 @@

    getIDocumentState().SetModified();

    SwTextBoxHelper::syncFlyFrameAttr(rFlyFormat, rSet);
    //SwTextBoxHelper::syncFlyFrameAttr(rFlyFormat, rSet);

    return bRet;
}
@@ -924,7 +924,7 @@
                                                               RES_DRAWFRMFMT))
                    {
                        SwTextBoxHelper::syncFlyFrameAttr(*pContact->GetFormat(),
                                                          pContact->GetFormat()->GetAttrSet());
                                                          pContact->GetFormat()->GetAttrSet(), pObj);
                    }
                }
                break;
diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx
index 16ad4d8..d2ccfaf8 100644
--- a/sw/source/core/doc/docfmt.cxx
+++ b/sw/source/core/doc/docfmt.cxx
@@ -483,8 +483,11 @@
    auto pShapeFormat = dynamic_cast<SwFrameFormat*>(&rFormat);
    if (pShapeFormat && SwTextBoxHelper::isTextBox(pShapeFormat, RES_DRAWFRMFMT))
    {
        SwTextBoxHelper::syncFlyFrameAttr(*pShapeFormat, rSet);
        SwTextBoxHelper::changeAnchor(pShapeFormat);
        if (auto pObj = pShapeFormat->FindRealSdrObject())
        {
            SwTextBoxHelper::syncFlyFrameAttr(*pShapeFormat, rSet, pObj);
            SwTextBoxHelper::changeAnchor(pShapeFormat, pObj);
        }
    }

    getIDocumentState().SetModified();
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 3858da3..93b9564 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -61,9 +61,10 @@

void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCopyText)
{
    if (dynamic_cast<SdrObjGroup*>(pObject->getParentSdrObjectFromSdrObject()))
        // The GroupShape Textbox creation method call comes here.
        return;
    assert(pShape);
    assert(pObject);

    const bool bIsGroupObj = dynamic_cast<SdrObjGroup*>(pObject->getParentSdrObjectFromSdrObject());

    // If TextBox wasn't enabled previously
    if (pShape->GetOtherTextBoxFormat() && pShape->GetOtherTextBoxFormat()->GetTextBox(pObject))
@@ -74,9 +75,9 @@

    if (bCopyText)
    {
        if (auto pSdrShape = pShape->FindRealSdrObject())
        if (pObject)
        {
            uno::Reference<text::XText> xSrcCnt(pSdrShape->getWeakUnoShape(), uno::UNO_QUERY);
            uno::Reference<text::XText> xSrcCnt(pObject->getWeakUnoShape(), uno::UNO_QUERY);
            auto xCur = xSrcCnt->createTextCursor();
            xCur->gotoStart(false);
            xCur->gotoEnd(true);
@@ -94,8 +95,7 @@
                                                                uno::UNO_QUERY);
    try
    {
        SdrObject* pSourceSDRShape = pShape->FindRealSdrObject();
        uno::Reference<text::XTextContent> XSourceShape(pSourceSDRShape->getUnoShape(),
        uno::Reference<text::XTextContent> XSourceShape(pObject->getUnoShape(),
                                                        uno::UNO_QUERY_THROW);
        xTextContentAppend->insertTextContentWithProperties(
            xTextFrame, uno::Sequence<beans::PropertyValue>(), XSourceShape->getAnchor());
@@ -155,45 +155,47 @@
        pShape->SetFormatAttr(aSet);
    }

    DoTextBoxZOrderCorrection(pShape);
    DoTextBoxZOrderCorrection(pShape, pObject);

    // Also initialize the properties, which are not constant, but inherited from the shape's ones.
    uno::Reference<drawing::XShape> xShape(pShape->FindRealSdrObject()->getUnoShape(),
                                           uno::UNO_QUERY);
    syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::makeAny(xShape->getSize()));
    uno::Reference<drawing::XShape> xShape(pObject->getUnoShape(), uno::UNO_QUERY);
    syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::makeAny(xShape->getSize()), pObject);

    uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
    syncProperty(pShape, RES_FOLLOW_TEXT_FLOW, MID_FOLLOW_TEXT_FLOW,
                 xShapePropertySet->getPropertyValue(UNO_NAME_IS_FOLLOWING_TEXT_FLOW));
                 xShapePropertySet->getPropertyValue(UNO_NAME_IS_FOLLOWING_TEXT_FLOW), pObject);
    syncProperty(pShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
                 xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE));
                 xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE), pObject);
    syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT));
                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT), pObject);
    syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION));
                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION), pObject);
    syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT));
                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT), pObject);
    syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION));
                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION), pObject);
    syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION));
                 xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION), pObject);
    syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION));
                 xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION), pObject);
    syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
                 xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT));
                 xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT), pObject);
    syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0,
                 xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST));
                 xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST), pObject);
    text::WritingMode eMode;
    if (xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE) >>= eMode)
        syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)));
        syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)), pObject);

    if (bIsGroupObj)
        doTextBoxPositioning(pShape, pObject);

    // Check if the shape had text before and move it to the new textframe
    if (!bCopyText || sCopyableText.isEmpty())
        return;

    auto pSdrShape = pShape->FindRealSdrObject();
    if (pSdrShape)
    if (pObject)
    {
        auto pSourceText = dynamic_cast<SdrTextObj*>(pSdrShape);
        auto pSourceText = dynamic_cast<SdrTextObj*>(pObject);
        uno::Reference<text::XTextRange> xDestText(xRealTextFrame, uno::UNO_QUERY);

        xDestText->setString(sCopyableText);
@@ -415,12 +417,14 @@
    return aRet;
}

tools::Rectangle SwTextBoxHelper::getTextRectangle(SwFrameFormat* pShape, bool bAbsolute)
tools::Rectangle SwTextBoxHelper::getTextRectangle(SdrObject* pShape, bool bAbsolute)
{
    tools::Rectangle aRet;
    aRet.SetEmpty();
    auto pSdrShape = pShape->FindRealSdrObject();
    auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pSdrShape);

    assert(pShape);

    auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pShape);
    if (pCustomShape)
    {
        // Need to temporarily release the lock acquired in
@@ -435,17 +439,17 @@
        if (nLocks)
            xLockable->setActionLocks(nLocks);
    }
    else if (pSdrShape)
    else if (pShape)
    {
        // fallback - get *any* bound rect we can possibly get hold of
        aRet = pSdrShape->GetCurrentBoundRect();
        aRet = pShape->GetCurrentBoundRect();
    }

    if (!bAbsolute && pSdrShape)
    if (!bAbsolute && pShape)
    {
        // Relative, so count the logic (reference) rectangle, see the EnhancedCustomShape2d ctor.
        Point aPoint(pSdrShape->GetSnapRect().Center());
        Size aSize(pSdrShape->GetLogicRect().GetSize());
        Point aPoint(pShape->GetSnapRect().Center());
        Size aSize(pShape->GetLogicRect().GetSize());
        aPoint.AdjustX(-(aSize.Width() / 2));
        aPoint.AdjustY(-(aSize.Height() / 2));
        tools::Rectangle aLogicRect(aPoint, aSize);
@@ -456,12 +460,12 @@
}

void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rPropertyName,
                                   const css::uno::Any& rValue)
                                   const css::uno::Any& rValue, SdrObject* pObj)
{
    // Textframes does not have valid horizontal adjust property, so map it to paragraph adjust property
    if (rPropertyName == UNO_NAME_TEXT_HORZADJUST)
    {
        SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
        SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
        if (!pFormat)
            return;

@@ -506,7 +510,7 @@
        // CustomShapeGeometry changes the textbox position offset and size, so adjust both.
        syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any());

        SdrObject* pObject = pShape->FindRealSdrObject();
        SdrObject* pObject = pObj ? pObj : pShape->FindRealSdrObject();
        if (pObject)
        {
            tools::Rectangle aRectangle(pObject->GetSnapRect());
@@ -518,7 +522,7 @@
                uno::makeAny(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Top()))));
        }

        SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
        SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
        if (!pFormat)
            return;

@@ -555,30 +559,30 @@

            if (nDirection)
            {
                syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(nDirection));
                syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(nDirection), pObj);
            }
        }
    }
    else if (rPropertyName == UNO_NAME_TEXT_VERT_ADJUST)
        syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0, rValue);
        syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0, rValue, pObj);
    else if (rPropertyName == UNO_NAME_TEXT_AUTOGROWHEIGHT)
        syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, rValue);
        syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, rValue, pObj);
    else if (rPropertyName == UNO_NAME_TEXT_LEFTDIST)
        syncProperty(pShape, RES_BOX, LEFT_BORDER_DISTANCE, rValue);
        syncProperty(pShape, RES_BOX, LEFT_BORDER_DISTANCE, rValue, pObj);
    else if (rPropertyName == UNO_NAME_TEXT_RIGHTDIST)
        syncProperty(pShape, RES_BOX, RIGHT_BORDER_DISTANCE, rValue);
        syncProperty(pShape, RES_BOX, RIGHT_BORDER_DISTANCE, rValue, pObj);
    else if (rPropertyName == UNO_NAME_TEXT_UPPERDIST)
        syncProperty(pShape, RES_BOX, TOP_BORDER_DISTANCE, rValue);
        syncProperty(pShape, RES_BOX, TOP_BORDER_DISTANCE, rValue, pObj);
    else if (rPropertyName == UNO_NAME_TEXT_LOWERDIST)
        syncProperty(pShape, RES_BOX, BOTTOM_BORDER_DISTANCE, rValue);
        syncProperty(pShape, RES_BOX, BOTTOM_BORDER_DISTANCE, rValue, pObj);
    else if (rPropertyName == UNO_NAME_TEXT_WRITINGMODE)
    {
        text::WritingMode eMode;
        sal_Int16 eMode2;
        if (rValue >>= eMode)
            syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)));
            syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)), pObj);
        else if (rValue >>= eMode2)
            syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(eMode2));
            syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(eMode2), pObj);
    }
    else
        SAL_INFO("sw.core", "SwTextBoxHelper::syncProperty: unhandled property: "
@@ -635,7 +639,7 @@
}

void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
                                   const css::uno::Any& rValue)
                                   const css::uno::Any& rValue, SdrObject* pObj)
{
    // No shape yet? Then nothing to do, initial properties are set by create().
    if (!pShape)
@@ -644,7 +648,7 @@
    uno::Any aValue(rValue);
    nMemberID &= ~CONVERT_TWIPS;

    SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
    SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
    if (!pFormat)
        return;

@@ -745,8 +749,8 @@
                case MID_ANCHOR_ANCHORTYPE:
                {
                    setWrapThrough(pShape);
                    changeAnchor(pShape);
                    doTextBoxPositioning(pShape);
                    changeAnchor(pShape, pObj);
                    doTextBoxPositioning(pShape, pObj);

                    return;
                }
@@ -844,7 +848,9 @@
    // Position/size should be the text position/size, not the shape one as-is.
    if (bAdjustX || bAdjustY || bAdjustSize)
    {
        tools::Rectangle aRect = getTextRectangle(pShape, /*bAbsolute=*/false);
        changeAnchor(pShape, pObj);
        tools::Rectangle aRect
            = getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), /*bAbsolute=*/false);
        if (!aRect.IsEmpty())
        {
            if (bAdjustX || bAdjustY)
@@ -929,9 +935,10 @@
    return aAnchorType;
}

void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& rSet)
void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& rSet,
                                       SdrObject* pObj)
{
    SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT);
    SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT, pObj);
    if (!pFormat)
        return;

@@ -950,12 +957,14 @@
                // The new position can be with anchor changing so sync it!
                const text::TextContentAnchorType aNewAnchorType
                    = mapAnchorType(rShape.GetAnchor().GetAnchorId());
                syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType));
                syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType),
                             pObj);
                if (bInlineAnchored)
                    return;
                SwFormatVertOrient aOrient(pItem->StaticWhichCast(RES_VERT_ORIENT));

                tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
                tools::Rectangle aRect = getTextRectangle(pObj ? pObj : rShape.FindRealSdrObject(),
                                                          /*bAbsolute=*/false);
                if (!aRect.IsEmpty())
                    aOrient.SetPos(aOrient.GetPos() + aRect.Top());

@@ -978,12 +987,14 @@
                // The new position can be with anchor changing so sync it!
                const text::TextContentAnchorType aNewAnchorType
                    = mapAnchorType(rShape.GetAnchor().GetAnchorId());
                syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType));
                syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType),
                             pObj);
                if (bInlineAnchored)
                    return;
                SwFormatHoriOrient aOrient(pItem->StaticWhichCast(RES_HORI_ORIENT));

                tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
                tools::Rectangle aRect = getTextRectangle(pObj ? pObj : rShape.FindRealSdrObject(),
                                                          /*bAbsolute=*/false);
                if (!aRect.IsEmpty())
                    aOrient.SetPos(aOrient.GetPos() + aRect.Left());

@@ -1003,13 +1014,18 @@
                SwFormatHoriOrient aHoriOrient(rShape.GetHoriOrient());
                SwFormatFrameSize aSize(pFormat->GetFrameSize());

                tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
                tools::Rectangle aRect = getTextRectangle(pObj ? pObj : rShape.FindRealSdrObject(),
                                                          /*bAbsolute=*/false);
                if (!aRect.IsEmpty())
                {
                    if (!bInlineAnchored)
                    {
                        aVertOrient.SetPos(aVertOrient.GetPos() + aRect.Top());
                        aHoriOrient.SetPos(aHoriOrient.GetPos() + aRect.Left());
                        aVertOrient.SetPos(
                            (pObj ? pObj->GetRelativePos().getX() : aVertOrient.GetPos())
                            + aRect.Top());
                        aHoriOrient.SetPos(
                            (pObj ? pObj->GetRelativePos().getY() : aHoriOrient.GetPos())
                            + aRect.Left());

                        aTextBoxSet.Put(aVertOrient);
                        aTextBoxSet.Put(aHoriOrient);
@@ -1029,7 +1045,7 @@
                    const text::TextContentAnchorType aNewAnchorType
                        = mapAnchorType(rShape.GetAnchor().GetAnchorId());
                    syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
                                 uno::Any(aNewAnchorType));
                                 uno::Any(aNewAnchorType), pObj);
                }
                else
                {
@@ -1048,9 +1064,10 @@
    } while (pItem && (0 != pItem->Which()));

    if (aTextBoxSet.Count())
        pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
        pFormat->SetFormatAttr(aTextBoxSet);
    //pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);

    DoTextBoxZOrderCorrection(&rShape);
    DoTextBoxZOrderCorrection(&rShape, pObj);
}

void SwTextBoxHelper::updateTextBoxMargin(SdrObject* pObj)
@@ -1092,8 +1109,8 @@
    syncProperty(pParentFormat, RES_FRM_SIZE, MID_FRMSIZE_WIDTH_TYPE,
                 uno::Any(bIsAutoWrap ? text::SizeType::FIX : text::SizeType::MIN));

    changeAnchor(pParentFormat);
    DoTextBoxZOrderCorrection(pParentFormat);
    changeAnchor(pParentFormat, pObj);
    DoTextBoxZOrderCorrection(pParentFormat, pObj);
}

bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape)
@@ -1129,147 +1146,147 @@
    return false;
}

bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape)
bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape, SdrObject* pObj)
{
    if (isTextBoxShapeHasValidTextFrame(pShape))
    if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
    {
        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
        const SwFormatAnchor& rOldAnch = pFormat->GetAnchor();
        const SwFormatAnchor& rNewAnch = pShape->GetAnchor();

        const auto pOldCnt = rOldAnch.GetContentAnchor();
        const auto pNewCnt = rNewAnch.GetContentAnchor();

        const uno::Any aShapeHorRelOrient
            = uno::makeAny(pShape->GetHoriOrient().GetRelationOrient());

        if (isAnchorTypeDifferent(pShape) || (pObj && pObj != pShape->FindRealSdrObject()))
        {
            const SwFormatAnchor& rOldAnch = pFormat->GetAnchor();
            const SwFormatAnchor& rNewAnch = pShape->GetAnchor();

            const auto pOldCnt = rOldAnch.GetContentAnchor();
            const auto pNewCnt = rNewAnch.GetContentAnchor();

            const uno::Any aShapeHorRelOrient
                = uno::makeAny(pShape->GetHoriOrient().GetRelationOrient());

            if (isAnchorTypeDifferent(pShape))
            try
            {
                try
                ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
                uno::Reference<beans::XPropertySet> const xPropertySet(
                    SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
                if (pOldCnt && rNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE
                    && rNewAnch.GetPageNum())
                {
                    ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
                    uno::Reference<beans::XPropertySet> const xPropertySet(
                        SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
                        uno::UNO_QUERY);
                    if (pOldCnt && rNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE
                        && rNewAnch.GetPageNum())
                    uno::Any aValue(text::TextContentAnchorType_AT_PAGE);
                    xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                   aShapeHorRelOrient);
                    xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                    xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
                                                   uno::Any(rNewAnch.GetPageNum()));
                }
                else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE && pNewCnt)
                {
                    if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
                    {
                        uno::Any aValue(text::TextContentAnchorType_AT_PAGE);
                        xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                       aShapeHorRelOrient);
                        uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
                                                       uno::Any(rNewAnch.GetPageNum()));
                    }
                    else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE && pNewCnt)
                    {
                        if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
                        {
                            uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
                            xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                            xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                           uno::Any(text::RelOrientation::CHAR));
                            xPropertySet->setPropertyValue(
                                UNO_NAME_VERT_ORIENT_RELATION,
                                uno::Any(text::RelOrientation::PRINT_AREA));
                            SwFormatAnchor aPos(pFormat->GetAnchor());
                            aPos.SetAnchor(pNewCnt);
                            pFormat->SetFormatAttr(aPos);
                        }
                        else
                        {
                            uno::Any aValue(mapAnchorType(rNewAnch.GetAnchorId()));
                            xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                           aShapeHorRelOrient);
                            xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                            pFormat->SetFormatAttr(rNewAnch);
                        }
                        xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                       uno::Any(text::RelOrientation::CHAR));
                        xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION,
                                                       uno::Any(text::RelOrientation::PRINT_AREA));
                        SwFormatAnchor aPos(pFormat->GetAnchor());
                        aPos.SetAnchor(pNewCnt);
                        pFormat->SetFormatAttr(aPos);
                    }
                    else
                    {
                        if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
                        {
                            uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
                            xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                            xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                           uno::Any(text::RelOrientation::CHAR));
                            xPropertySet->setPropertyValue(
                                UNO_NAME_VERT_ORIENT_RELATION,
                                uno::Any(text::RelOrientation::PRINT_AREA));
                            SwFormatAnchor aPos(pFormat->GetAnchor());
                            aPos.SetAnchor(pNewCnt);
                            pFormat->SetFormatAttr(aPos);
                        }
                        else
                        {
                            xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                           aShapeHorRelOrient);
                            pFormat->SetFormatAttr(pShape->GetAnchor());
                        }
                        uno::Any aValue(mapAnchorType(rNewAnch.GetAnchorId()));
                        xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                       aShapeHorRelOrient);
                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                        pFormat->SetFormatAttr(rNewAnch);
                    }
                }
                catch (uno::Exception& e)
                else
                {
                    SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << e.Message);
                    if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
                    {
                        uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
                        xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
                        xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                       uno::Any(text::RelOrientation::CHAR));
                        xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION,
                                                       uno::Any(text::RelOrientation::PRINT_AREA));
                        SwFormatAnchor aPos(pFormat->GetAnchor());
                        aPos.SetAnchor(pNewCnt);
                        pFormat->SetFormatAttr(aPos);
                    }
                    else
                    {
                        xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
                                                       aShapeHorRelOrient);
                        pFormat->SetFormatAttr(pShape->GetAnchor());
                    }
                }
            }

            return doTextBoxPositioning(pShape) && DoTextBoxZOrderCorrection(pShape);
            catch (uno::Exception& e)
            {
                SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << e.Message);
            }
        }

        return doTextBoxPositioning(pShape, pObj) && DoTextBoxZOrderCorrection(pShape, pObj);
    }

    return false;
}

bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape)
bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pObj)
{
    if (isTextBoxShapeHasValidTextFrame(pShape))
    const bool bIsGroupObj = (pObj != pShape->FindRealSdrObject()) && pObj;
    if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
    {
        if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
        ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
        if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
        {
            ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
            if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
            tools::Rectangle aRect(
                getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), false));

            auto nLeftSpace = pShape->GetLRSpace().GetLeft();

            SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient());
            aNewHOri.SetPos(aRect.Left() + nLeftSpace);

            SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
            aNewVOri.SetPos(aRect.Top() + pShape->GetVertOrient().GetPos());

            // tdf#140598: Do not apply wrong rectangle position.
            if (aRect.TopLeft() != Point(0, 0))
            {
                tools::Rectangle aRect(getTextRectangle(pShape, false));

                auto nLeftSpace = pShape->GetLRSpace().GetLeft();

                SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient());
                aNewHOri.SetPos(aRect.Left() + nLeftSpace);

                SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
                aNewVOri.SetPos(aRect.Top() + pShape->GetVertOrient().GetPos());

                // tdf#140598: Do not apply wrong rectangle position.
                if (aRect.TopLeft() != Point(0, 0))
                {
                    pFormat->SetFormatAttr(aNewHOri);
                    pFormat->SetFormatAttr(aNewVOri);
                }
                else
                    SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!");
                pFormat->SetFormatAttr(aNewHOri);
                pFormat->SetFormatAttr(aNewVOri);
            }
            else
            {
                tools::Rectangle aRect(getTextRectangle(pShape, false));

                // tdf#140598: Do not apply wrong rectangle position.
                if (aRect.TopLeft() != Point(0, 0))
                {
                    SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
                    aNewHOri.SetPos(aNewHOri.GetPos() + aRect.Left());
                    SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
                    aNewVOri.SetPos(aNewVOri.GetPos() + aRect.Top());

                    pFormat->SetFormatAttr(aNewHOri);
                    pFormat->SetFormatAttr(aNewVOri);
                }
                else
                    SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!");
            }
            return true;
                SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!");
        }
        else
        {
            tools::Rectangle aRect(
                getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), false));

            // tdf#140598: Do not apply wrong rectangle position.
            if (aRect.TopLeft() != Point(0, 0) || bIsGroupObj)
            {
                SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
                aNewHOri.SetPos(
                    (bIsGroupObj && pObj ? pObj->GetRelativePos().getX() : aNewHOri.GetPos())
                    + aRect.Left());
                SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
                aNewVOri.SetPos(
                    (bIsGroupObj && pObj ? pObj->GetRelativePos().getY() : aNewVOri.GetPos())
                    + aRect.Top());

                pFormat->SetFormatAttr(aNewHOri);
                pFormat->SetFormatAttr(aNewVOri);
            }
            else
                SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!");
        }
        return true;
    }

    return false;
}

@@ -1307,52 +1324,59 @@
    return false;
}

bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape)
bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape, SdrObject* pObj)
{
    if (isTextBoxShapeHasValidTextFrame(pShape))
    // TODO: do this with group shape textboxes.
    SdrObject* pShpObj = nullptr;
    //if (pObj)
    //    pShpObj = pObj;
    //else
    pShpObj = pShape->FindRealSdrObject();

    if (pShpObj)
    {
        if (SdrObject* pShpObj = pShape->FindRealSdrObject())
        if (SdrObject* pFrmObj
            = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj)->FindRealSdrObject())
        {
            if (SdrObject* pFrmObj
                = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT)->FindRealSdrObject())
            // Get the draw model from the doc
            SwDrawModel* pDrawModel
                = pShape->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
            if (pDrawModel)
            {
                // Get the draw model from the doc
                SwDrawModel* pDrawModel
                    = pShape->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
                if (pDrawModel)
                {
                    // Not really sure this will work all page, but it seems it will.
                    auto pPage = pDrawModel->GetPage(0);
                    // Recalc all Zorders
                    pPage->RecalcObjOrdNums();
                    // If the shape is behind the frame, is good, but if there are some objects
                    // between of them that is wrong so put the frame exactly one level higher
                    // than the shape.
                    if (pFrmObj->GetOrdNum() > pShpObj->GetOrdNum())
                        pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pShpObj->GetOrdNum() + 1);
                    else
                        // Else, if the frame is behind the shape, bring to the front of it.
                        while (pFrmObj->GetOrdNum() <= pShpObj->GetOrdNum())
                        {
                            pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pFrmObj->GetOrdNum() + 1);
                            // If there is any problem with the indexes, do not run over the infinity
                            if (pPage->GetObjCount() == pFrmObj->GetOrdNum())
                                break;
                        }
                    pPage->RecalcObjOrdNums();
                    return true; // Success
                }
                SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
                                    "No Valid Draw model for SdrObject for the shape!");
                // Not really sure this will work all page, but it seems it will.
                auto pPage = pDrawModel->GetPage(0);
                // Recalc all Zorders
                pPage->RecalcObjOrdNums();
                // Here is a counter avoiding running to in infinity:
                sal_uInt16 nIterator = 0;
                // If the shape is behind the frame, is good, but if there are some objects
                // between of them that is wrong so put the frame exactly one level higher
                // than the shape.
                if (pFrmObj->GetOrdNum() > pShpObj->GetOrdNum())
                    pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pShpObj->GetOrdNum() + 1);
                else
                    // Else, if the frame is behind the shape, bring to the front of it.
                    while (pFrmObj->GetOrdNum() <= pShpObj->GetOrdNum())
                    {
                        pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pFrmObj->GetOrdNum() + 1);
                        // If there is any problem with the indexes, do not run over the infinity
                        if (pPage->GetObjCount() == pFrmObj->GetOrdNum())
                            break;
                        ++nIterator;
                        if (nIterator > 300)
                            break; // Do not run to infinity
                    }
                pPage->RecalcObjOrdNums();
                return true; // Success
            }
            SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
                                "No Valid SdrObject for the frame!");
                                "No Valid Draw model for SdrObject for the shape!");
        }
        SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
                            "No Valid SdrObject for the shape!");
                            "No Valid SdrObject for the frame!");
    }
    SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
                        "No Valid TextFrame!");
                        "No Valid SdrObject for the shape!");

    return false;
}
@@ -1369,14 +1393,10 @@

SwTextBoxNode::~SwTextBoxNode()
{
    // This only happens if the shape or the doc is in dtor.
    for (auto& rTextBoxEntry : m_pTextBoxes)
    {
        rTextBoxEntry.m_pDrawObject = nullptr;
        m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
            rTextBoxEntry.m_pTextBoxFormat);
    }
    m_pOwnerShapeFormat->SetOtherTextBoxFormat(nullptr);
    m_pTextBoxes.clear();

    if (m_pOwnerShapeFormat && m_pOwnerShapeFormat->GetOtherTextBoxFormat())
        m_pOwnerShapeFormat->SetOtherTextBoxFormat(nullptr);
}

void SwTextBoxNode::AddTextBox(SdrObject* pDrawObject, SwFrameFormat* pNewTextBox)
@@ -1403,21 +1423,19 @@
    assert(pDrawObject);
    if (m_pTextBoxes.size())
    {
        for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
        for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end();)
        {
            if (it->m_pDrawObject == pDrawObject)
            {
                m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
                    it->m_pTextBoxFormat);
                m_pTextBoxes.erase(it);
                it = m_pTextBoxes.erase(it);
                break;
            }
            else
                ++it;
        }
    }
    if (!m_pTextBoxes.size())
    {
        m_pOwnerShapeFormat->SetOtherTextBoxFormat(nullptr);
    }
}

SwFrameFormat* SwTextBoxNode::GetTextBox(const SdrObject* pDrawObject) const
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 383be2c..7cd60ce 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1091,7 +1091,7 @@
        SfxItemSet aResizeSet(pFormat->GetDoc()->GetAttrPool(), svl::Items<RES_FRM_SIZE, RES_FRM_SIZE>);
        SwFormatFrameSize aSize;
        aResizeSet.Put(aSize);
        SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet);
        SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet, pFormat->FindRealSdrObject());
    }
}

@@ -1249,6 +1249,12 @@
                    }
                    // 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));
                    }

                }
                SwTwips nXPosDiff(0);
                SwTwips nYPosDiff(0);
@@ -1338,7 +1344,7 @@
            // tdf#135198: keep text box together with its shape
            SwRect aObjRect(rObj.GetSnapRect());
            const SwPageFrame* rPageFrame = pAnchoredDrawObj->GetPageFrame();
            if (rPageFrame && rPageFrame->isFrameAreaPositionValid())
            if (rPageFrame && rPageFrame->isFrameAreaPositionValid() && !rObj.getChildrenOfSdrObject())
            {
                SwDoc* const pDoc = GetFormat()->GetDoc();

@@ -1349,14 +1355,29 @@
                const bool bEnableSetModified = pDoc->getIDocumentState().IsEnableSetModified();
                pDoc->getIDocumentState().SetEnableSetModified(false);

                SfxItemSet aSyncSet(pDoc->GetAttrPool(),
                                    svl::Items<RES_VERT_ORIENT, RES_ANCHOR>);
                SfxItemSet aSyncSet(
                    pDoc->GetAttrPool(),
                    svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT, RES_ANCHOR, RES_ANCHOR>);
                aSyncSet.Put(GetFormat()->GetHoriOrient());
                aSyncSet.Put(SwFormatVertOrient(aObjRect.Top() - rPageFrame->getFrameArea().Top(),
                                                text::VertOrientation::NONE,
                                                text::RelOrientation::PAGE_FRAME));
                aSyncSet.Put(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, pAnchoredDrawObj->GetPageFrame()->GetPhyPageNum()));

                SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet);
                auto pSdrObj = const_cast<SdrObject*>(&rObj);
                if (pSdrObj != GetFormat()->FindRealSdrObject())
                {
                    SfxItemSet aSet(
                        pDoc->GetAttrPool(),
                        svl::Items<RES_FRM_SIZE, RES_FRM_SIZE>);

                    aSet.Put(aSyncSet);
                    aSet.Put(pSdrObj->GetMergedItem(RES_FRM_SIZE));
                    SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSet, pSdrObj);
                    SwTextBoxHelper::changeAnchor(GetFormat(), pSdrObj);
                }
                else
                    SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet, GetFormat()->FindRealSdrObject());

                pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
            }
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index fb0e1f9..33d6a83 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -967,8 +967,16 @@
        SdrObject *pObject = rMarkList.GetMark(i)->GetMarkedSdrObj();
        SwContact* pContact = GetUserCall(pObject);
        SwFrameFormat* pFormat = pContact->GetFormat();
        if (SwFrameFormat* pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
            aTextBoxesToDelete.push_back(pTextBox);
        if (auto pChildren = 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);
        }
        else
            if (SwFrameFormat* pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
                aTextBoxesToDelete.push_back(pTextBox);
    }

    if ( pDoc->DeleteSelection( *this ) )
diff --git a/sw/source/core/frmedt/fecopy.cxx b/sw/source/core/frmedt/fecopy.cxx
index 1394c7b..6e3792e 100644
--- a/sw/source/core/frmedt/fecopy.cxx
+++ b/sw/source/core/frmedt/fecopy.cxx
@@ -400,9 +400,9 @@
                        if (SwDrawFrameFormat *pDrawFormat = dynamic_cast<SwDrawFrameFormat*>(pFormat))
                            pDrawFormat->PosAttrSet();
                    }
                    if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
                    if (SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT, pObj))
                    {
                        SwTextBoxHelper::syncFlyFrameAttr(*pFormat, pFormat->GetAttrSet());
                        SwTextBoxHelper::syncFlyFrameAttr(*pFormat, pFormat->GetAttrSet(), pObj);
                    }

                    if( bSelectInsert )
diff --git a/sw/source/core/frmedt/fefly1.cxx b/sw/source/core/frmedt/fefly1.cxx
index c8fdf46..a453e99 100644
--- a/sw/source/core/frmedt/fefly1.cxx
+++ b/sw/source/core/frmedt/fefly1.cxx
@@ -446,7 +446,7 @@
    bool bTextBox = false;
    if (rFormat.Which() == RES_DRAWFRMFMT)
    {
        bTextBox = SwTextBoxHelper::isTextBox(&rFormat, RES_DRAWFRMFMT);
        bTextBox = SwTextBoxHelper::isTextBox(&rFormat, RES_DRAWFRMFMT, pObj);
    }

    SwFlyFrame* pFly = nullptr;
@@ -471,8 +471,9 @@
    }
    else if (bTextBox)
    {
        auto pFlyFormat = dynamic_cast<const SwFlyFrameFormat*>(
            SwTextBoxHelper::getOtherTextBoxFormat(&rFormat, RES_DRAWFRMFMT));
        auto pFlyFormat
            = dynamic_cast<const SwFlyFrameFormat*>(SwTextBoxHelper::getOtherTextBoxFormat(
                &rFormat, RES_DRAWFRMFMT, pObj ? pObj : rFormat.FindRealSdrObject()));
        if (pFlyFormat)
        {
            pFly = pFlyFormat->GetFrame();
@@ -612,9 +613,20 @@
                                new SwHandleAnchorNodeChg( *pFlyFrameFormat, aAnch ));
                        }
                        rFormat.GetDoc()->SetAttr( aAnch, rFormat );
                        if (SwTextBoxHelper::getOtherTextBoxFormat(&rFormat, RES_DRAWFRMFMT))
                        if (SwTextBoxHelper::getOtherTextBoxFormat(&rFormat, RES_DRAWFRMFMT,
                            pObj ? pObj : rFormat.FindRealSdrObject()))
                        {
                            SwTextBoxHelper::syncFlyFrameAttr(rFormat, rFormat.GetAttrSet());
                            if (pObj->getChildrenOfSdrObject())
                            {
                                for (size_t i = 0;
                                     i < pObj->getChildrenOfSdrObject()->GetObjCount(); ++i)
                                    SwTextBoxHelper::changeAnchor(
                                        &rFormat, pObj->getChildrenOfSdrObject()->GetObj(i));
                            }
                            else
                                SwTextBoxHelper::syncFlyFrameAttr(
                                    rFormat, rFormat.GetAttrSet(),
                                    pObj ? pObj : rFormat.FindRealSdrObject());
                        }
                    }
                    // #i28701# - no call of method
diff --git a/sw/source/core/frmedt/feshview.cxx b/sw/source/core/frmedt/feshview.cxx
index 2041bc4..c55324d 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -1102,7 +1102,7 @@
                        pPage->SetObjectOrdNum(pObj->GetOrdNum(), pObj->GetOrdNum() + nShift);
                    }
                // The shape is on the right level, correct the layer of the frame
                SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat);
                SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
            }

    GetDoc()->getIDocumentState().SetModified();
@@ -1152,7 +1152,7 @@
                        }
                    }
                // And set correct layer for the selected textbox.
                SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat);
                SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj);
            }

    GetDoc()->getIDocumentState().SetModified();
@@ -1220,7 +1220,7 @@
                pFormat->SetFormatAttr( aOpa );
                // If pObj has textframe, put its textframe to the right level
                if (auto pTextBx = FindFrameFormat(pObj))
                    SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx);
                    SwTextBoxHelper::DoTextBoxZOrderCorrection(pTextBx, pObj);
            }
        }
    }
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index adcc388..76c9611 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -90,6 +90,7 @@
#include <hints.hxx>
#include <frameformats.hxx>
#include <unoprnms.hxx>
#include <svx/svdpage.hxx>

#include <ndtxt.hxx>

@@ -2551,16 +2552,18 @@
        auto pObj = FindRealSdrObject();
        if (Which() == RES_FLYFRMFMT && pObj)
        {
            // This is a fly-frame-format just del this
            // This is a fly-frame-format just delete this
            // textbox entry from the draw-frame-format.
            m_pOtherTextBoxFormat->DelTextBox(pObj);

            // delete format after deleting the last textbox
            if (!m_pOtherTextBoxFormat->GetTextBoxCount())
                delete m_pOtherTextBoxFormat;
        }

        m_pOtherTextBoxFormat = nullptr;
        if (Which() == RES_DRAWFRMFMT)
        {
            // This format is the owner shape, so its time
            // to del the textbox node.
            delete m_pOtherTextBoxFormat;
            m_pOtherTextBoxFormat = nullptr;
        }
    }
}

diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 33b53994..9f3bf54 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -535,7 +535,7 @@
    {
        // get the text area of the shape
        const tools::Rectangle aTextRectangle
            = SwTextBoxHelper::getTextRectangle(pShapeFormat, false);
            = SwTextBoxHelper::getTextRectangle(pShapeFormat->FindRealSdrObject(), false);
        // get the original textframe position
        SwFormatHoriOrient aHOri = pShapeFormat->GetHoriOrient();
        SwFormatVertOrient aVOri = pShapeFormat->GetVertOrient();
diff --git a/sw/source/core/text/porfly.cxx b/sw/source/core/text/porfly.cxx
index 260a186..de72a0e 100644
--- a/sw/source/core/text/porfly.cxx
+++ b/sw/source/core/text/porfly.cxx
@@ -375,8 +375,7 @@
            // of the textbox accordingly.
            // Both rectangles are absolute, SwFormatHori/VertOrient's position
            // is relative to the print area of the anchor text frame.
            tools::Rectangle aTextRectangle = SwTextBoxHelper::getTextRectangle(pShape);
            tools::Long nXoffs  = SwTextBoxHelper::getTextRectangle(pShape, false).Left();
            tools::Rectangle aTextRectangle = SwTextBoxHelper::getTextRectangle(pSdrObj);

            const auto aPos(pShape->GetAnchor().GetContentAnchor());
            SwFormatVertOrient aVert(pTextBox->GetVertOrient());
@@ -385,7 +384,13 @@
            // tdf#138598 Replace vertical alignment of As_char textboxes in footer
            // tdf#140158 Remove horizontal positioning of As_char textboxes, because
            // the anchor moving does the same for it.
            if (!aPos->nNode.GetNode().FindFooterStartNode())
            const bool bIsInHeaderFooter = aPos->nNode.GetNode().FindFooterStartNode();
            // TODO: Find solution for Group Shapes in Header/Footer.
            tools::Long nXoffs
                = SwTextBoxHelper::getTextRectangle(
                      bIsInHeaderFooter ? pShape->FindRealSdrObject() : pSdrObj, false)
                      .Left();
            if (!bIsInHeaderFooter)
            {
                aVert.SetVertOrient(css::text::VertOrientation::NONE);
                aVert.SetRelationOrient(css::text::RelOrientation::FRAME);
@@ -396,7 +401,7 @@
            else
            {
                aVert.SetVertOrient(css::text::VertOrientation::NONE);
                aVert.SetPos(SwTextBoxHelper::getTextRectangle(pShape, false).Top());
                aVert.SetPos(SwTextBoxHelper::getTextRectangle(pShape->FindRealSdrObject(), false).Top());
            }

            SwFormatAnchor aNewTxBxAnchor(pTextBox->GetAnchor());
diff --git a/sw/source/core/undo/undraw.cxx b/sw/source/core/undo/undraw.cxx
index fc7efcd..8fd748d 100644
--- a/sw/source/core/undo/undraw.cxx
+++ b/sw/source/core/undo/undraw.cxx
@@ -41,6 +41,7 @@
#include <dcontact.hxx>
#include <viewsh.hxx>
#include <frameformats.hxx>
#include <textboxhelper.hxx>

struct SwUndoGroupObjImpl
{
@@ -196,6 +197,22 @@
    auto pObj = m_pObjArray[0].pObj;
    pObj->SetUserCall(nullptr);

    // This will store the textboxes what were owned by this group
    std::vector<std::pair<SdrObject*, SwFrameFormat*>> vTextBoxes;
    if (auto pOldTextBoxNode = pFormat->GetOtherTextBoxFormat())
    {
        if (auto pChildren = pObj->getChildrenOfSdrObject())
        {
            for (size_t idx = 0; idx < pChildren->GetObjCount(); idx++)
            {
                auto pChild = pChildren->GetObj(idx);

                if (auto pTextBox = pOldTextBoxNode->GetTextBox(pChild))
                    vTextBoxes.push_back(std::pair(pChild, pTextBox));
            }
        }
    }

    ::lcl_SaveAnchor( pFormat, m_pObjArray[0].nNodeIdx );

    pFormat->RemoveAllUnos();
@@ -219,6 +236,18 @@
        // #i45718# - follow-up of #i35635# move object to visible layer
        pContact->MoveObjToVisibleLayer( pObj );

        for (auto& rElem : vTextBoxes)
        {
            if (rElem.first == pObj)
            {
                auto pNewTextBoxNode = new SwTextBoxNode(rSave.pFormat);
                rSave.pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
                pNewTextBoxNode->AddTextBox(rElem.first, rElem.second);
                rElem.second->SetOtherTextBoxFormat(pNewTextBoxNode);
                break;
            }
        }

        SwDrawFrameFormat* pDrawFrameFormat = rSave.pFormat;

        // #i45952# - notify that position attributes are already set
@@ -237,6 +266,9 @@
    SwDoc* pDoc = m_pObjArray[0].pFormat->GetDoc();
    SwFrameFormats& rFlyFormats = *pDoc->GetSpzFrameFormats();

    // This will store the textboxes from the ex-group-shapes
    std::vector<std::pair<SdrObject*, SwFrameFormat*>> vTextBoxes;

    for( sal_uInt16 n = 1; n < m_nSize; ++n )
    {
        SwUndoGroupObjImpl& rSave = m_pObjArray[n];
@@ -245,6 +277,13 @@

        SwDrawContact *pContact = static_cast<SwDrawContact*>(GetUserCall(pObj));

        // Save the textboxes
        if (auto pOldTextBoxNode = rSave.pFormat->GetOtherTextBoxFormat())
        {
            if (auto pTextBox = pOldTextBoxNode->GetTextBox(pObj))
                vTextBoxes.push_back(std::pair(pObj, pTextBox));
        }

        // object will destroy itself
        pContact->Changed( *pObj, SdrUserCallType::Delete, pObj->GetLastBoundRect() );
        pObj->SetUserCall( nullptr );
@@ -268,6 +307,18 @@

    SwDrawFrameFormat* pDrawFrameFormat = m_pObjArray[0].pFormat;

    // Restore the textboxes
    if (vTextBoxes.size())
    {
        auto pNewTextBoxNode = new SwTextBoxNode(m_pObjArray[0].pFormat);
        for (auto& rElem : vTextBoxes)
        {
            pNewTextBoxNode->AddTextBox(rElem.first, rElem.second);
            rElem.second->SetOtherTextBoxFormat(pNewTextBoxNode);
        }
        m_pObjArray[0].pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
    }

    // #i45952# - notify that position attributes are already set
    OSL_ENSURE(pDrawFrameFormat,
            "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object");
@@ -339,6 +390,9 @@
    SwDoc *const pDoc = & rContext.GetDoc();
    SwFrameFormats& rFlyFormats = *pDoc->GetSpzFrameFormats();

    // This will store the textboxes what were owned by this group
    std::vector<std::pair<SdrObject*, SwFrameFormat*>> vTextBoxes;

    // remove from array
    for( sal_uInt16 n = 1; n < m_nSize; ++n )
    {
@@ -346,6 +400,23 @@

        ::lcl_SaveAnchor( rSave.pFormat, rSave.nNodeIdx );

        // copy the textboxes for later use to this vector
        if (auto pTxBxNd = rSave.pFormat->GetOtherTextBoxFormat())
        {
            if (auto pGroupObj = m_pObjArray[0].pObj)
            {
                if (auto pChildren = pGroupObj->getChildrenOfSdrObject())
                {
                    for (size_t idx = 0; idx < pChildren->GetObjCount(); idx++)
                    {
                        auto pChild = pChildren->GetObj(idx);
                        if (auto pTextBox = pTxBxNd->GetTextBox(pChild))
                            vTextBoxes.push_back(std::pair(pChild, pTextBox));
                    }
                }
            }
        }

        rSave.pFormat->RemoveAllUnos();

        rFlyFormats.erase( std::find( rFlyFormats.begin(), rFlyFormats.end(), rSave.pFormat ));
@@ -362,6 +433,19 @@

    SwDrawFrameFormat* pDrawFrameFormat = m_pObjArray[0].pFormat;

    // Restore the vector content for the new formats
    if (vTextBoxes.size())
    {
        auto pNewTxBxNd = new SwTextBoxNode(m_pObjArray[0].pFormat);
        for (auto& rElem : vTextBoxes)
        {
            pNewTxBxNd->AddTextBox(rElem.first, rElem.second);
            rElem.second->SetOtherTextBoxFormat(pNewTxBxNd);
        }
        m_pObjArray[0].pFormat->SetOtherTextBoxFormat(pNewTxBxNd);
    }


    // #i45952# - notify that position attributes are already set
    OSL_ENSURE(pDrawFrameFormat,
            "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object");
@@ -380,6 +464,19 @@

    ::lcl_SaveAnchor( pFormat, m_pObjArray[0].nNodeIdx );

    // Store the textboxes in this vector for later use.
    std::vector<std::pair<SdrObject*, SwFrameFormat*>> vTextBoxes;
    if (auto pTextBoxNode = pFormat->GetOtherTextBoxFormat())
    {
        auto pMasterObj = m_pObjArray[0].pObj;

        if (auto pObjList = pMasterObj->getChildrenOfSdrObject())
            for (size_t idx = 0; idx < pObjList->GetObjCount(); idx++)
            {
                vTextBoxes.push_back(std::pair(pObjList->GetObj(idx), pTextBoxNode->GetTextBox(pObjList->GetObj(idx))));
            }
    }

    pFormat->RemoveAllUnos();

    // remove from array
@@ -396,6 +493,19 @@

        SwDrawFrameFormat* pDrawFrameFormat = rSave.pFormat;

        // Restore the textboxes for the restored group shape.
        for (auto& pElem : vTextBoxes)
        {
            if (pElem.first == rSave.pObj)
            {
                auto pTmpTxBxNd = new SwTextBoxNode(rSave.pFormat);
                pTmpTxBxNd->AddTextBox(rSave.pObj, pElem.second);
                pFormat->SetOtherTextBoxFormat(pTmpTxBxNd);
                pElem.second->SetOtherTextBoxFormat(pTmpTxBxNd);
                break;
            }
        }

        // #i45952# - notify that position attributes are already set
        OSL_ENSURE(pDrawFrameFormat,
                "<SwUndoDrawGroup::Undo(..)> - wrong type of frame format for drawing object" );
diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx
index 1ed8ec3..580553d 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -949,6 +949,7 @@
SwXShape::~SwXShape()
{
    SolarMutexGuard aGuard;

    if (m_xShapeAgg.is())
    {
        uno::Reference< uno::XInterface >  xRef;
@@ -1505,7 +1506,11 @@
                }
                else if (pEntry->nWID == FN_TEXT_BOX)
                {
                    bool bValue = SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT);
                    auto pSvxShape = GetSvxShape();
                    bool bValue = SwTextBoxHelper::isTextBox(
                        pFormat, RES_DRAWFRMFMT,
                        ((pSvxShape && pSvxShape->GetSdrObject()) ? pSvxShape->GetSdrObject()
                                                                  : pFormat->FindRealSdrObject()));
                    aRet <<= bValue;
                }
                else if (pEntry->nWID == RES_CHAIN)
diff --git a/sw/source/uibase/shells/drawsh.cxx b/sw/source/uibase/shells/drawsh.cxx
index beb197c..52a3b0d 100644
--- a/sw/source/uibase/shells/drawsh.cxx
+++ b/sw/source/uibase/shells/drawsh.cxx
@@ -498,7 +498,7 @@
                {
                    SwFrameFormat* pFrameFormat = ::FindFrameFormat(pObj);
                    // Allow creating a TextBox only in case this is a draw format without a TextBox so far.
                    if (pFrameFormat && pFrameFormat->Which() == RES_DRAWFRMFMT && !SwTextBoxHelper::isTextBox(pFrameFormat, RES_DRAWFRMFMT))
                    if (pFrameFormat && pFrameFormat->Which() == RES_DRAWFRMFMT && !SwTextBoxHelper::isTextBox(pFrameFormat, RES_DRAWFRMFMT, pObj))
                    {
                        if (SdrObjCustomShape* pCustomShape = dynamic_cast<SdrObjCustomShape*>( pObj) )
                        {
@@ -521,7 +521,7 @@
                {
                    SwFrameFormat* pFrameFormat = ::FindFrameFormat(pObj);
                    // Allow removing a TextBox only in case it has one.
                    if (pFrameFormat && SwTextBoxHelper::isTextBox(pFrameFormat, RES_DRAWFRMFMT))
                    if (pFrameFormat && SwTextBoxHelper::isTextBox(pFrameFormat, RES_DRAWFRMFMT, pObj))
                        bDisable = false;
                }