sw/inc/textboxhelper.hxx | 14 sw/qa/uitest/writer_tests7/tdf143574.py | 3 sw/source/core/doc/DocumentLayoutManager.cxx | 81 +++- sw/source/core/doc/docdraw.cxx | 30 + sw/source/core/doc/docfly.cxx | 4 sw/source/core/doc/docfmt.cxx | 7 sw/source/core/doc/textboxhelper.cxx | 456 ++++++++++++++------------- sw/source/core/draw/dcontact.cxx | 31 + sw/source/core/draw/dview.cxx | 12 sw/source/core/frmedt/fecopy.cxx | 4 sw/source/core/frmedt/fefly1.cxx | 22 + sw/source/core/frmedt/feshview.cxx | 6 sw/source/core/layout/atrfrm.cxx | 15 sw/source/core/layout/flycnt.cxx | 2 sw/source/core/text/porfly.cxx | 13 sw/source/core/undo/undraw.cxx | 110 ++++++ sw/source/core/unocore/unodraw.cxx | 7 sw/source/uibase/shells/drawsh.cxx | 4 18 files changed, 531 insertions(+), 290 deletions(-)
New commits: commit ba5156abace2e41ec4d21397c0875f7e1efd2beb Author: Attila Bakos (NISZ) <bakos.attilakar...@nisz.hu> AuthorDate: Wed Sep 1 16:38:07 2021 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Thu Sep 16 12:56:10 2021 +0200 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 <nem...@numbertext.org> Reviewed-by: László Németh <nem...@numbertext.org> diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx index 3cd442ed7194..978cf77327b9 100644 --- a/sw/inc/textboxhelper.hxx +++ b/sw/inc/textboxhelper.hxx @@ -69,10 +69,10 @@ public: /// 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 @@ public: 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 @@ public: /// 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 @@ public: // 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 @@ public: 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 08e59b7c682a..61265e229f57 100644 --- a/sw/qa/uitest/writer_tests7/tdf143574.py +++ b/sw/qa/uitest/writer_tests7/tdf143574.py @@ -33,7 +33,6 @@ class tdf143574(UITestCase): # 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 1e071ef3ac5e..4cee8ad7c0b0 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 @@ SwFrameFormat *DocumentLayoutManager::CopyLayoutFormat( 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()) - { - // 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); + auto pObj = rSource.FindRealSdrObject(); + auto pTextBoxNd = new SwTextBoxNode(pDest); + pDest->SetOtherTextBoxFormat(pTextBoxNd); - if (!bMakeFrames && rNewAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR) + if (pObj) { - // 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); + 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); - // Link FLY and DRAW formats, so it becomes a text box - auto pTextBox = new SwTextBoxNode(pDest); - pTextBox->AddTextBox(pDest->FindRealSdrObject(), pDestTextBox); + 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); + } - pDest->SetOtherTextBoxFormat(pTextBox); - pDestTextBox->SetOtherTextBoxFormat(pTextBox); + if (!bIsGroupObj) + break; + } + } } if (pDest->GetName().isEmpty()) diff --git a/sw/source/core/doc/docdraw.cxx b/sw/source/core/doc/docdraw.cxx index 609b174072e0..0aff4b8993ff 100644 --- a/sw/source/core/doc/docdraw.cxx +++ b/sw/source/core/doc/docdraw.cxx @@ -208,6 +208,8 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView ) 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 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView ) 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 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView ) 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 @@ void SwDoc::UnGroupSelection( SdrView& rDrawView ) 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 @@ void SwDoc::UnGroupSelection( SdrView& rDrawView ) 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 6ff9bf910240..d8fe293c7f0a 100644 --- a/sw/source/core/doc/docfly.cxx +++ b/sw/source/core/doc/docfly.cxx @@ -577,7 +577,7 @@ bool SwDoc::SetFlyFrameAttr( SwFrameFormat& rFlyFormat, SfxItemSet& rSet ) getIDocumentState().SetModified(); - SwTextBoxHelper::syncFlyFrameAttr(rFlyFormat, rSet); + //SwTextBoxHelper::syncFlyFrameAttr(rFlyFormat, rSet); return bRet; } @@ -924,7 +924,7 @@ bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList, 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 16ad4d8dfcd0..d2ccfaf81544 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -483,8 +483,11 @@ void SwDoc::SetAttr( const SfxItemSet& rSet, SwFormat& rFormat ) 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 3858da359a3c..93b9564a59bf 100644 --- a/sw/source/core/doc/textboxhelper.cxx +++ b/sw/source/core/doc/textboxhelper.cxx @@ -61,9 +61,10 @@ using namespace com::sun::star; 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 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo 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 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo 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 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo 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 @@ uno::Any SwTextBoxHelper::queryInterface(const SwFrameFormat* pShape, const uno: 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 @@ tools::Rectangle SwTextBoxHelper::getTextRectangle(SwFrameFormat* pShape, bool b 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 @@ tools::Rectangle SwTextBoxHelper::getTextRectangle(SwFrameFormat* pShape, bool b } 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 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP // 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 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP 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 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP 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 @@ css::uno::Any SwTextBoxHelper::getProperty(SwFrameFormat const* pShape, const OU } 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 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_u 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 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_u case MID_ANCHOR_ANCHORTYPE: { setWrapThrough(pShape); - changeAnchor(pShape); - doTextBoxPositioning(pShape); + changeAnchor(pShape, pObj); + doTextBoxPositioning(pShape, pObj); return; } @@ -844,7 +848,9 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_u // 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 @@ text::TextContentAnchorType SwTextBoxHelper::mapAnchorType(const RndStdIds& rAnc 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 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& // 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 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& // 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 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& 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 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& 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 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const& } 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 @@ void SwTextBoxHelper::updateTextBoxMargin(SdrObject* pObj) 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 @@ bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape) 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 SwFormatAnchor& rOldAnch = pFormat->GetAnchor(); + const SwFormatAnchor& rNewAnch = pShape->GetAnchor(); - const auto pOldCnt = rOldAnch.GetContentAnchor(); - const auto pNewCnt = rNewAnch.GetContentAnchor(); + const auto pOldCnt = rOldAnch.GetContentAnchor(); + const auto pNewCnt = rNewAnch.GetContentAnchor(); - const uno::Any aShapeHorRelOrient - = uno::makeAny(pShape->GetHoriOrient().GetRelationOrient()); + const uno::Any aShapeHorRelOrient + = uno::makeAny(pShape->GetHoriOrient().GetRelationOrient()); - if (isAnchorTypeDifferent(pShape)) + if (isAnchorTypeDifferent(pShape) || (pObj && pObj != pShape->FindRealSdrObject())) + { + 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_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(text::TextContentAnchorType_AT_PAGE); + uno::Any aValue(mapAnchorType(rNewAnch.GetAnchorId())); 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())); + pFormat->SetFormatAttr(rNewAnch); } - else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE && pNewCnt) + } + else + { + if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR) { - 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); - } + 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 { - 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()); - } + xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION, + aShapeHorRelOrient); + pFormat->SetFormatAttr(pShape->GetAnchor()); } } - catch (uno::Exception& e) - { - SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << e.Message); - } } - - 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(pShape, false)); + tools::Rectangle aRect( + getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), false)); - auto nLeftSpace = pShape->GetLRSpace().GetLeft(); + auto nLeftSpace = pShape->GetLRSpace().GetLeft(); - SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient()); - aNewHOri.SetPos(aRect.Left() + nLeftSpace); + SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient()); + aNewHOri.SetPos(aRect.Left() + nLeftSpace); - SwFormatVertOrient aNewVOri(pFormat->GetVertOrient()); - aNewVOri.SetPos(aRect.Top() + pShape->GetVertOrient().GetPos()); + 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!"); + // tdf#140598: Do not apply wrong rectangle position. + if (aRect.TopLeft() != Point(0, 0)) + { + 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()); + SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!"); + } + else + { + tools::Rectangle aRect( + getTextRectangle(pObj ? pObj : pShape->FindRealSdrObject(), false)); - pFormat->SetFormatAttr(aNewHOri); - pFormat->SetFormatAttr(aNewVOri); - } - else - SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!"); + // 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); } - return true; + else + SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!"); } + return true; } + return false; } @@ -1307,52 +1324,59 @@ bool SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(const SwFrameFormat* pShap 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(SwFrameFormat* pOwnerShape) 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 @@ void SwTextBoxNode::DelTextBox(SdrObject* pDrawObject) 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 383be2c56f51..7cd60ce197d0 100644 --- a/sw/source/core/draw/dcontact.cxx +++ b/sw/source/core/draw/dcontact.cxx @@ -1091,7 +1091,7 @@ static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat) 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 @@ 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)); + } + } SwTwips nXPosDiff(0); SwTwips nYPosDiff(0); @@ -1338,7 +1344,7 @@ void SwDrawContact::Changed_( const SdrObject& rObj, // 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 @@ void SwDrawContact::Changed_( const SdrObject& rObj, 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 fb0e1f9c8294..33d6a83fb1f8 100644 --- a/sw/source/core/draw/dview.cxx +++ b/sw/source/core/draw/dview.cxx @@ -967,8 +967,16 @@ void SwDrawView::DeleteMarked() 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 1394c7b7469b..6e3792eb9f29 100644 --- a/sw/source/core/frmedt/fecopy.cxx +++ b/sw/source/core/frmedt/fecopy.cxx @@ -400,9 +400,9 @@ bool SwFEShell::CopyDrawSel( SwFEShell& rDestShell, const Point& rSttPt, 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 c8fdf46bb185..a453e9906c65 100644 --- a/sw/source/core/frmedt/fefly1.cxx +++ b/sw/source/core/frmedt/fefly1.cxx @@ -446,7 +446,7 @@ Point SwFEShell::FindAnchorPos( const Point& rAbsPos, bool bMoveIt ) 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 @@ Point SwFEShell::FindAnchorPos( const Point& rAbsPos, bool bMoveIt ) } 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 @@ Point SwFEShell::FindAnchorPos( const Point& rAbsPos, bool bMoveIt ) 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 2041bc4e7451..c55324d48150 100644 --- a/sw/source/core/frmedt/feshview.cxx +++ b/sw/source/core/frmedt/feshview.cxx @@ -1102,7 +1102,7 @@ void SwFEShell::SelectionToTop( bool bTop ) 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 @@ void SwFEShell::SelectionToBottom( bool bBottom ) } } // And set correct layer for the selected textbox. - SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat); + SwTextBoxHelper::DoTextBoxZOrderCorrection(pFormat, pObj); } GetDoc()->getIDocumentState().SetModified(); @@ -1220,7 +1220,7 @@ void SwFEShell::ChangeOpaque( SdrLayerID nLayerId ) 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 adcc38806465..76c961168110 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 @@ SwFrameFormat::~SwFrameFormat() 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 33b539949917..9f3bf54debb0 100644 --- a/sw/source/core/layout/flycnt.cxx +++ b/sw/source/core/layout/flycnt.cxx @@ -535,7 +535,7 @@ void SwFlyAtContentFrame::MakeAll(vcl::RenderContext* pRenderContext) { // 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 260a1860d375..de72a0ec6076 100644 --- a/sw/source/core/text/porfly.cxx +++ b/sw/source/core/text/porfly.cxx @@ -375,8 +375,7 @@ void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, const Point &rBase, // 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 @@ void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, const Point &rBase, // 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 @@ void SwFlyCntPortion::SetBase( const SwTextFrame& rFrame, const Point &rBase, 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 fc7efcdfec70..8fd748dda95e 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 @@ void SwUndoDrawGroup::UndoImpl(::sw::UndoRedoContext &) 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 @@ void SwUndoDrawGroup::UndoImpl(::sw::UndoRedoContext &) // #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 @@ void SwUndoDrawGroup::RedoImpl(::sw::UndoRedoContext &) 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 @@ void SwUndoDrawGroup::RedoImpl(::sw::UndoRedoContext &) 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 @@ void SwUndoDrawGroup::RedoImpl(::sw::UndoRedoContext &) 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 @@ void SwUndoDrawUnGroup::UndoImpl(::sw::UndoRedoContext & rContext) 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 @@ void SwUndoDrawUnGroup::UndoImpl(::sw::UndoRedoContext & rContext) ::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 @@ void SwUndoDrawUnGroup::UndoImpl(::sw::UndoRedoContext & rContext) 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 @@ void SwUndoDrawUnGroup::RedoImpl(::sw::UndoRedoContext &) ::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 @@ void SwUndoDrawUnGroup::RedoImpl(::sw::UndoRedoContext &) 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 1ed8ec3a5d2e..580553dbf8a2 100644 --- a/sw/source/core/unocore/unodraw.cxx +++ b/sw/source/core/unocore/unodraw.cxx @@ -949,6 +949,7 @@ void SwXShape::AddExistingShapeToFormat( SdrObject const & _rObj ) SwXShape::~SwXShape() { SolarMutexGuard aGuard; + if (m_xShapeAgg.is()) { uno::Reference< uno::XInterface > xRef; @@ -1505,7 +1506,11 @@ uno::Any SwXShape::getPropertyValue(const OUString& rPropertyName) } 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 beb197c87fa9..52a3b0d02beb 100644 --- a/sw/source/uibase/shells/drawsh.cxx +++ b/sw/source/uibase/shells/drawsh.cxx @@ -498,7 +498,7 @@ void SwDrawShell::GetState(SfxItemSet& rSet) { 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 @@ void SwDrawShell::GetState(SfxItemSet& rSet) { 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; }