summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAttila Bakos (NISZ) <bakos.attilakaroly@nisz.hu>2021-11-03 15:39:32 +0100
committerLászló Németh <nemeth@numbertext.org>2021-11-24 11:51:07 +0100
commiteabcfb3f18a6944d9ad89cecd3eb3ca7a2259cf3 (patch)
treed1c66ab6056a467e3fc07bdbf6f07e179cb9e678
parentbecd76743fd7a3ae84404f26b1afb60b923cabb2 (diff)
tdf#129183 sw: textboxes in group shapes - part 3
Grouping/ungrouping nested groups works now. Manual test: 1. Insert Shape. 2. Right-click on selected shape, Add Text Box (and some text). 3. Insert a new shape. 4. Select and group the two shapes. 3. Insert a third shape. 4. Select and group the shape and the previously grouped shapes. The text box remains in the nested shape group. Details: 1) tdf#144271 memory leak of SwTextBoxHelper, by replacing the textbox structure vector with std::unordered map, and rethinking of the ownership of the objects. If a SwFrameFormat dies, and that is a FLYFRMFMT, it will be deleted from the textbox node and the FrameFormat table in the doc too, and the drawing will be stay as it was before. If the dying format is a drawing, all the textboxes, and the node will be deleted. 2) Introducing the new UNO property TextBoxContent, which is needed for writerfilter/xmloff later to set a new textbox for the shape via UNO. 3) Missing parameters are present now for syncing the textbox parameters. 4) Introducing a new function namely the handleGroupTextBox() to do the tasks simply with all textboxes in a group shape. This can handle nested groups as well (group in a group). Known issues: now copy of nested group objects is implemented but not enabled, because it causes an assert. Change-Id: I931886eda01c7a3db93098de10f5e5f48f2f217b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124657 Tested-by: László Németh <nemeth@numbertext.org> Reviewed-by: László Németh <nemeth@numbertext.org>
-rw-r--r--sw/inc/textboxhelper.hxx74
-rw-r--r--sw/inc/unomid.h4
-rw-r--r--sw/inc/unoprnms.hxx1
-rw-r--r--sw/qa/uitest/data/ComplexGroupShapeTest.odtbin0 -> 11448 bytes
-rw-r--r--sw/qa/uitest/writer_tests4/ComplexGroupShapeTest.py124
-rw-r--r--sw/source/core/doc/DocumentLayoutManager.cxx45
-rw-r--r--sw/source/core/doc/docdraw.cxx55
-rw-r--r--sw/source/core/doc/docfly.cxx11
-rw-r--r--sw/source/core/doc/textboxhelper.cxx492
-rw-r--r--sw/source/core/draw/dcontact.cxx11
-rw-r--r--sw/source/core/draw/dview.cxx8
-rw-r--r--sw/source/core/frmedt/feshview.cxx4
-rw-r--r--sw/source/core/layout/atrfrm.cxx5
-rw-r--r--sw/source/core/unocore/unodraw.cxx66
-rw-r--r--sw/source/core/unocore/unomap.cxx3
-rw-r--r--sw/source/core/unocore/unomap1.cxx1
16 files changed, 702 insertions, 202 deletions
diff --git a/sw/inc/textboxhelper.hxx b/sw/inc/textboxhelper.hxx
index 2e5b27cfccb0..10841ed8626c 100644
--- a/sw/inc/textboxhelper.hxx
+++ b/sw/inc/textboxhelper.hxx
@@ -11,6 +11,7 @@
#define INCLUDED_SW_INC_TEXTBOXHELPER_HXX
#include <map>
+#include <unordered_map>
#include <optional>
#include <set>
#include <vector>
@@ -60,12 +61,16 @@ public:
/// the original text in the shape will be copied to the frame
/// The textbox is created for the shape given by the pObject parameter.
static void create(SwFrameFormat* pShape, SdrObject* pObject, bool bCopyText = false);
+ /// Sets the given textframe as textbox for the given (group member) shape.
+ static void set(SwFrameFormat* pShape, SdrObject* pObject,
+ css::uno::Reference<css::text::XTextFrame> xNew);
/// Destroy a TextBox for a shape. If the format has more textboxes
/// like group shapes, it will destroy only that textbox what belongs
/// to the given pObject shape.
static void destroy(const SwFrameFormat* pShape, const SdrObject* pObject);
/// Get interface of a shape's TextBox, if there is any.
- static css::uno::Any queryInterface(const SwFrameFormat* pShape, const css::uno::Type& rType);
+ static css::uno::Any queryInterface(const SwFrameFormat* pShape, const css::uno::Type& rType,
+ SdrObject* pObj = nullptr);
/// Sync property of TextBox with the one of the shape.
static void syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
@@ -90,7 +95,7 @@ public:
/// Sets the surround to through for the textframe of the given shape,
/// not to interfere with the layout. Returns true on success.
- static bool setWrapThrough(SwFrameFormat* pShape);
+ static bool setWrapThrough(SwFrameFormat* pShape, SdrObject* pObj = nullptr);
/// Sets the anchor of the associated textframe of the given shape, and
/// returns true on success.
@@ -100,15 +105,20 @@ public:
/// returns true on success.
static bool doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pObj);
+ /// Sets the correct size of textframe depending on the given SdrObject.
+ static bool setTextBoxSize(const SwFrameFormat* pShape, SdrObject* pObj);
+
/// Returns true if the anchor different for the given shape, and the
/// associated textframe of the given shape.
/// Note: In case of AS_CHAR anchor the anchor type must be different,
/// because if not, layout breaks, but this situation also handled by
/// this function, and returns true in that case too.
- static std::optional<bool> isAnchorTypeDifferent(const SwFrameFormat* pShape);
+ static std::optional<bool> isAnchorTypeDifferent(const SwFrameFormat* pShape,
+ SdrObject* pObj = nullptr);
/// Returns true if the given shape has a valid textframe.
- static bool isTextBoxShapeHasValidTextFrame(const SwFrameFormat* pShape);
+ static bool isTextBoxShapeHasValidTextFrame(const SwFrameFormat* pShape,
+ SdrObject* pObj = nullptr);
// 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.
@@ -177,6 +187,26 @@ public:
/// Undo the effect of saveLinks() + individual resetLink() calls.
static void restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrameFormat*>& rNew,
SavedLink& rSavedLinks);
+
+ /// The following actions are implemented for groupshapes with textboxes too.
+ /// The selected action will be done for all of the group member textboxes.
+ enum GroupTextBoxActionType
+ {
+ POSITION_SIZE_AND_ANCHOR_CHANGE,
+ DELETE,
+ Z_ORDER_CHANGE
+ };
+
+ /// Does the selected action with ALL textboxes in the group.
+ /// Parameters:
+ /// - pGroupShapeFormat: The frame format of the group shape where the textboxes belongs to.
+ /// - pGroupObject: The drawing object for the group.
+ /// - eActionType: The action what the function is supposed to do.
+ /// WARN: This function will run recursive! ALL textboxes of the group will be handled by
+ /// the desired action!
+ static void handleTextBoxGroup(SwFrameFormat* pGroupShapeFormat,
+ GroupTextBoxActionType eActionType,
+ SdrObject* pGroupObject = nullptr);
};
/// Textboxes are basically textframe + shape pairs. This means one shape has one frame.
@@ -185,27 +215,15 @@ public:
/// it can have multiple textboxes.
class SwTextBoxNode
{
- // One TextBox-entry
- struct SwTextBoxElement
- {
- // The textframe format
- SwFrameFormat* m_pTextBoxFormat;
- // The Draw object where the textbox belongs to
- SdrObject* m_pDrawObject;
- // This is for indicating if the textbox is in special case: for example during undo.
- bool m_bIsActive;
- };
-
- // This vector stores the textboxes what belongs to this node
- std::vector<SwTextBoxElement> m_pTextBoxes;
+ // This map stores the textboxes what belongs to this node
+ std::unordered_map<const SdrObject*, SwFrameFormat*> m_pTextBoxTable;
// This is the pointer to the shape format, which has this node
// (and the textboxes)
SwFrameFormat* m_pOwnerShapeFormat;
-
-public:
// Not needed.
SwTextBoxNode() = delete;
+public:
// ctor
SwTextBoxNode(SwFrameFormat* pOwnerShapeFormat);
// dtor
@@ -224,24 +242,24 @@ public:
// Parameters:
// pDrawObject: The shape which have the textbox to be deleted.
void DelTextBox(const SdrObject* pDrawObject);
+ void DelTextBox(SwFrameFormat* pTextBox);
// This will return with the frame format of the textbox what belongs
// to the given shape (pDrawObject)
SwFrameFormat* GetTextBox(const SdrObject* pDrawObject) const;
- // Is this textbox has special state, undo for example?
- bool IsTextBoxActive(const SdrObject* pDrawObject) const;
-
- // Setters for the state flag.
- void SetTextBoxInactive(const SdrObject* pDrawObject);
- void SetTextBoxActive(const SdrObject* pDrawObject);
-
// If this is a group shape, that returns true.
- bool IsGroupTextBox() const;
+ bool IsGroupTextBoxShape() const;
// This returns with the shape what this class belongs to.
SwFrameFormat* GetOwnerShape() { return m_pOwnerShapeFormat; };
// This will give the current number of textboxes.
- size_t GetTextBoxCount() const { return m_pTextBoxes.size(); };
+ size_t GetTextBoxCount() const { return m_pTextBoxTable.size(); };
+
+ // Gives a const reference to the text box table, useful for undo and grouping.
+ const std::unordered_map<const SdrObject*, SwFrameFormat*>& GetTextBoxTable() const
+ {
+ return m_pTextBoxTable;
+ };
};
#endif // INCLUDED_SW_INC_TEXTBOXHELPER_HXX
diff --git a/sw/inc/unomid.h b/sw/inc/unomid.h
index d249b32fc25a..5b6e8a0cb6cd 100644
--- a/sw/inc/unomid.h
+++ b/sw/inc/unomid.h
@@ -151,6 +151,10 @@
// SwFormatFollowTextFlow
#define MID_FOLLOW_TEXT_FLOW 0
+// TextBox
+#define MID_TEXTBOX 0
+#define MID_TEXTBOX_CONTENT 1
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx
index 7ef5d0a58cd7..1e16bc413d01 100644
--- a/sw/inc/unoprnms.hxx
+++ b/sw/inc/unoprnms.hxx
@@ -74,6 +74,7 @@
#define UNO_NAME_FOOTER_RIGHT_MARGIN "FooterRightMargin"
#define UNO_NAME_TEXT_RANGE "TextRange"
#define UNO_NAME_TEXT_BOX "TextBox"
+#define UNO_NAME_TEXT_BOX_CONTENT "TextBoxContent"
#define UNO_NAME_NAME "Name"
#define UNO_NAME_CHAR_STYLE_NAME "CharStyleName"
#define UNO_NAME_ANCHOR_CHAR_STYLE_NAME "AnchorCharStyleName"
diff --git a/sw/qa/uitest/data/ComplexGroupShapeTest.odt b/sw/qa/uitest/data/ComplexGroupShapeTest.odt
new file mode 100644
index 000000000000..8fe093203690
--- /dev/null
+++ b/sw/qa/uitest/data/ComplexGroupShapeTest.odt
Binary files differ
diff --git a/sw/qa/uitest/writer_tests4/ComplexGroupShapeTest.py b/sw/qa/uitest/writer_tests4/ComplexGroupShapeTest.py
new file mode 100644
index 000000000000..cdac088a32d7
--- /dev/null
+++ b/sw/qa/uitest/writer_tests4/ComplexGroupShapeTest.py
@@ -0,0 +1,124 @@
+# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+from uitest.framework import UITestCase
+from uitest.uihelper.common import get_state_as_dict
+from uitest.uihelper.common import select_pos
+from uitest.uihelper.common import get_url_for_data_file
+from libreoffice.uno.propertyvalue import mkPropertyValues
+import time
+
+class ComplexGroupShapeTest(UITestCase):
+ def test_ComplexGroupShape(self):
+ with self.ui_test.load_file(get_url_for_data_file("ComplexGroupShapeTest.odt")):
+ xWriterDoc = self.xUITest.getTopFocusWindow()
+ xWriterEdit = xWriterDoc.getChild("writer_edit")
+ document = self.ui_test.get_component()
+
+ # check the shape type
+ self.assertEqual("com.sun.star.drawing.GroupShape", document.DrawPage.getByIndex(1).ShapeType)
+
+ # select the shape
+ self.xUITest.executeCommand(".uno:JumpToNextFrame")
+ self.ui_test.wait_until_child_is_available('metricfield')
+
+ # go inside the group
+ self.xUITest.executeCommand(".uno:EnterGroup")
+
+ # select a shape in the group
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+
+ # add a textbox to this subshape
+ self.xUITest.executeCommand(".uno:AddTextBox")
+
+ # select the next shape in the group
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+
+ # add a textbox to this subshape
+ self.xUITest.executeCommand(".uno:AddTextBox")
+
+ # leave the groupshape
+ self.xUITest.executeCommand(".uno:LeaveGroup")
+
+ # select the other shape
+ self.xUITest.executeCommand(".uno:JumpToNextFrame")
+ self.ui_test.wait_until_child_is_available('metricfield')
+
+ # get the current selection
+ ShapeCollection = document.getCurrentSelection()
+
+ # extend the selection with the grouped shape
+ ShapeCollection.add(document.DrawPage.getByIndex(0))
+ ShapeCollection.add(document.DrawPage.getByIndex(1))
+
+ # select these shapes
+ document.getCurrentController().select(ShapeCollection)
+
+ # do ungroup
+ self.xUITest.executeCommand(".uno:FormatGroup")
+
+ # deselect
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"ESC"}))
+ time.sleep(0.1)
+
+ # select the group
+ self.xUITest.executeCommand(".uno:JumpToNextFrame")
+ self.ui_test.wait_until_child_is_available('metricfield')
+
+ # move it down
+ for i in range(1, 30):
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"DOWN"}))
+ time.sleep(0.1)
+
+ # select again
+ self.xUITest.executeCommand(".uno:JumpToNextFrame")
+ self.ui_test.wait_until_child_is_available('metricfield')
+
+ # do ungroup
+ self.xUITest.executeCommand(".uno:FormatUngroup")
+
+ # deselect everything
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"ESC"}))
+ time.sleep(0.1)
+
+ # select the first ex-group member shape
+ self.xUITest.executeCommand(".uno:JumpToNextFrame")
+ self.ui_test.wait_until_child_is_available('metricfield')
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+
+ # check if it is a textbox
+ self.assertEqual(True,document.getCurrentSelection().getByIndex(0).TextBox)
+
+ # go to the other one
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+
+ # this is still a group, so it cannot be a textbox
+ self.assertEqual(False,document.getCurrentSelection().getByIndex(0).TextBox)
+
+ # do ungroup
+ self.xUITest.executeCommand(".uno:FormatUngroup")
+
+ # deselect
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE":"ESC"}))
+ time.sleep(0.1)
+
+ # select one shape of the last group
+ self.xUITest.executeCommand(".uno:JumpToNextFrame")
+ self.ui_test.wait_until_child_is_available('metricfield')
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+ xWriterEdit.executeAction("TYPE", mkPropertyValues({"KEYCODE": "TAB"}))
+
+ # check if it is a textbox
+ self.assertEqual(True,document.getCurrentSelection().getByIndex(0).TextBox)
+
+ # Without the fix in place, the following problems occurred during this test:
+ # - After the grouping old textbox frames detached from their shape before
+ # - Moving caused messed layout
+ # - After ungroup, the shapes in the embed group lost their textbox
+
+# vim: set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/sw/source/core/doc/DocumentLayoutManager.cxx b/sw/source/core/doc/DocumentLayoutManager.cxx
index c67e9e05e9a6..ae49a77183c0 100644
--- a/sw/source/core/doc/DocumentLayoutManager.cxx
+++ b/sw/source/core/doc/DocumentLayoutManager.cxx
@@ -312,7 +312,39 @@ void DocumentLayoutManager::DelLayoutFormat( SwFrameFormat *pFormat )
}
m_rDoc.getIDocumentState().SetModified();
}
-
+#if 0
+// TODO: Replace the textbox part of frameformat copying method to this.
+// Now disabled because cause asserts in sw (Node index is still registered in dtor).
+// Without this nested group textboxes are not handled correctly.
+static void lcl_CopyTextBoxes(SwDoc* pDoc, SwTextBoxNode* pSrcTextBoxes, const SdrObject* pSrcObj,
+ SwTextBoxNode* pDestTextBoxes, SdrObject* pDestObj,
+ bool bSetTextFlyAtt, bool bMakeFrames)
+{
+ auto pSrcChildren = pSrcObj->getChildrenOfSdrObject();
+ auto pDestChildren = pDestObj->getChildrenOfSdrObject();
+ if (pSrcChildren && pDestChildren)
+ {
+ if (pSrcChildren->GetObjCount() == pDestChildren->GetObjCount())
+ for (size_t i = 0; i < pSrcChildren->GetObjCount(); ++i)
+ {
+ lcl_CopyTextBoxes(pDoc, pSrcTextBoxes, pSrcChildren->GetObj(i), pDestTextBoxes,
+ pDestChildren->GetObj(i), bSetTextFlyAtt, bMakeFrames);
+ }
+ }
+ else
+ {
+ if (auto pSourceTextBoxFormat = pSrcTextBoxes->GetTextBox(pSrcObj))
+ {
+ assert(pSourceTextBoxFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR);
+ auto pNewTextBoxFormat = pDoc->GetDocumentLayoutManager().CopyLayoutFormat(
+ *pSourceTextBoxFormat, pSourceTextBoxFormat->GetAnchor(), bSetTextFlyAtt,
+ bMakeFrames);
+ pDestTextBoxes->AddTextBox(pDestObj, pNewTextBoxFormat);
+ pNewTextBoxFormat->SetOtherTextBoxFormat(pDestTextBoxes);
+ }
+ }
+}
+#endif
/** Copies the stated format (pSrc) to pDest and returns pDest.
If there's no pDest, it is created.
@@ -469,7 +501,18 @@ SwFrameFormat *DocumentLayoutManager::CopyLayoutFormat(
auto pObj = rSource.FindRealSdrObject();
auto pTextBoxNd = new SwTextBoxNode(pDest);
pDest->SetOtherTextBoxFormat(pTextBoxNd);
+#if 0
+ // TODO: Change the copy algorithm to this. See comment in lcl_CopyTextBoxes for details.
+ 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;
+ }
+ lcl_CopyTextBoxes(&m_rDoc, rSource.GetOtherTextBoxFormat(), rSource.FindRealSdrObject(),
+ pTextBoxNd, pDest->FindRealSdrObject(), bSetTextFlyAtt, bMakeFrames);
+#endif
if (pObj)
{
const bool bIsGroupObj = pObj->getChildrenOfSdrObject();
diff --git a/sw/source/core/doc/docdraw.cxx b/sw/source/core/doc/docdraw.cxx
index 0aff4b8993ff..39adffb8b5a0 100644
--- a/sw/source/core/doc/docdraw.cxx
+++ b/sw/source/core/doc/docdraw.cxx
@@ -209,7 +209,7 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
bGroupMembersNotPositioned = pAnchoredDrawObj->NotYetPositioned();
}
- std::vector<std::pair<SwFrameFormat*, SdrObject*>> vSavedTextBoxes;
+ std::unordered_map<const SdrObject*, SwFrameFormat*> vSavedTextBoxes;
// Destroy ContactObjects and formats.
for( size_t i = 0; i < rMrkList.GetMarkCount(); ++i )
{
@@ -224,8 +224,13 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
"<SwDoc::GroupSelection(..)> - group members have different positioning status!" );
#endif
// Before the format will be killed, save its textbox for later use.
- if (auto pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(pContact->GetFormat(), RES_DRAWFRMFMT, pObj))
- vSavedTextBoxes.push_back(std::pair<SwFrameFormat*, SdrObject*>(pTextBox, pObj));
+ if (auto pTxBxNd = pContact->GetFormat()->GetOtherTextBoxFormat())
+ {
+ for (auto& rElem : pTxBxNd->GetTextBoxTable())
+ {
+ vSavedTextBoxes.emplace(rElem);
+ }
+ }
pFormat = static_cast<SwDrawFrameFormat*>(pContact->GetFormat());
// Deletes itself!
@@ -256,8 +261,8 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
auto pTextBoxNode = new SwTextBoxNode(pFormat);
for (auto& pTextBoxEntry : vSavedTextBoxes)
{
- pTextBoxNode->AddTextBox(pTextBoxEntry.second, pTextBoxEntry.first);
- pTextBoxEntry.first->SetOtherTextBoxFormat(pTextBoxNode);
+ pTextBoxNode->AddTextBox(const_cast<SdrObject*>(pTextBoxEntry.first), pTextBoxEntry.second);
+ pTextBoxEntry.second->SetOtherTextBoxFormat(pTextBoxNode);
}
pFormat->SetOtherTextBoxFormat(pTextBoxNode);
vSavedTextBoxes.clear();
@@ -299,6 +304,27 @@ SwDrawContact* SwDoc::GroupSelection( SdrView& rDrawView )
return pNewContact;
}
+static void lcl_CollectTextBoxesForSubGroupObj(SwFrameFormat* pTargetFormat, SwTextBoxNode* pTextBoxNode,
+ SdrObject* pSourceObjs)
+{
+ if (auto pChildrenObjs = pSourceObjs->getChildrenOfSdrObject())
+ for (size_t i = 0; i < pChildrenObjs->GetObjCount(); ++i)
+ lcl_CollectTextBoxesForSubGroupObj(pTargetFormat, pTextBoxNode, pChildrenObjs->GetObj(i));
+ else
+ {
+ if (auto pTextBox = pTextBoxNode->GetTextBox(pSourceObjs))
+ {
+ if (!pTargetFormat->GetOtherTextBoxFormat())
+ {
+ pTargetFormat->SetOtherTextBoxFormat(new SwTextBoxNode(pTargetFormat));
+ }
+
+ pTargetFormat->GetOtherTextBoxFormat()->AddTextBox(pSourceObjs, pTextBox);
+ pTextBox->SetOtherTextBoxFormat(pTargetFormat->GetOtherTextBoxFormat());
+ }
+ }
+}
+
void SwDoc::UnGroupSelection( SdrView& rDrawView )
{
bool const bUndo = GetIDocumentUndoRedo().DoesUndo();
@@ -349,13 +375,22 @@ void SwDoc::UnGroupSelection( SdrView& rDrawView )
pFormat->SetFormatAttr( aAnch );
if (pTextBoxNode)
- if (auto pTextBoxFormat = pTextBoxNode->GetTextBox(pSubObj))
+ {
+ if (!pSubObj->getChildrenOfSdrObject())
+ {
+ if (auto pTextBoxFormat = pTextBoxNode->GetTextBox(pSubObj))
+ {
+ auto pNewTextBoxNode = new SwTextBoxNode(pFormat);
+ pNewTextBoxNode->AddTextBox(pSubObj, pTextBoxFormat);
+ pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
+ pTextBoxFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
+ };
+ }
+ else
{
- auto pNewTextBoxNode = new SwTextBoxNode(pFormat);
- pNewTextBoxNode->AddTextBox(pSubObj, pTextBoxFormat);
- pFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
- pTextBoxFormat->SetOtherTextBoxFormat(pNewTextBoxNode);
+ lcl_CollectTextBoxesForSubGroupObj(pFormat, pTextBoxNode, pSubObj);
}
+ }
// #i36010# - set layout direction of the position
pFormat->SetPositionLayoutDir(
diff --git a/sw/source/core/doc/docfly.cxx b/sw/source/core/doc/docfly.cxx
index 6b73f1f756b5..16365ebbbfec 100644
--- a/sw/source/core/doc/docfly.cxx
+++ b/sw/source/core/doc/docfly.cxx
@@ -577,8 +577,6 @@ bool SwDoc::SetFlyFrameAttr( SwFrameFormat& rFlyFormat, SfxItemSet& rSet )
getIDocumentState().SetModified();
- //SwTextBoxHelper::syncFlyFrameAttr(rFlyFormat, rSet);
-
return bRet;
}
@@ -920,12 +918,9 @@ bool SwDoc::ChgAnchor( const SdrMarkList& _rMrkList,
pNd->InsertItem( aFormat, aPos.nContent.GetIndex(), 0 );
// Has a textbox attached to the format? Sync it as well!
- if (SwTextBoxHelper::getOtherTextBoxFormat(pContact->GetFormat(),
- RES_DRAWFRMFMT))
- {
- SwTextBoxHelper::syncFlyFrameAttr(*pContact->GetFormat(),
- pContact->GetFormat()->GetAttrSet(), pObj);
- }
+ SwTextBoxHelper::syncFlyFrameAttr(*pContact->GetFormat(),
+ pContact->GetFormat()->GetAttrSet(), pObj);
+
}
break;
default:
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 418c69927228..8bd107623b8a 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -187,7 +187,8 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo
syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)), pObject);
if (bIsGroupObj)
- doTextBoxPositioning(pShape, pObject);
+ handleTextBoxGroup(
+ pShape, SwTextBoxHelper::GroupTextBoxActionType::POSITION_SIZE_AND_ANCHOR_CHANGE);
// Check if the shape had text before and move it to the new textframe
if (!bCopyText || sCopyableText.isEmpty())
@@ -207,18 +208,156 @@ void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCo
}
}
+void SwTextBoxHelper::set(SwFrameFormat* pShapeFormat, SdrObject* pObj,
+ uno::Reference<text::XTextFrame> xNew)
+{
+ // Do not set invalid data
+ assert(pShapeFormat && pObj && xNew);
+ // Firstly find the format of the new textbox.
+ SwFrameFormat* pFormat = nullptr;
+ if (auto pTextFrame = dynamic_cast<SwXTextFrame*>(xNew.get()))
+ pFormat = pTextFrame->GetFrameFormat();
+ if (!pFormat)
+ return;
+ std::vector<std::pair<beans::Property, uno::Any>> aOldProps;
+ // If there is a format, check if the shape already has a textbox assigned to.
+ if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormat())
+ {
+ // If it has a texbox, destroy it.
+ if (pTextBoxNode->GetTextBox(pObj))
+ {
+ auto xOldFrame
+ = pObj->getUnoShape()->queryInterface(cppu::UnoType<text::XTextRange>::get());
+ if (xOldFrame.hasValue())
+ {
+ uno::Reference<beans::XPropertySet> xOldprops(xOldFrame, uno::UNO_QUERY);
+ uno::Reference<beans::XPropertyState> xOldPropStates(xOldFrame, uno::UNO_QUERY);
+ for (auto& rProp : xOldprops->getPropertySetInfo()->getProperties())
+ {
+ try
+ {
+ if (xOldPropStates->getPropertyState(rProp.Name)
+ == beans::PropertyState::PropertyState_DIRECT_VALUE)
+ aOldProps.push_back(
+ std::pair(rProp, xOldprops->getPropertyValue(rProp.Name)));
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+ destroy(pShapeFormat, pObj);
+ }
+ // And set the new one.
+ pTextBoxNode->AddTextBox(pObj, pFormat);
+ pFormat->SetOtherTextBoxFormat(pTextBoxNode);
+ }
+ else
+ {
+ // If the shape do not have a texbox node and textbox,
+ // create that for the shape.
+ auto* pTextBox = new SwTextBoxNode(pShapeFormat);
+ pTextBox->AddTextBox(pObj, pFormat);
+ pShapeFormat->SetOtherTextBoxFormat(pTextBox);
+ pFormat->SetOtherTextBoxFormat(pTextBox);
+ }
+
+ // Initialize its properties
+ uno::Reference<beans::XPropertySet> xPropertySet(xNew, uno::UNO_QUERY);
+ uno::Any aEmptyBorder = uno::makeAny(table::BorderLine2());
+ xPropertySet->setPropertyValue(UNO_NAME_TOP_BORDER, aEmptyBorder);
+ xPropertySet->setPropertyValue(UNO_NAME_BOTTOM_BORDER, aEmptyBorder);
+ xPropertySet->setPropertyValue(UNO_NAME_LEFT_BORDER, aEmptyBorder);
+ xPropertySet->setPropertyValue(UNO_NAME_RIGHT_BORDER, aEmptyBorder);
+ xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::makeAny(sal_Int32(100)));
+ xPropertySet->setPropertyValue(UNO_NAME_SIZE_TYPE, uno::makeAny(text::SizeType::FIX));
+ xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
+ // Add a new name to it
+ uno::Reference<container::XNamed> xNamed(xNew, uno::UNO_QUERY);
+ xNamed->setName(pShapeFormat->GetDoc()->GetUniqueFrameName());
+ // And sync. properties.
+ uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
+ syncProperty(pShapeFormat, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::makeAny(xShape->getSize()),
+ pObj);
+
+ uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
+ syncProperty(pShapeFormat, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
+ xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE), pObj);
+ syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
+ xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT), pObj);
+ syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
+ xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION), pObj);
+ syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
+ xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT), pObj);
+ syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
+ xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION), pObj);
+ syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
+ xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION), pObj);
+ syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
+ xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION), pObj);
+ syncProperty(pShapeFormat, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
+ xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT), pObj);
+
+ drawing::TextVerticalAdjust aVertAdj = drawing::TextVerticalAdjust_CENTER;
+
+ if ((uno::Reference<beans::XPropertyState>(xShape, uno::UNO_QUERY_THROW))
+ ->getPropertyState(UNO_NAME_TEXT_VERT_ADJUST)
+ != beans::PropertyState::PropertyState_DEFAULT_VALUE)
+ {
+ aVertAdj = xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST)
+ .get<drawing::TextVerticalAdjust>();
+ }
+
+ xPropertySet->setPropertyValue(UNO_NAME_TEXT_VERT_ADJUST, uno::makeAny(aVertAdj));
+ text::WritingMode eMode;
+ if (xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE) >>= eMode)
+ syncProperty(pShapeFormat, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)), pObj);
+ if (aOldProps.size())
+ {
+ for (auto& rProp : aOldProps)
+ {
+ try
+ {
+ xPropertySet->setPropertyValue(rProp.first.Name, rProp.second);
+ }
+ catch (...)
+ {
+ }
+ }
+ }
+ if (pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
+ && pFormat->GetAnchor().GetPageNum() == 0)
+ {
+ pFormat->SetFormatAttr(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, 1));
+ }
+ // Do sync for the new textframe.
+ handleTextBoxGroup(pShapeFormat, GroupTextBoxActionType::POSITION_SIZE_AND_ANCHOR_CHANGE);
+}
+
void SwTextBoxHelper::destroy(const SwFrameFormat* pShape, const SdrObject* pObject)
{
+ assert(pShape && pObject);
+
// If a TextBox was enabled previously
- auto pTextBox = pShape->GetOtherTextBoxFormat();
- if (pTextBox && pTextBox->IsTextBoxActive(pObject))
+ auto pTextBoxNode = pShape->GetOtherTextBoxFormat();
+ if (!pTextBoxNode)
+ {
+ SAL_WARN("sw.core", "SwTextBoxHelper::destroy: No TextBoxNode!");
+ return;
+ }
+
+ if (auto pFormat = pTextBoxNode->GetTextBox(pObject))
{
// Unlink the TextBox's text range from the original shape.
- pTextBox->SetTextBoxInactive(pObject);
+ pTextBoxNode->DelTextBox(pObject);
+ pFormat->SetOtherTextBoxFormat(nullptr);
// Delete the associated TextFrame.
- pTextBox->DelTextBox(pObject);
+ pFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(pFormat);
+ return;
}
+
+ SAL_WARN("sw.core", "SwTextBoxHelper::destroy: No TextBox to destroy!");
}
bool SwTextBoxHelper::isTextBox(const SwFrameFormat* pFormat, sal_uInt16 nType,
@@ -233,6 +372,9 @@ bool SwTextBoxHelper::isTextBox(const SwFrameFormat* pFormat, sal_uInt16 nType,
if (!pTextBox)
return false;
+ if (!pTextBox->GetTextBoxCount())
+ return false;
+
if (nType == RES_DRAWFRMFMT)
{
if (pObject)
@@ -333,6 +475,12 @@ sal_Int32 SwTextBoxHelper::getOrdNum(const SdrObject* pObject)
void SwTextBoxHelper::getShapeWrapThrough(const SwFrameFormat* pTextBox, bool& rWrapThrough)
{
+ if (!pTextBox->GetOtherTextBoxFormat())
+ {
+ SAL_WARN("sw.core", "SwTextBoxHelper::getShapeWrapThrough: No TextBoxNode!");
+ return;
+ }
+
SwFrameFormat* pShape = SwTextBoxHelper::getOtherTextBoxFormat(pTextBox, RES_FLYFRMFMT);
if (pShape)
rWrapThrough = pShape->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
@@ -367,7 +515,8 @@ SwFrameFormat* SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference<drawing::XS
return nullptr;
SwFrameFormat* pFormat = pShape->GetFrameFormat();
- return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT);
+ return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT,
+ SdrObject::getSdrObjectFromXShape(xShape));
}
uno::Reference<text::XTextFrame>
@@ -388,33 +537,49 @@ SwTextBoxHelper::getUnoTextFrame(uno::Reference<drawing::XShape> const& xShape)
return {};
}
-template <typename T> static void lcl_queryInterface(const SwFrameFormat* pShape, uno::Any& rAny)
+uno::Any SwTextBoxHelper::queryInterface(const SwFrameFormat* pShape, const uno::Type& rType,
+ SdrObject* pObj)
{
- if (SwFrameFormat* pFormat = SwTextBoxHelper::getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+ if (!pShape)
+ return {};
+
+ if (!pShape->GetOtherTextBoxFormat())
{
- uno::Reference<T> const xInterface(
- SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
- rAny <<= xInterface;
+ SAL_WARN("sw.core", "SwTextBoxHelper::queryInterface: No TextBoxNode!");
+ return {};
+ }
+
+ SwFrameFormat* pFormat = SwTextBoxHelper::getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
+
+ if (!pFormat)
+ {
+ SAL_WARN("sw.core", "SwTextBoxHelper::queryInterface: No TextBox!");
+ return {};
}
-}
-uno::Any SwTextBoxHelper::queryInterface(const SwFrameFormat* pShape, const uno::Type& rType)
-{
uno::Any aRet;
if (rType == cppu::UnoType<css::text::XTextAppend>::get())
{
- lcl_queryInterface<text::XTextAppend>(pShape, aRet);
+ uno::Reference<css::text::XTextAppend> const xInterface(
+ SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY_THROW);
+ aRet <<= xInterface;
}
else if (rType == cppu::UnoType<css::text::XText>::get())
{
- lcl_queryInterface<text::XText>(pShape, aRet);
+ uno::Reference<css::text::XText> const xInterface(
+ SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY_THROW);
+ aRet <<= xInterface;
}
else if (rType == cppu::UnoType<css::text::XTextRange>::get())
{
- lcl_queryInterface<text::XTextRange>(pShape, aRet);
+ uno::Reference<css::text::XTextRange> const xInterface(
+ SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY_THROW);
+ aRet <<= xInterface;
}
+ assert(aRet.hasValue());
+
return aRet;
}
@@ -908,6 +1073,51 @@ void SwTextBoxHelper::restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrame
}
}
+void SwTextBoxHelper::handleTextBoxGroup(SwFrameFormat* pGroupShapeFormat,
+ GroupTextBoxActionType eActionType,
+ SdrObject* pGroupObject)
+{
+ if (!pGroupShapeFormat)
+ return;
+
+ SdrObject* pMasterObj = nullptr;
+ if (!pGroupObject)
+ pMasterObj = pGroupShapeFormat->FindRealSdrObject();
+ else
+ pMasterObj = pGroupObject;
+
+ if (auto pChildrenObjs = pMasterObj->getChildrenOfSdrObject())
+ {
+ for (size_t i = 0; i < pChildrenObjs->GetObjCount(); ++i)
+ handleTextBoxGroup(pGroupShapeFormat, eActionType, pChildrenObjs->GetObj(i));
+ }
+ else
+ {
+ switch (eActionType)
+ {
+ case GroupTextBoxActionType::POSITION_SIZE_AND_ANCHOR_CHANGE:
+ {
+ changeAnchor(pGroupShapeFormat, pMasterObj);
+ setTextBoxSize(pGroupShapeFormat, pMasterObj);
+ break;
+ }
+ case GroupTextBoxActionType::Z_ORDER_CHANGE:
+ {
+ DoTextBoxZOrderCorrection(pGroupShapeFormat, pMasterObj);
+ break;
+ }
+ case GroupTextBoxActionType::DELETE:
+ {
+ destroy(pGroupShapeFormat, pMasterObj);
+ break;
+ }
+ default:
+ SAL_WARN("sw.core", "SwTextBoxHelper::handleTextBoxGroup: Unknown Action!");
+ break;
+ }
+ }
+}
+
text::TextContentAnchorType SwTextBoxHelper::mapAnchorType(const RndStdIds& rAnchorID)
{
text::TextContentAnchorType aAnchorType;
@@ -1066,7 +1276,6 @@ void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat& rShape, SfxItemSet const&
if (aTextBoxSet.Count())
pFormat->SetFormatAttr(aTextBoxSet);
- //pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
DoTextBoxZOrderCorrection(&rShape, pObj);
}
@@ -1114,12 +1323,11 @@ void SwTextBoxHelper::updateTextBoxMargin(SdrObject* pObj)
DoTextBoxZOrderCorrection(pParentFormat, pObj);
}
-bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape)
+bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape, SdrObject* pObj)
{
- OUString sErrMsg;
- if (isTextBoxShapeHasValidTextFrame(pShape))
+ if (isTextBoxShapeHasValidTextFrame(pShape, pObj))
{
- if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+ if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
{
::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
if (auto xFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat))
@@ -1132,53 +1340,77 @@ bool SwTextBoxHelper::setWrapThrough(SwFrameFormat* pShape)
}
catch (uno::Exception& e)
{
- sErrMsg = "Exception caught: " + e.Message;
+ SAL_WARN("sw.core",
+ "SwTextBoxHelper::setWrapThrough: Exception caught: " << e.Message);
}
else
- sErrMsg = "No XTextFrame!";
+ SAL_WARN("sw.core", "SwTextBoxHelper::setWrapThrough: No XTextFrame!");
}
else
- sErrMsg = "No Other TextBox Format!";
+ SAL_WARN("sw.core", "SwTextBoxHelper::setWrapThrough: No Other TextBox Format!");
}
else
- sErrMsg = "Not a Valid TextBox object!";
+ SAL_WARN("sw.core", "SwTextBoxHelper::setWrapThrough: Not a Valid TextBox object!");
- SAL_WARN("sw.core", "SwTextBoxHelper::setWrapThrough: " << sErrMsg);
return false;
}
bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape, SdrObject* pObj)
{
+ // Get the desired textbox from the shape
if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
{
+ // Collect the anchors
const SwFormatAnchor& rOldAnch = pFormat->GetAnchor();
const SwFormatAnchor& rNewAnch = pShape->GetAnchor();
+ // Collect the anchor positions (in the text)
const auto pOldCnt = rOldAnch.GetContentAnchor();
const auto pNewCnt = rNewAnch.GetContentAnchor();
+ // Collect the relative anchor points
const uno::Any aShapeHorRelOrient
= uno::makeAny(pShape->GetHoriOrient().GetRelationOrient());
+ const uno::Any aShapeVertRelOrient
+ = uno::makeAny(pShape->GetVertOrient().GetRelationOrient());
- if (isAnchorTypeDifferent(pShape) || (pObj && pObj != pShape->FindRealSdrObject()))
+ // Get the new page number. If this is 0 incrase it to 1!
+ // (0 is invalid page)
+ const sal_uInt16 nPageNum = rNewAnch.GetPageNum() ? rNewAnch.GetPageNum() : 1;
+
+ // If anchor is different, sync needed
+ if (isAnchorTypeDifferent(pShape, pObj) || (pObj && pObj != pShape->FindRealSdrObject()))
{
try
{
+ // Disable undo for the sync
::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
+ // Get the properties of the textframe
uno::Reference<beans::XPropertySet> const xPropertySet(
SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
+
+ // Anchoring situations:
+
+ // First:
+ // the old anchor is in the text (namely inline or at_char/para) and,
+ // the new one will be at_page
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_VERT_ORIENT_RELATION,
+ aShapeVertRelOrient);
xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
- xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
- uno::Any(rNewAnch.GetPageNum()));
+ xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO, uno::Any(nPageNum));
}
+ // Second:
+ // The reverse of the previous one: Old one at page, new at-text.
else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE && pNewCnt)
{
+ // If the new at-text anchor is inline, the textbox can not be inline too,
+ // so change it to at_char and make its position according to the shape.
if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
{
uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
@@ -1191,17 +1423,28 @@ bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape, SdrObject* pObj)
aPos.SetAnchor(pNewCnt);
pFormat->SetFormatAttr(aPos);
}
+ // Else, copy the anchor of the shape to the frame. Correct pagenum if needed.
else
{
uno::Any aValue(mapAnchorType(rNewAnch.GetAnchorId()));
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
aShapeHorRelOrient);
+ xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION,
+ aShapeVertRelOrient);
xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
+ if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE
+ && !rNewAnch.GetPageNum())
+ xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
+ uno::Any(sal_uInt16(1)));
+
pFormat->SetFormatAttr(rNewAnch);
}
}
+ // Third:
+ // At-text anchor changes to at-text. (Only the type changes)
else
{
+ // Special treatment for inline case.
if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
{
uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
@@ -1214,10 +1457,19 @@ bool SwTextBoxHelper::changeAnchor(SwFrameFormat* pShape, SdrObject* pObj)
aPos.SetAnchor(pNewCnt);
pFormat->SetFormatAttr(aPos);
}
+ // Else, just copy the anchor.
else
{
xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
aShapeHorRelOrient);
+ xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION,
+ aShapeVertRelOrient);
+
+ if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE
+ && !rNewAnch.GetPageNum())
+ xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
+ uno::Any(sal_uInt16(1)));
+
pFormat->SetFormatAttr(pShape->GetAnchor());
}
}
@@ -1253,6 +1505,12 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb
SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
aNewVOri.SetPos(aRect.Top() + pShape->GetVertOrient().GetPos());
+ if (bIsGroupObj)
+ {
+ aNewHOri.SetPos(aNewHOri.GetPos() + pObj->GetRelativePos().getX());
+ aNewVOri.SetPos(aNewVOri.GetPos() + pObj->GetRelativePos().getY());
+ }
+
// tdf#140598: Do not apply wrong rectangle position.
if (aRect.TopLeft() != Point(0, 0))
{
@@ -1272,11 +1530,11 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb
{
SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
aNewHOri.SetPos(
- (bIsGroupObj && pObj ? pObj->GetRelativePos().getX() : aNewHOri.GetPos())
+ ((bIsGroupObj && pObj) ? pObj->GetRelativePos().getX() : aNewHOri.GetPos())
+ aRect.Left());
SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
aNewVOri.SetPos(
- (bIsGroupObj && pObj ? pObj->GetRelativePos().getY() : aNewVOri.GetPos())
+ ((bIsGroupObj && pObj) ? pObj->GetRelativePos().getY() : aNewVOri.GetPos())
+ aRect.Top());
pFormat->SetFormatAttr(aNewHOri);
@@ -1291,12 +1549,31 @@ bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat* pShape, SdrObject* pOb
return false;
}
-std::optional<bool> SwTextBoxHelper::isAnchorTypeDifferent(const SwFrameFormat* pShape)
+bool SwTextBoxHelper::setTextBoxSize(const SwFrameFormat* pShape, SdrObject* pObj)
+{
+ if (!pShape || !pObj)
+ return false;
+
+ if (auto pTBox = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
+ {
+ const auto& rSize = getTextRectangle(pObj, false).GetSize();
+ if (!rSize.IsEmpty())
+ {
+ SwFormatFrameSize aSizeFormatItem = pTBox->GetFrameSize();
+ aSizeFormatItem.SetSize(rSize);
+ return pTBox->SetFormatAttr(aSizeFormatItem);
+ }
+ }
+ return false;
+}
+
+std::optional<bool> SwTextBoxHelper::isAnchorTypeDifferent(const SwFrameFormat* pShape,
+ SdrObject* pObj)
{
std::optional<bool> bRet;
- if (isTextBoxShapeHasValidTextFrame(pShape))
+ if (isTextBoxShapeHasValidTextFrame(pShape, pObj))
{
- if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+ if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
{
if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
bRet = (pFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_CHAR
@@ -1308,20 +1585,21 @@ std::optional<bool> SwTextBoxHelper::isAnchorTypeDifferent(const SwFrameFormat*
return bRet;
}
-bool SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(const SwFrameFormat* pShape)
+bool SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(const SwFrameFormat* pShape, SdrObject* pObj)
{
if (pShape && pShape->Which() == RES_DRAWFRMFMT)
- if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
+ if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
if (pFormat && pFormat->Which() == RES_FLYFRMFMT)
return true;
else
- SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: "
- "Shape does not have valid textframe!");
+ SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: Shape does "
+ "not have valid textframe!");
else
- SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: "
- "Shape does not have associated frame!");
+ SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: Shape does not "
+ "have associated frame!");
else
- SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: Not valid shape!");
+ SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: No valid shape");
+
return false;
}
@@ -1329,9 +1607,6 @@ bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape, const Sdr
{
// TODO: do this with group shape textboxes.
SdrObject* pShpObj = nullptr;
- //if (pObj)
- // pShpObj = pObj;
- //else
pShpObj = pShape->FindRealSdrObject();
if (pShpObj)
@@ -1365,39 +1640,53 @@ bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat* pShape, const Sdr
break;
++nIterator;
if (nIterator > 300)
+ {
break; // Do not run to infinity
+ }
}
pPage->RecalcObjOrdNums();
return true; // Success
}
- SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
- "No Valid Draw model for SdrObject for the shape!");
+ SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): No Valid Draw model "
+ "for SdrObject for the shape!");
}
- SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
- "No Valid SdrObject for the frame!");
+ SAL_WARN("sw.core",
+ "SwTextBoxHelper::DoTextBoxZOrderCorrection(): No Valid SdrObject for the frame!");
}
- SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
- "No Valid SdrObject for the shape!");
+ SAL_WARN("sw.core",
+ "SwTextBoxHelper::DoTextBoxZOrderCorrection(): No Valid SdrObject for the shape!");
return false;
}
+// SwTextBoxNode class:
+
SwTextBoxNode::SwTextBoxNode(SwFrameFormat* pOwnerShape)
{
assert(pOwnerShape);
assert(pOwnerShape->Which() == RES_DRAWFRMFMT);
m_pOwnerShapeFormat = pOwnerShape;
- if (!m_pTextBoxes.empty())
- m_pTextBoxes.clear();
+ if (!m_pTextBoxTable.empty())
+ m_pTextBoxTable.clear();
}
SwTextBoxNode::~SwTextBoxNode()
{
- m_pTextBoxes.clear();
+ if (m_pTextBoxTable.size())
+ {
+ for (auto& rTextBox : m_pTextBoxTable)
+ {
+ rTextBox.second->SetOtherTextBoxFormat(nullptr);
+ rTextBox.second = nullptr;
+ }
+ m_pTextBoxTable.clear();
+ }
if (m_pOwnerShapeFormat && m_pOwnerShapeFormat->GetOtherTextBoxFormat())
m_pOwnerShapeFormat->SetOtherTextBoxFormat(nullptr);
+
+ m_pOwnerShapeFormat = nullptr;
}
void SwTextBoxNode::AddTextBox(SdrObject* pDrawObject, SwFrameFormat* pNewTextBox)
@@ -1407,102 +1696,63 @@ void SwTextBoxNode::AddTextBox(SdrObject* pDrawObject, SwFrameFormat* pNewTextBo
assert(pDrawObject);
- SwTextBoxElement aElem;
- aElem.m_bIsActive = true;
- aElem.m_pDrawObject = pDrawObject;
- aElem.m_pTextBoxFormat = pNewTextBox;
+ if (!m_pTextBoxTable.count(pDrawObject))
+ {
+ m_pTextBoxTable.emplace(pDrawObject, pNewTextBox);
+ }
+ else
+ {
+ m_pTextBoxTable[pDrawObject] = pNewTextBox;
+ }
auto pSwFlyDraw = dynamic_cast<SwFlyDrawObj*>(pDrawObject);
if (pSwFlyDraw)
{
pSwFlyDraw->SetTextBox(true);
}
- m_pTextBoxes.push_back(aElem);
}
void SwTextBoxNode::DelTextBox(const SdrObject* pDrawObject)
{
assert(pDrawObject);
- if (m_pTextBoxes.empty())
- return;
-
- for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end();)
- {
- if (it->m_pDrawObject == pDrawObject)
- {
- m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
- it->m_pTextBoxFormat);
- it = m_pTextBoxes.erase(it);
- break;
- }
- ++it;
- }
-}
+ auto pObj = const_cast<SdrObject*>(pDrawObject);
-SwFrameFormat* SwTextBoxNode::GetTextBox(const SdrObject* pDrawObject) const
-{
- assert(pDrawObject);
- if (!m_pTextBoxes.empty())
- {
- for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
- {
- if (it->m_pDrawObject == pDrawObject)
- {
- return it->m_pTextBoxFormat;
- }
- }
- }
- return nullptr;
-}
-
-bool SwTextBoxNode::IsTextBoxActive(const SdrObject* pDrawObject) const
-{
- assert(pDrawObject);
+ if (m_pTextBoxTable.empty())
+ return;
- if (!m_pTextBoxes.empty())
+ if (m_pTextBoxTable.count(pObj))
{
- for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
- {
- if (it->m_pDrawObject == pDrawObject)
- {
- return it->m_bIsActive;
- }
- }
+ m_pTextBoxTable[pObj]->SetOtherTextBoxFormat(nullptr);
+ m_pTextBoxTable.erase(pObj);
}
- return false;
}
-void SwTextBoxNode::SetTextBoxActive(const SdrObject* pDrawObject)
+void SwTextBoxNode::DelTextBox(SwFrameFormat* pTextBox)
{
- assert(pDrawObject);
+ if (!pTextBox || m_pTextBoxTable.empty())
+ return;
- if (!m_pTextBoxes.empty())
- {
- for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
+ for (auto it = m_pTextBoxTable.begin(); it != m_pTextBoxTable.end(); ++it)
+ if (it->second == pTextBox)
{
- if (it->m_pDrawObject == pDrawObject)
- {
- it->m_bIsActive = true;
- }
+ it->second->SetOtherTextBoxFormat(nullptr);
+ m_pTextBoxTable.erase(it->first);
+ break;
}
- }
}
-void SwTextBoxNode::SetTextBoxInactive(const SdrObject* pDrawObject)
+SwFrameFormat* SwTextBoxNode::GetTextBox(const SdrObject* pDrawObject) const
{
assert(pDrawObject);
-
- if (!m_pTextBoxes.empty())
+ if (!m_pTextBoxTable.empty())
{
- for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
+ if (m_pTextBoxTable.count(pDrawObject))
{
- if (it->m_pDrawObject == pDrawObject)
- {
- it->m_bIsActive = false;
- }
+ return m_pTextBoxTable.at(pDrawObject);
}
}
+ return nullptr;
}
-bool SwTextBoxNode::IsGroupTextBox() const { return m_pTextBoxes.size() > 1; }
+bool SwTextBoxNode::IsGroupTextBoxShape() const { return m_pTextBoxTable.size() > 1; }
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index cb9618c44e8b..f8aefc6acdd6 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1250,10 +1250,9 @@ void SwDrawContact::Changed_( const SdrObject& rObj,
// use geometry of drawing object
aObjRect = pGroupObj->GetSnapRect();
- for (size_t i = 0; i < pGroupObj->getChildrenOfSdrObject()->GetObjCount(); ++i )
- {
- SwTextBoxHelper::doTextBoxPositioning(GetFormat(), pGroupObj->getChildrenOfSdrObject()->GetObj(i));
- }
+ SwTextBoxHelper::handleTextBoxGroup(
+ GetFormat(),
+ SwTextBoxHelper::GroupTextBoxActionType::POSITION_SIZE_AND_ANCHOR_CHANGE);
}
SwTwips nXPosDiff(0);
@@ -1370,7 +1369,9 @@ void SwDrawContact::Changed_( const SdrObject& rObj,
aSet.Put(aSyncSet);
aSet.Put(pSdrObj->GetMergedItem(RES_FRM_SIZE));
SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSet, pSdrObj);
- SwTextBoxHelper::changeAnchor(GetFormat(), pSdrObj);
+ SwTextBoxHelper::handleTextBoxGroup(
+ GetFormat(),
+ SwTextBoxHelper::GroupTextBoxActionType::POSITION_SIZE_AND_ANCHOR_CHANGE);
}
else
SwTextBoxHelper::syncFlyFrameAttr(*GetFormat(), aSyncSet, GetFormat()->FindRealSdrObject());
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index 510addf10a9c..6f7251698af8 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -967,12 +967,10 @@ void SwDrawView::DeleteMarked()
SdrObject *pObject = rMarkList.GetMark(i)->GetMarkedSdrObj();
SwContact* pContact = GetUserCall(pObject);
SwFrameFormat* pFormat = pContact->GetFormat();
- if (auto pChildren = pObject->getChildrenOfSdrObject())
+ if (pObject->getChildrenOfSdrObject())
{
- for (size_t it = 0; it < pChildren->GetObjCount(); ++it)
- if (SwFrameFormat* pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(
- pFormat, RES_DRAWFRMFMT, pChildren->GetObj(it)))
- aTextBoxesToDelete.push_back(pTextBox);
+ SwTextBoxHelper::handleTextBoxGroup(pFormat,
+ SwTextBoxHelper::GroupTextBoxActionType::DELETE);
}
else
if (SwFrameFormat* pTextBox = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
diff --git a/sw/source/core/frmedt/feshview.cxx b/sw/source/core/frmedt/feshview.cxx
index 1e3c8f2ff150..893926456d10 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -1064,7 +1064,7 @@ void SwFEShell::SelectionToTop( bool bTop )
if (auto pFormat = FindFrameFormat(pObj))
{
// If it has not textframe skip...
- if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat))
+ if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat, pObj))
continue;
// If it has a textframe so it is a textbox, get its page
if (auto pDrwModel
@@ -1133,7 +1133,7 @@ void SwFEShell::SelectionToBottom( bool bBottom )
if (auto pFormat = FindFrameFormat(pObj))
{
// If the shape has not textframes skip.
- if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat))
+ if (!SwTextBoxHelper::isTextBoxShapeHasValidTextFrame(pFormat, pObj))
continue;
// If has, move the shape to correct level with...
if (auto pDrwModel
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index 4791fda80169..9a2fb39ba680 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -2550,12 +2550,11 @@ SwFrameFormat::~SwFrameFormat()
if( nullptr == m_pOtherTextBoxFormat )
return;
- auto pObj = FindRealSdrObject();
- if (Which() == RES_FLYFRMFMT && pObj)
+ if (Which() == RES_FLYFRMFMT)
{
// This is a fly-frame-format just delete this
// textbox entry from the draw-frame-format.
- m_pOtherTextBoxFormat->DelTextBox(pObj);
+ m_pOtherTextBoxFormat->DelTextBox(this);
}
if (Which() == RES_DRAWFRMFMT)
diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx
index 4d04857e7199..cbb0266c0af6 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -963,7 +963,13 @@ SwXShape::~SwXShape()
uno::Any SwXShape::queryInterface( const uno::Type& aType )
{
- uno::Any aRet = SwTextBoxHelper::queryInterface(GetFrameFormat(), aType);
+ uno::Any aRet;
+ if (aType == cppu::UnoType<text::XText>::get()
+ || aType == cppu::UnoType<text::XTextAppend>::get()
+ || aType == cppu::UnoType<text::XTextRange>::get())
+ aRet = SwTextBoxHelper::queryInterface(GetFrameFormat(), aType,
+ SdrObject::getSdrObjectFromXShape(mxShape));
+
if (aRet.hasValue())
return aRet;
@@ -1151,18 +1157,28 @@ void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& a
}
else if (pEntry->nWID == FN_TEXT_BOX)
{
- bool bValue(false);
- aValue >>= bValue;
- if (bValue)
- SwTextBoxHelper::create(pFormat, GetSvxShape()->GetSdrObject());
- else
- SwTextBoxHelper::destroy(pFormat, GetSvxShape()->GetSdrObject());
-
+ if (pEntry->nMemberId == MID_TEXTBOX)
+ {
+ bool bValue(false);
+ aValue >>= bValue;
+ if (bValue)
+ SwTextBoxHelper::create(pFormat, GetSvxShape()->GetSdrObject());
+ else
+ SwTextBoxHelper::destroy(pFormat, GetSvxShape()->GetSdrObject());
+ }
+ else if (pEntry->nMemberId == MID_TEXTBOX_CONTENT)
+ {
+ if (aValue.getValueType() == cppu::UnoType<uno::Reference<text::XTextFrame>>::get())
+ SwTextBoxHelper::set(pFormat, GetSvxShape()->GetSdrObject(),
+ aValue.get<uno::Reference<text::XTextFrame>>());
+ else
+ SAL_WARN( "sw.uno", "This is not a TextFrame!" );
+ }
}
else if (pEntry->nWID == RES_CHAIN)
{
if (pEntry->nMemberId == MID_CHAIN_NEXTNAME || pEntry->nMemberId == MID_CHAIN_PREVNAME)
- SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue);
+ SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue, SdrObject::getSdrObjectFromXShape(mxShape));
}
// #i28749#
else if ( FN_SHAPE_POSITION_LAYOUT_DIR == pEntry->nWID )
@@ -1333,7 +1349,7 @@ void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& a
pFormat->SetFormatAttr(aSet);
}
// We have a pFormat and a pEntry as well: try to sync TextBox property.
- SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue);
+ SwTextBoxHelper::syncProperty(pFormat, pEntry->nWID, pEntry->nMemberId, aValue, SdrObject::getSdrObjectFromXShape(mxShape));
}
else
{
@@ -1423,7 +1439,7 @@ void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& a
if (pFormat)
{
// We have a pFormat (but no pEntry): try to sync TextBox property.
- SwTextBoxHelper::syncProperty(pFormat, rPropertyName, aValue);
+ SwTextBoxHelper::syncProperty(pFormat, rPropertyName, aValue, SdrObject::getSdrObjectFromXShape(mxShape));
}
// #i31698# - restore object position, if caption point is set.
@@ -1504,12 +1520,26 @@ uno::Any SwXShape::getPropertyValue(const OUString& rPropertyName)
}
else if (pEntry->nWID == FN_TEXT_BOX)
{
- auto pSvxShape = GetSvxShape();
- bool bValue = SwTextBoxHelper::isTextBox(
- pFormat, RES_DRAWFRMFMT,
- ((pSvxShape && pSvxShape->GetSdrObject()) ? pSvxShape->GetSdrObject()
- : pFormat->FindRealSdrObject()));
- aRet <<= bValue;
+ if (pEntry->nMemberId == MID_TEXTBOX)
+ {
+ auto pSvxShape = GetSvxShape();
+ bool bValue = SwTextBoxHelper::isTextBox(
+ pFormat, RES_DRAWFRMFMT,
+ ((pSvxShape && pSvxShape->GetSdrObject()) ? pSvxShape->GetSdrObject()
+ : pFormat->FindRealSdrObject()));
+ aRet <<= bValue;
+ }
+ else if (pEntry->nMemberId == MID_TEXTBOX_CONTENT)
+ {
+ auto pObj = SdrObject::getSdrObjectFromXShape(mxShape);
+ auto xRange = SwTextBoxHelper::queryInterface(
+ pFormat, cppu::UnoType<text::XText>::get(),
+ pObj ? pObj : pFormat->FindRealSdrObject());
+
+ uno::Reference<text::XTextFrame> xFrame(xRange, uno::UNO_QUERY);
+ if (xFrame.is())
+ aRet <<= xFrame;
+ }
}
else if (pEntry->nWID == RES_CHAIN)
{
@@ -1790,7 +1820,7 @@ uno::Sequence< beans::PropertyState > SwXShape::getPropertyStates(
else if (pEntry->nWID == FN_TEXT_BOX)
{
// The TextBox property is set, if we can find a textbox for this shape.
- if (pFormat && SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
+ if (pFormat && SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT, SdrObject::getSdrObjectFromXShape(mxShape)))
pRet[nProperty] = beans::PropertyState_DIRECT_VALUE;
else
pRet[nProperty] = beans::PropertyState_DEFAULT_VALUE;
diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx
index 4e373b6c511e..3b9f0d7d8944 100644
--- a/sw/source/core/unocore/unomap.cxx
+++ b/sw/source/core/unocore/unomap.cxx
@@ -291,7 +291,8 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
{ u"" UNO_NAME_RELATIVE_HEIGHT_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_HEIGHT_RELATION },
{ u"" UNO_NAME_RELATIVE_WIDTH, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH },
{ u"" UNO_NAME_RELATIVE_WIDTH_RELATION, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, MID_FRMSIZE_REL_WIDTH_RELATION },
- { u"" UNO_NAME_TEXT_BOX, FN_TEXT_BOX, cppu::UnoType<bool>::get(), PROPERTY_NONE, 0},
+ { u"" UNO_NAME_TEXT_BOX, FN_TEXT_BOX, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TEXTBOX},
+ { u"" UNO_NAME_TEXT_BOX_CONTENT, FN_TEXT_BOX, cppu::UnoType<text::XTextFrame>::get(), PROPERTY_NONE, MID_TEXTBOX_CONTENT},
{ u"" UNO_NAME_CHAIN_NEXT_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_NEXTNAME},
{ u"" UNO_NAME_CHAIN_PREV_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_PREVNAME},
{ u"" UNO_NAME_CHAIN_NAME, RES_CHAIN, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID ,MID_CHAIN_NAME },
diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx
index 9a186b05d280..63b4f2d5e209 100644
--- a/sw/source/core/unocore/unomap1.cxx
+++ b/sw/source/core/unocore/unomap1.cxx
@@ -786,6 +786,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetFramePropertyMap()
{ u"" UNO_NAME_SIZE_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_SIZE_TYPE },
{ u"" UNO_NAME_WIDTH_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH_TYPE },
{ u"" UNO_NAME_WRITING_MODE, RES_FRAMEDIR, cppu::UnoType<sal_Int16>::get(), PROPERTY_NONE, 0 },
+ //{ u"" UNO_NAME_TEXT_BOX, FN_TEXT_BOX, cppu::UnoType<bool>::get(), PROPERTY_NONE, MID_TEXTBOX},
// added FillProperties for SW, same as FILL_PROPERTIES in svx
// but need own defines in Writer due to later association of strings