1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <textboxhelper.hxx>
11 #include <fmtcntnt.hxx>
12 #include <fmtanchr.hxx>
13 #include <fmtcnct.hxx>
14 #include <fmtornt.hxx>
15 #include <fmtfsize.hxx>
17 #include <IDocumentLayoutAccess.hxx>
18 #include <IDocumentState.hxx>
20 #include <unocoll.hxx>
21 #include <unoframe.hxx>
22 #include <unodraw.hxx>
23 #include <unotextrange.hxx>
26 #include <unoprnms.hxx>
28 #include <fmtsrnd.hxx>
29 #include <fmtfollowtextflow.hxx>
31 #include <frameformats.hxx>
32 #include <dflyobj.hxx>
33 #include <swtable.hxx>
35 #include <editeng/unoprnms.hxx>
36 #include <editeng/memberids.h>
37 #include <svx/svdoashp.hxx>
38 #include <svx/svdpage.hxx>
39 #include <svl/itemiter.hxx>
40 #include <comphelper/sequenceashashmap.hxx>
41 #include <sal/log.hxx>
42 #include <tools/UnitConversion.hxx>
43 #include <svx/swframetypes.hxx>
44 #include <drawdoc.hxx>
45 #include <IDocumentUndoRedo.hxx>
46 #include <IDocumentDrawModelAccess.hxx>
49 #include <com/sun/star/document/XActionLockable.hpp>
50 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
51 #include <com/sun/star/text/SizeType.hpp>
52 #include <com/sun/star/text/WrapTextMode.hpp>
53 #include <com/sun/star/text/XTextDocument.hpp>
54 #include <com/sun/star/text/XTextFrame.hpp>
55 #include <com/sun/star/table/BorderLine2.hpp>
56 #include <com/sun/star/text/WritingMode.hpp>
57 #include <com/sun/star/text/WritingMode2.hpp>
58 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
59 #include <com/sun/star/style/ParagraphAdjust.hpp>
61 using namespace com::sun::star
;
63 void SwTextBoxHelper::create(SwFrameFormat
* pShape
, SdrObject
* pObject
, bool bCopyText
)
68 // If TextBox wasn't enabled previously
69 if (pShape
->GetOtherTextBoxFormats() && pShape
->GetOtherTextBoxFormats()->GetTextBox(pObject
))
72 // Store the current text content of the shape
73 OUString sCopyableText
;
79 uno::Reference
<text::XText
> xSrcCnt(pObject
->getWeakUnoShape().get(), uno::UNO_QUERY
);
80 auto xCur
= xSrcCnt
->createTextCursor();
81 xCur
->gotoStart(false);
83 sCopyableText
= xCur
->getText()->getString();
87 // Create the associated TextFrame and insert it into the document.
88 uno::Reference
<text::XTextContent
> xTextFrame(
89 SwXServiceProvider::MakeInstance(SwServiceType::TypeTextFrame
, *pShape
->GetDoc()),
91 uno::Reference
<text::XTextDocument
> xTextDocument(
92 pShape
->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY
);
93 uno::Reference
<text::XTextContentAppend
> xTextContentAppend(xTextDocument
->getText(),
95 xTextContentAppend
->appendTextContent(xTextFrame
, uno::Sequence
<beans::PropertyValue
>());
97 // Link FLY and DRAW formats, so it becomes a text box (needed for syncProperty calls).
98 uno::Reference
<text::XTextFrame
> xRealTextFrame(xTextFrame
, uno::UNO_QUERY
);
99 auto pTextFrame
= dynamic_cast<SwXTextFrame
*>(xRealTextFrame
.get());
100 assert(nullptr != pTextFrame
);
101 SwFrameFormat
* pFormat
= pTextFrame
->GetFrameFormat();
103 assert(nullptr != dynamic_cast<SwDrawFrameFormat
*>(pShape
));
104 assert(nullptr != dynamic_cast<SwFlyFrameFormat
*>(pFormat
));
106 if (!pShape
->GetOtherTextBoxFormats())
108 auto pTextBox
= std::make_shared
<SwTextBoxNode
>(SwTextBoxNode(pShape
));
109 pTextBox
->AddTextBox(pObject
, pFormat
);
110 pShape
->SetOtherTextBoxFormats(pTextBox
);
111 pFormat
->SetOtherTextBoxFormats(pTextBox
);
115 auto& pTextBox
= pShape
->GetOtherTextBoxFormats();
116 pTextBox
->AddTextBox(pObject
, pFormat
);
117 pFormat
->SetOtherTextBoxFormats(pTextBox
);
119 // Initialize properties.
120 uno::Reference
<beans::XPropertySet
> xPropertySet(xTextFrame
, uno::UNO_QUERY
);
121 uno::Any aEmptyBorder
{ table::BorderLine2() };
122 xPropertySet
->setPropertyValue(UNO_NAME_TOP_BORDER
, aEmptyBorder
);
123 xPropertySet
->setPropertyValue(UNO_NAME_BOTTOM_BORDER
, aEmptyBorder
);
124 xPropertySet
->setPropertyValue(UNO_NAME_LEFT_BORDER
, aEmptyBorder
);
125 xPropertySet
->setPropertyValue(UNO_NAME_RIGHT_BORDER
, aEmptyBorder
);
127 xPropertySet
->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE
, uno::Any(sal_Int32(100)));
129 xPropertySet
->setPropertyValue(UNO_NAME_SIZE_TYPE
, uno::Any(text::SizeType::FIX
));
131 xPropertySet
->setPropertyValue(UNO_NAME_SURROUND
, uno::Any(text::WrapTextMode_THROUGH
));
133 uno::Reference
<container::XNamed
> xNamed(xTextFrame
, uno::UNO_QUERY
);
134 assert(!xNamed
->getName().isEmpty());
137 // Link its text range to the original shape.
138 uno::Reference
<text::XTextRange
> xTextBox(xTextFrame
, uno::UNO_QUERY_THROW
);
139 SwUnoInternalPaM
aInternalPaM(*pShape
->GetDoc());
140 if (sw::XTextRangeToSwPaM(aInternalPaM
, xTextBox
))
142 SwAttrSet
aSet(pShape
->GetAttrSet());
143 SwFormatContent
aContent(aInternalPaM
.GetPointNode().StartOfSectionNode());
145 pShape
->SetFormatAttr(aSet
);
148 DoTextBoxZOrderCorrection(pShape
, pObject
);
150 // Also initialize the properties, which are not constant, but inherited from the shape's ones.
151 uno::Reference
<drawing::XShape
> xShape(pObject
->getUnoShape(), uno::UNO_QUERY
);
152 syncProperty(pShape
, RES_FRM_SIZE
, MID_FRMSIZE_SIZE
, uno::Any(xShape
->getSize()), pObject
);
154 uno::Reference
<beans::XPropertySet
> xShapePropertySet(xShape
, uno::UNO_QUERY
);
155 syncProperty(pShape
, RES_FOLLOW_TEXT_FLOW
, MID_FOLLOW_TEXT_FLOW
,
156 xShapePropertySet
->getPropertyValue(UNO_NAME_IS_FOLLOWING_TEXT_FLOW
), pObject
);
157 syncProperty(pShape
, RES_ANCHOR
, MID_ANCHOR_ANCHORTYPE
,
158 xShapePropertySet
->getPropertyValue(UNO_NAME_ANCHOR_TYPE
), pObject
);
159 syncProperty(pShape
, RES_HORI_ORIENT
, MID_HORIORIENT_ORIENT
,
160 xShapePropertySet
->getPropertyValue(UNO_NAME_HORI_ORIENT
), pObject
);
161 syncProperty(pShape
, RES_HORI_ORIENT
, MID_HORIORIENT_RELATION
,
162 xShapePropertySet
->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
), pObject
);
163 syncProperty(pShape
, RES_VERT_ORIENT
, MID_VERTORIENT_ORIENT
,
164 xShapePropertySet
->getPropertyValue(UNO_NAME_VERT_ORIENT
), pObject
);
165 syncProperty(pShape
, RES_VERT_ORIENT
, MID_VERTORIENT_RELATION
,
166 xShapePropertySet
->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION
), pObject
);
167 syncProperty(pShape
, RES_HORI_ORIENT
, MID_HORIORIENT_POSITION
,
168 xShapePropertySet
->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION
), pObject
);
169 syncProperty(pShape
, RES_VERT_ORIENT
, MID_VERTORIENT_POSITION
,
170 xShapePropertySet
->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION
), pObject
);
171 syncProperty(pShape
, RES_FRM_SIZE
, MID_FRMSIZE_IS_AUTO_HEIGHT
,
172 xShapePropertySet
->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT
), pObject
);
173 syncProperty(pShape
, RES_TEXT_VERT_ADJUST
, 0,
174 xShapePropertySet
->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST
), pObject
);
175 text::WritingMode eMode
;
176 if (xShapePropertySet
->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE
) >>= eMode
)
177 syncProperty(pShape
, RES_FRAMEDIR
, 0, uno::Any(sal_Int16(eMode
)), pObject
);
179 changeAnchor(pShape
, pObject
);
180 syncTextBoxSize(pShape
, pObject
);
182 // Check if the shape had text before and move it to the new textframe
183 if (!bCopyText
|| sCopyableText
.isEmpty())
188 auto pSourceText
= DynCastSdrTextObj(pObject
);
189 uno::Reference
<text::XTextRange
> xDestText(xRealTextFrame
, uno::UNO_QUERY
);
191 xDestText
->setString(sCopyableText
);
194 pSourceText
->SetText(OUString());
196 pShape
->GetDoc()->getIDocumentState().SetModified();
200 void SwTextBoxHelper::set(SwFrameFormat
* pShapeFormat
, SdrObject
* pObj
,
201 uno::Reference
<text::XTextFrame
> xNew
)
203 // Do not set invalid data
204 assert(pShapeFormat
&& pObj
&& xNew
);
205 // Firstly find the format of the new textbox.
206 SwFrameFormat
* pFormat
= nullptr;
207 if (auto pTextFrame
= dynamic_cast<SwXTextFrame
*>(xNew
.get()))
208 pFormat
= pTextFrame
->GetFrameFormat();
212 // If there is a format, check if the shape already has a textbox assigned to.
213 if (auto& pTextBoxNode
= pShapeFormat
->GetOtherTextBoxFormats())
215 // If it has a texbox, destroy it.
216 if (pTextBoxNode
->GetTextBox(pObj
))
217 pTextBoxNode
->DelTextBox(pObj
, true);
218 // And set the new one.
219 pTextBoxNode
->AddTextBox(pObj
, pFormat
);
220 pFormat
->SetOtherTextBoxFormats(pTextBoxNode
);
224 // If the shape do not have a texbox node and textbox,
225 // create that for the shape.
226 auto pTextBox
= std::make_shared
<SwTextBoxNode
>(SwTextBoxNode(pShapeFormat
));
227 pTextBox
->AddTextBox(pObj
, pFormat
);
228 pShapeFormat
->SetOtherTextBoxFormats(pTextBox
);
229 pFormat
->SetOtherTextBoxFormats(pTextBox
);
231 // Initialize its properties
232 uno::Reference
<beans::XPropertySet
> xPropertySet(xNew
, uno::UNO_QUERY
);
233 uno::Any aEmptyBorder
{ table::BorderLine2() };
234 xPropertySet
->setPropertyValue(UNO_NAME_TOP_BORDER
, aEmptyBorder
);
235 xPropertySet
->setPropertyValue(UNO_NAME_BOTTOM_BORDER
, aEmptyBorder
);
236 xPropertySet
->setPropertyValue(UNO_NAME_LEFT_BORDER
, aEmptyBorder
);
237 xPropertySet
->setPropertyValue(UNO_NAME_RIGHT_BORDER
, aEmptyBorder
);
238 xPropertySet
->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE
, uno::Any(sal_Int32(100)));
239 xPropertySet
->setPropertyValue(UNO_NAME_SIZE_TYPE
, uno::Any(text::SizeType::FIX
));
240 xPropertySet
->setPropertyValue(UNO_NAME_SURROUND
, uno::Any(text::WrapTextMode_THROUGH
));
241 // Add a new name to it
242 uno::Reference
<container::XNamed
> xNamed(xNew
, uno::UNO_QUERY
);
243 assert(!xNamed
->getName().isEmpty());
245 // And sync. properties.
246 uno::Reference
<drawing::XShape
> xShape(pObj
->getUnoShape(), uno::UNO_QUERY
);
247 syncProperty(pShapeFormat
, RES_FRM_SIZE
, MID_FRMSIZE_SIZE
, uno::Any(xShape
->getSize()), pObj
);
248 uno::Reference
<beans::XPropertySet
> xShapePropertySet(xShape
, uno::UNO_QUERY
);
249 syncProperty(pShapeFormat
, RES_ANCHOR
, MID_ANCHOR_ANCHORTYPE
,
250 xShapePropertySet
->getPropertyValue(UNO_NAME_ANCHOR_TYPE
), pObj
);
251 syncProperty(pShapeFormat
, RES_HORI_ORIENT
, MID_HORIORIENT_ORIENT
,
252 xShapePropertySet
->getPropertyValue(UNO_NAME_HORI_ORIENT
), pObj
);
253 syncProperty(pShapeFormat
, RES_HORI_ORIENT
, MID_HORIORIENT_RELATION
,
254 xShapePropertySet
->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
), pObj
);
255 syncProperty(pShapeFormat
, RES_VERT_ORIENT
, MID_VERTORIENT_ORIENT
,
256 xShapePropertySet
->getPropertyValue(UNO_NAME_VERT_ORIENT
), pObj
);
257 syncProperty(pShapeFormat
, RES_VERT_ORIENT
, MID_VERTORIENT_RELATION
,
258 xShapePropertySet
->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION
), pObj
);
259 syncProperty(pShapeFormat
, RES_HORI_ORIENT
, MID_HORIORIENT_POSITION
,
260 xShapePropertySet
->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION
), pObj
);
261 syncProperty(pShapeFormat
, RES_VERT_ORIENT
, MID_VERTORIENT_POSITION
,
262 xShapePropertySet
->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION
), pObj
);
263 syncProperty(pShapeFormat
, RES_FRM_SIZE
, MID_FRMSIZE_IS_AUTO_HEIGHT
,
264 xShapePropertySet
->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT
), pObj
);
265 drawing::TextVerticalAdjust aVertAdj
= drawing::TextVerticalAdjust_CENTER
;
266 if ((uno::Reference
<beans::XPropertyState
>(xShape
, uno::UNO_QUERY_THROW
))
267 ->getPropertyState(UNO_NAME_TEXT_VERT_ADJUST
)
268 != beans::PropertyState::PropertyState_DEFAULT_VALUE
)
270 aVertAdj
= xShapePropertySet
->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST
)
271 .get
<drawing::TextVerticalAdjust
>();
273 xPropertySet
->setPropertyValue(UNO_NAME_TEXT_VERT_ADJUST
, uno::Any(aVertAdj
));
274 text::WritingMode eMode
;
275 if (xShapePropertySet
->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE
) >>= eMode
)
276 syncProperty(pShapeFormat
, RES_FRAMEDIR
, 0, uno::Any(sal_Int16(eMode
)), pObj
);
278 // Do sync for the new textframe.
279 synchronizeGroupTextBoxProperty(&changeAnchor
, pShapeFormat
, pObj
);
280 synchronizeGroupTextBoxProperty(&syncTextBoxSize
, pShapeFormat
, pObj
);
282 updateTextBoxMargin(pObj
);
285 void SwTextBoxHelper::destroy(const SwFrameFormat
* pShape
, const SdrObject
* pObject
)
287 // If a TextBox was enabled previously
288 auto& pTextBox
= pShape
->GetOtherTextBoxFormats();
291 // Unlink the TextBox's text range from the original shape.
292 // Delete the associated TextFrame.
293 pTextBox
->DelTextBox(pObject
, true);
297 bool SwTextBoxHelper::isTextBox(const SwFrameFormat
* pFormat
, sal_uInt16 nType
,
298 const SdrObject
* pObject
)
300 DBG_TESTSOLARMUTEX();
301 assert(nType
== RES_FLYFRMFMT
|| nType
== RES_DRAWFRMFMT
);
302 if (!pFormat
|| pFormat
->Which() != nType
)
305 auto& pTextBox
= pFormat
->GetOtherTextBoxFormats();
309 if (nType
== RES_DRAWFRMFMT
)
312 return pTextBox
->GetTextBox(pObject
);
313 if (auto pObj
= pFormat
->FindRealSdrObject())
314 return pTextBox
->GetTextBox(pObj
);
317 if (nType
== RES_FLYFRMFMT
)
319 return pTextBox
->GetOwnerShape();
325 bool SwTextBoxHelper::hasTextFrame(const SdrObject
* pObj
)
330 uno::Reference
<drawing::XShape
> xShape(pObj
->getWeakUnoShape().get(), uno::UNO_QUERY
);
333 return SwTextBoxHelper::getOtherTextBoxFormat(xShape
);
336 sal_Int32
SwTextBoxHelper::getCount(SdrPage
const* pPage
)
339 for (std::size_t i
= 0; i
< pPage
->GetObjCount(); ++i
)
341 SdrObject
* p
= pPage
->GetObj(i
);
342 if (p
&& p
->IsTextBox())
349 sal_Int32
SwTextBoxHelper::getCount(const SwDoc
& rDoc
)
352 for (const sw::SpzFrameFormat
* pFormat
: *rDoc
.GetSpzFrameFormats())
354 if (isTextBox(pFormat
, RES_FLYFRMFMT
))
360 uno::Any
SwTextBoxHelper::getByIndex(SdrPage
const* pPage
, sal_Int32 nIndex
)
363 throw lang::IndexOutOfBoundsException();
365 SdrObject
* pRet
= nullptr;
366 sal_Int32 nCount
= 0; // Current logical index.
367 for (std::size_t i
= 0; i
< pPage
->GetObjCount(); ++i
)
369 SdrObject
* p
= pPage
->GetObj(i
);
370 if (p
&& p
->IsTextBox())
372 if (nCount
== nIndex
)
381 throw lang::IndexOutOfBoundsException();
383 return uno::Any(uno::Reference
<drawing::XShape
>(pRet
->getUnoShape(), uno::UNO_QUERY
));
386 sal_Int32
SwTextBoxHelper::getOrdNum(const SdrObject
* pObject
)
388 if (const SdrPage
* pPage
= pObject
->getSdrPageFromSdrObject())
390 sal_Int32 nOrder
= 0; // Current logical order.
391 for (std::size_t i
= 0; i
< pPage
->GetObjCount(); ++i
)
393 SdrObject
* p
= pPage
->GetObj(i
);
394 if (p
&& p
->IsTextBox())
402 SAL_WARN("sw.core", "SwTextBoxHelper::getOrdNum: no page or page doesn't contain the object");
403 return pObject
->GetOrdNum();
406 void SwTextBoxHelper::getShapeWrapThrough(const SwFrameFormat
* pTextBox
, bool& rWrapThrough
)
408 SwFrameFormat
* pShape
= SwTextBoxHelper::getOtherTextBoxFormat(pTextBox
, RES_FLYFRMFMT
);
410 rWrapThrough
= pShape
->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH
;
413 SwFrameFormat
* SwTextBoxHelper::getOtherTextBoxFormat(const SwFrameFormat
* pFormat
,
414 sal_uInt16 nType
, const SdrObject
* pObject
)
416 SolarMutexGuard aGuard
;
417 if (!isTextBox(pFormat
, nType
, pObject
))
420 if (nType
== RES_DRAWFRMFMT
)
423 return pFormat
->GetOtherTextBoxFormats()->GetTextBox(pObject
);
424 if (pFormat
->FindRealSdrObject())
425 return pFormat
->GetOtherTextBoxFormats()->GetTextBox(pFormat
->FindRealSdrObject());
428 if (nType
== RES_FLYFRMFMT
)
430 return pFormat
->GetOtherTextBoxFormats()->GetOwnerShape();
435 SwFrameFormat
* SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference
<drawing::XShape
> const& xShape
)
437 auto pShape
= dynamic_cast<SwXShape
*>(xShape
.get());
441 SwFrameFormat
* pFormat
= pShape
->GetFrameFormat();
442 return getOtherTextBoxFormat(pFormat
, RES_DRAWFRMFMT
,
443 SdrObject::getSdrObjectFromXShape(xShape
));
446 uno::Reference
<text::XTextFrame
>
447 SwTextBoxHelper::getUnoTextFrame(uno::Reference
<drawing::XShape
> const& xShape
)
451 auto pFrameFormat
= SwTextBoxHelper::getOtherTextBoxFormat(xShape
);
454 auto pSdrObj
= pFrameFormat
->FindSdrObject();
457 return { pSdrObj
->getUnoShape(), uno::UNO_QUERY
};
464 template <typename T
>
465 static void lcl_queryInterface(const SwFrameFormat
* pShape
, uno::Any
& rAny
, SdrObject
* pObj
)
467 if (SwFrameFormat
* pFormat
468 = SwTextBoxHelper::getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
))
470 uno::Reference
<T
> const xInterface(
471 static_cast<cppu::OWeakObject
*>(
472 SwXTextFrame::CreateXTextFrame(*pFormat
->GetDoc(), pFormat
).get()),
478 uno::Any
SwTextBoxHelper::queryInterface(const SwFrameFormat
* pShape
, const uno::Type
& rType
,
483 if (rType
== cppu::UnoType
<css::text::XTextAppend
>::get())
485 lcl_queryInterface
<text::XTextAppend
>(pShape
, aRet
, pObj
);
487 else if (rType
== cppu::UnoType
<css::text::XText
>::get())
489 lcl_queryInterface
<text::XText
>(pShape
, aRet
, pObj
);
491 else if (rType
== cppu::UnoType
<css::text::XTextRange
>::get())
493 lcl_queryInterface
<text::XTextRange
>(pShape
, aRet
, pObj
);
499 tools::Rectangle
SwTextBoxHelper::getRelativeTextRectangle(SdrObject
* pShape
)
501 tools::Rectangle aRet
;
506 auto pCustomShape
= dynamic_cast<SdrObjCustomShape
*>(pShape
);
509 // Need to temporarily release the lock acquired in
510 // SdXMLShapeContext::AddShape(), otherwise we get an empty rectangle,
511 // see EnhancedCustomShapeEngine::getTextBounds().
512 uno::Reference
<document::XActionLockable
> xLockable(pCustomShape
->getUnoShape(),
514 sal_Int16 nLocks
= 0;
516 nLocks
= xLockable
->resetActionLocks();
517 pCustomShape
->GetTextBounds(aRet
);
519 xLockable
->setActionLocks(nLocks
);
523 // fallback - get *any* bound rect we can possibly get hold of
524 aRet
= pShape
->GetCurrentBoundRect();
529 // Relative, so count the logic (reference) rectangle, see the EnhancedCustomShape2d ctor.
530 Point
aPoint(pShape
->GetSnapRect().Center());
531 Size
aSize(pShape
->GetLogicRect().GetSize());
532 aPoint
.AdjustX(-(aSize
.Width() / 2));
533 aPoint
.AdjustY(-(aSize
.Height() / 2));
534 tools::Rectangle
aLogicRect(aPoint
, aSize
);
535 aRet
.Move(-1 * aLogicRect
.Left(), -1 * aLogicRect
.Top());
541 void SwTextBoxHelper::syncProperty(SwFrameFormat
* pShape
, std::u16string_view rPropertyName
,
542 const css::uno::Any
& rValue
, SdrObject
* pObj
)
544 // Textframes does not have valid horizontal adjust property, so map it to paragraph adjust property
545 if (rPropertyName
== UNO_NAME_TEXT_HORZADJUST
)
547 SwFrameFormat
* pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
);
551 auto xTextFrame
= SwXTextFrame::CreateXTextFrame(*pFormat
->GetDoc(), pFormat
);
552 uno::Reference
<text::XTextCursor
> xCursor
= xTextFrame
->getText()->createTextCursor();
554 // Select all paragraphs in the textframe
555 xCursor
->gotoStart(false);
556 xCursor
->gotoEnd(true);
557 uno::Reference
<beans::XPropertySet
> xFrameParaProps(xCursor
, uno::UNO_QUERY
);
559 // And simply map the property
560 const auto eValue
= rValue
.get
<drawing::TextHorizontalAdjust
>();
563 case drawing::TextHorizontalAdjust::TextHorizontalAdjust_CENTER
:
564 xFrameParaProps
->setPropertyValue(
565 UNO_NAME_PARA_ADJUST
,
566 uno::Any(style::ParagraphAdjust::ParagraphAdjust_CENTER
)); //3
568 case drawing::TextHorizontalAdjust::TextHorizontalAdjust_LEFT
:
569 xFrameParaProps
->setPropertyValue(
570 UNO_NAME_PARA_ADJUST
,
571 uno::Any(style::ParagraphAdjust::ParagraphAdjust_LEFT
)); //0
573 case drawing::TextHorizontalAdjust::TextHorizontalAdjust_RIGHT
:
574 xFrameParaProps
->setPropertyValue(
575 UNO_NAME_PARA_ADJUST
,
576 uno::Any(style::ParagraphAdjust::ParagraphAdjust_RIGHT
)); //1
580 "SwTextBoxHelper::syncProperty: unhandled TextHorizontalAdjust: "
581 << static_cast<sal_Int32
>(eValue
));
587 if (rPropertyName
== u
"CustomShapeGeometry")
589 // CustomShapeGeometry changes the textbox position offset and size, so adjust both.
590 syncProperty(pShape
, RES_FRM_SIZE
, MID_FRMSIZE_SIZE
, uno::Any());
592 SdrObject
* pObject
= pObj
? pObj
: pShape
->FindRealSdrObject();
595 tools::Rectangle
aRectangle(pObject
->GetSnapRect());
596 syncProperty(pShape
, RES_HORI_ORIENT
, MID_HORIORIENT_POSITION
,
597 uno::Any(static_cast<sal_Int32
>(convertTwipToMm100(aRectangle
.Left()))));
598 syncProperty(pShape
, RES_VERT_ORIENT
, MID_VERTORIENT_POSITION
,
599 uno::Any(static_cast<sal_Int32
>(convertTwipToMm100(aRectangle
.Top()))));
602 SwFrameFormat
* pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
);
606 // Older documents or documents in ODF strict do not have WritingMode, but have used the
607 // TextRotateAngle values -90 and -270 to emulate these text directions of frames.
608 // ToDo: Is TextPreRotateAngle needed for diagrams or can it be removed?
609 comphelper::SequenceAsHashMap
aCustomShapeGeometry(rValue
);
610 auto it
= aCustomShapeGeometry
.find("TextPreRotateAngle");
611 if (it
== aCustomShapeGeometry
.end())
613 it
= aCustomShapeGeometry
.find("TextRotateAngle");
616 if (it
!= aCustomShapeGeometry
.end())
618 auto nAngle
= it
->second
.has
<sal_Int32
>() ? it
->second
.get
<sal_Int32
>() : 0;
621 nAngle
= it
->second
.has
<double>() ? it
->second
.get
<double>() : 0;
624 sal_Int16 nDirection
= 0;
628 nDirection
= text::WritingMode2::TB_RL90
;
631 nDirection
= text::WritingMode2::BT_LR
;
634 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled property value: "
635 "CustomShapeGeometry:TextPreRotateAngle: "
642 syncProperty(pShape
, RES_FRAMEDIR
, 0, uno::Any(nDirection
), pObj
);
646 else if (rPropertyName
== UNO_NAME_TEXT_VERT_ADJUST
)
647 syncProperty(pShape
, RES_TEXT_VERT_ADJUST
, 0, rValue
, pObj
);
648 else if (rPropertyName
== UNO_NAME_TEXT_AUTOGROWHEIGHT
)
649 syncProperty(pShape
, RES_FRM_SIZE
, MID_FRMSIZE_IS_AUTO_HEIGHT
, rValue
, pObj
);
650 else if (rPropertyName
== UNO_NAME_TEXT_LEFTDIST
)
651 syncProperty(pShape
, RES_BOX
, LEFT_BORDER_DISTANCE
, rValue
, pObj
);
652 else if (rPropertyName
== UNO_NAME_TEXT_RIGHTDIST
)
653 syncProperty(pShape
, RES_BOX
, RIGHT_BORDER_DISTANCE
, rValue
, pObj
);
654 else if (rPropertyName
== UNO_NAME_TEXT_UPPERDIST
)
655 syncProperty(pShape
, RES_BOX
, TOP_BORDER_DISTANCE
, rValue
, pObj
);
656 else if (rPropertyName
== UNO_NAME_TEXT_LOWERDIST
)
657 syncProperty(pShape
, RES_BOX
, BOTTOM_BORDER_DISTANCE
, rValue
, pObj
);
658 else if (rPropertyName
== UNO_NAME_TEXT_WRITINGMODE
)
660 text::WritingMode eMode
;
662 if (rValue
>>= eMode
)
663 syncProperty(pShape
, RES_FRAMEDIR
, 0, uno::Any(sal_Int16(eMode
)), pObj
);
664 else if (rValue
>>= eMode2
)
665 syncProperty(pShape
, RES_FRAMEDIR
, 0, uno::Any(eMode2
), pObj
);
667 else if (rPropertyName
== u
"WritingMode")
670 if (rValue
>>= eMode2
)
671 syncProperty(pShape
, RES_FRAMEDIR
, 0, uno::Any(eMode2
), pObj
);
674 SAL_INFO("sw.core", "SwTextBoxHelper::syncProperty: unhandled property: "
675 << static_cast<OUString
>(rPropertyName
));
678 void SwTextBoxHelper::getProperty(SwFrameFormat
const* pShape
, sal_uInt16 nWID
, sal_uInt8 nMemberID
,
679 css::uno::Any
& rValue
)
684 nMemberID
&= ~CONVERT_TWIPS
;
686 SwFrameFormat
* pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
);
690 if (nWID
!= RES_CHAIN
)
695 case MID_CHAIN_PREVNAME
:
696 case MID_CHAIN_NEXTNAME
:
698 const SwFormatChain
& rChain
= pFormat
->GetChain();
699 rChain
.QueryValue(rValue
, nMemberID
);
703 rValue
<<= pFormat
->GetName();
706 SAL_WARN("sw.core", "SwTextBoxHelper::getProperty: unhandled member-id: "
707 << o3tl::narrowing
<sal_uInt16
>(nMemberID
));
712 css::uno::Any
SwTextBoxHelper::getProperty(SwFrameFormat
const* pShape
, const OUString
& rPropName
)
717 SwFrameFormat
* pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
);
721 rtl::Reference
<SwXTextFrame
> xPropertySet
722 = SwXTextFrame::CreateXTextFrame(*pFormat
->GetDoc(), pFormat
);
724 return xPropertySet
->getPropertyValue(rPropName
);
727 void SwTextBoxHelper::syncProperty(SwFrameFormat
* pShape
, sal_uInt16 nWID
, sal_uInt8 nMemberID
,
728 const css::uno::Any
& rValue
, SdrObject
* pObj
)
730 // No shape yet? Then nothing to do, initial properties are set by create().
734 uno::Any
aValue(rValue
);
735 nMemberID
&= ~CONVERT_TWIPS
;
737 SwFrameFormat
* pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
);
741 OUString aPropertyName
;
742 bool bAdjustX
= false;
743 bool bAdjustY
= false;
744 bool bAdjustSize
= false;
747 case RES_HORI_ORIENT
:
750 case MID_HORIORIENT_ORIENT
:
751 aPropertyName
= UNO_NAME_HORI_ORIENT
;
753 case MID_HORIORIENT_RELATION
:
754 if (pShape
->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
)
755 aPropertyName
= UNO_NAME_HORI_ORIENT_RELATION
;
759 case MID_HORIORIENT_POSITION
:
760 aPropertyName
= UNO_NAME_HORI_ORIENT_POSITION
;
764 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
765 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
766 << " (which-id: " << nWID
<< ")");
775 aPropertyName
= UNO_NAME_LEFT_MARGIN
;
778 aPropertyName
= UNO_NAME_RIGHT_MARGIN
;
781 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
782 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
783 << " (which-id: " << nWID
<< ")");
788 case RES_VERT_ORIENT
:
791 case MID_VERTORIENT_ORIENT
:
792 aPropertyName
= UNO_NAME_VERT_ORIENT
;
794 case MID_VERTORIENT_RELATION
:
795 if (pShape
->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR
)
796 aPropertyName
= UNO_NAME_VERT_ORIENT_RELATION
;
800 case MID_VERTORIENT_POSITION
:
801 aPropertyName
= UNO_NAME_VERT_ORIENT_POSITION
;
805 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
806 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
807 << " (which-id: " << nWID
<< ")");
814 case MID_FRMSIZE_WIDTH_TYPE
:
815 aPropertyName
= UNO_NAME_WIDTH_TYPE
;
817 case MID_FRMSIZE_IS_AUTO_HEIGHT
:
818 aPropertyName
= UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT
;
820 case MID_FRMSIZE_REL_HEIGHT_RELATION
:
821 aPropertyName
= UNO_NAME_RELATIVE_HEIGHT_RELATION
;
823 case MID_FRMSIZE_REL_WIDTH_RELATION
:
824 aPropertyName
= UNO_NAME_RELATIVE_WIDTH_RELATION
;
827 aPropertyName
= UNO_NAME_SIZE
;
835 case MID_ANCHOR_ANCHORTYPE
:
837 changeAnchor(pShape
, pObj
);
842 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
843 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
844 << " (which-id: " << nWID
<< ")");
850 uno::Reference
<text::XTextRange
> xRange
;
852 SwUnoInternalPaM
aInternalPaM(*pFormat
->GetDoc());
853 if (sw::XTextRangeToSwPaM(aInternalPaM
, xRange
))
855 SwFormatAnchor
aAnchor(pFormat
->GetAnchor());
856 aAnchor
.SetAnchor(aInternalPaM
.Start());
857 pFormat
->SetFormatAttr(aAnchor
);
864 case MID_CHAIN_PREVNAME
:
865 aPropertyName
= UNO_NAME_CHAIN_PREV_NAME
;
867 case MID_CHAIN_NEXTNAME
:
868 aPropertyName
= UNO_NAME_CHAIN_NEXT_NAME
;
871 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
872 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
873 << " (which-id: " << nWID
<< ")");
877 case RES_TEXT_VERT_ADJUST
:
878 aPropertyName
= UNO_NAME_TEXT_VERT_ADJUST
;
883 case LEFT_BORDER_DISTANCE
:
884 aPropertyName
= UNO_NAME_LEFT_BORDER_DISTANCE
;
886 case RIGHT_BORDER_DISTANCE
:
887 aPropertyName
= UNO_NAME_RIGHT_BORDER_DISTANCE
;
889 case TOP_BORDER_DISTANCE
:
890 aPropertyName
= UNO_NAME_TOP_BORDER_DISTANCE
;
892 case BOTTOM_BORDER_DISTANCE
:
893 aPropertyName
= UNO_NAME_BOTTOM_BORDER_DISTANCE
;
896 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
897 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
898 << " (which-id: " << nWID
<< ")");
903 aPropertyName
= UNO_NAME_OPAQUE
;
906 aPropertyName
= UNO_NAME_WRITING_MODE
;
908 case RES_WRAP_INFLUENCE_ON_OBJPOS
:
911 case MID_ALLOW_OVERLAP
:
912 aPropertyName
= UNO_NAME_ALLOW_OVERLAP
;
915 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
916 << o3tl::narrowing
<sal_uInt16
>(nMemberID
)
917 << " (which-id: " << nWID
<< ")");
922 SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled which-id: "
923 << nWID
<< " (member-id: "
924 << o3tl::narrowing
<sal_uInt16
>(nMemberID
) << ")");
928 if (aPropertyName
.isEmpty())
931 // Position/size should be the text position/size, not the shape one as-is.
932 if (bAdjustX
|| bAdjustY
|| bAdjustSize
)
934 changeAnchor(pShape
, pObj
);
935 tools::Rectangle aRect
936 = getRelativeTextRectangle(pObj
? pObj
: pShape
->FindRealSdrObject());
937 if (!aRect
.IsEmpty())
939 if (bAdjustX
|| bAdjustY
)
942 if (aValue
>>= nValue
)
944 nValue
+= convertTwipToMm100(bAdjustX
? aRect
.Left() : aRect
.Top());
948 else if (bAdjustSize
)
950 awt::Size
aSize(convertTwipToMm100(aRect
.getOpenWidth()),
951 convertTwipToMm100(aRect
.getOpenHeight()));
956 auto aGuard
= SwTextBoxLockGuard(*pShape
->GetOtherTextBoxFormats());
957 rtl::Reference
<SwXTextFrame
> const xPropertySet
958 = SwXTextFrame::CreateXTextFrame(*pFormat
->GetDoc(), pFormat
);
959 xPropertySet
->setPropertyValue(aPropertyName
, aValue
);
962 void SwTextBoxHelper::saveLinks(const sw::FrameFormats
<sw::SpzFrameFormat
*>& rFormats
,
963 std::map
<const SwFrameFormat
*, const SwFrameFormat
*>& rLinks
)
965 for (const auto pFormat
: rFormats
)
967 if (SwFrameFormat
* pTextBox
= getOtherTextBoxFormat(pFormat
, RES_DRAWFRMFMT
))
968 rLinks
[pFormat
] = pTextBox
;
972 void SwTextBoxHelper::restoreLinks(std::set
<ZSortFly
>& rOld
, std::vector
<SwFrameFormat
*>& rNew
,
973 SavedLink
& rSavedLinks
)
976 for (const auto& rIt
: rOld
)
978 auto aTextBoxIt
= rSavedLinks
.find(rIt
.GetFormat());
979 if (aTextBoxIt
!= rSavedLinks
.end())
982 for (const auto& rJt
: rOld
)
984 if (rJt
.GetFormat() == aTextBoxIt
->second
)
985 rNew
[i
]->SetFormatAttr(rNew
[j
]->GetContent());
993 text::TextContentAnchorType
SwTextBoxHelper::mapAnchorType(const RndStdIds
& rAnchorID
)
995 text::TextContentAnchorType aAnchorType
;
998 case RndStdIds::FLY_AS_CHAR
:
999 aAnchorType
= text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER
;
1001 case RndStdIds::FLY_AT_CHAR
:
1002 aAnchorType
= text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER
;
1004 case RndStdIds::FLY_AT_PARA
:
1005 aAnchorType
= text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH
;
1007 case RndStdIds::FLY_AT_PAGE
:
1008 aAnchorType
= text::TextContentAnchorType::TextContentAnchorType_AT_PAGE
;
1010 case RndStdIds::FLY_AT_FLY
:
1011 aAnchorType
= text::TextContentAnchorType::TextContentAnchorType_AT_FRAME
;
1014 aAnchorType
= text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH
;
1015 SAL_WARN("sw.core", "SwTextBoxHelper::mapAnchorType: Unknown AnchorType!");
1021 void SwTextBoxHelper::syncFlyFrameAttr(SwFrameFormat
& rShape
, SfxItemSet
const& rSet
,
1024 SwFrameFormat
* pFormat
= getOtherTextBoxFormat(&rShape
, RES_DRAWFRMFMT
, pObj
);
1028 const bool bInlineAnchored
= rShape
.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
;
1029 const bool bLayoutInCell
= rShape
.GetFollowTextFlow().GetValue()
1030 && rShape
.GetAnchor().GetAnchorNode()
1031 && rShape
.GetAnchor().GetAnchorNode()->FindTableNode();
1032 SfxItemSet
aTextBoxSet(pFormat
->GetDoc()->GetAttrPool(), aFrameFormatSetRange
);
1034 SfxItemIter
aIter(rSet
);
1035 const SfxPoolItem
* pItem
= aIter
.GetCurItem();
1039 switch (pItem
->Which())
1041 case RES_VERT_ORIENT
:
1043 // The new position can be with anchor changing so sync it!
1044 const text::TextContentAnchorType aNewAnchorType
1045 = mapAnchorType(rShape
.GetAnchor().GetAnchorId());
1046 syncProperty(&rShape
, RES_ANCHOR
, MID_ANCHOR_ANCHORTYPE
, uno::Any(aNewAnchorType
),
1048 if (bInlineAnchored
|| bLayoutInCell
)
1050 SwFormatVertOrient
aOrient(pItem
->StaticWhichCast(RES_VERT_ORIENT
));
1052 tools::Rectangle aRect
1053 = getRelativeTextRectangle(pObj
? pObj
: rShape
.FindRealSdrObject());
1054 if (!aRect
.IsEmpty())
1055 aOrient
.SetPos(aOrient
.GetPos() + aRect
.Top());
1057 if (rShape
.GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
1058 && rShape
.GetAnchor().GetPageNum() != 0)
1059 aOrient
.SetRelationOrient(rShape
.GetVertOrient().GetRelationOrient());
1060 aTextBoxSet
.Put(aOrient
);
1062 // restore height (shrunk for extending beyond the page bottom - tdf#91260)
1063 SwFormatFrameSize
aSize(pFormat
->GetFrameSize());
1064 if (!aRect
.IsEmpty())
1066 aSize
.SetHeight(aRect
.getOpenHeight());
1067 aTextBoxSet
.Put(aSize
);
1071 case RES_HORI_ORIENT
:
1073 // The new position can be with anchor changing so sync it!
1074 const text::TextContentAnchorType aNewAnchorType
1075 = mapAnchorType(rShape
.GetAnchor().GetAnchorId());
1076 syncProperty(&rShape
, RES_ANCHOR
, MID_ANCHOR_ANCHORTYPE
, uno::Any(aNewAnchorType
),
1078 if (bInlineAnchored
|| bLayoutInCell
)
1080 SwFormatHoriOrient
aOrient(pItem
->StaticWhichCast(RES_HORI_ORIENT
));
1082 tools::Rectangle aRect
1083 = getRelativeTextRectangle(pObj
? pObj
: rShape
.FindRealSdrObject());
1084 if (!aRect
.IsEmpty())
1085 aOrient
.SetPos(aOrient
.GetPos() + aRect
.Left());
1087 if (rShape
.GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
1088 && rShape
.GetAnchor().GetPageNum() != 0)
1089 aOrient
.SetRelationOrient(rShape
.GetHoriOrient().GetRelationOrient());
1090 aTextBoxSet
.Put(aOrient
);
1095 // In case the shape got resized, then we need to adjust both
1096 // the position and the size of the textbox (e.g. larger
1097 // rounded edges of a rectangle -> need to push right/down the
1099 SwFormatVertOrient
aVertOrient(rShape
.GetVertOrient());
1100 SwFormatHoriOrient
aHoriOrient(rShape
.GetHoriOrient());
1101 SwFormatFrameSize
aSize(pFormat
->GetFrameSize());
1103 tools::Rectangle aRect
1104 = getRelativeTextRectangle(pObj
? pObj
: rShape
.FindRealSdrObject());
1105 if (!aRect
.IsEmpty())
1107 if (!bInlineAnchored
)
1110 (pObj
? pObj
->GetRelativePos().getX() : aVertOrient
.GetPos())
1113 (pObj
? pObj
->GetRelativePos().getY() : aHoriOrient
.GetPos())
1116 aTextBoxSet
.Put(aVertOrient
);
1117 aTextBoxSet
.Put(aHoriOrient
);
1120 aSize
.SetWidth(aRect
.getOpenWidth());
1121 aSize
.SetHeight(aRect
.getOpenHeight());
1122 aTextBoxSet
.Put(aSize
);
1128 if (pItem
->StaticWhichCast(RES_ANCHOR
) == rShape
.GetAnchor())
1129 // the anchor have to be synced
1131 const text::TextContentAnchorType aNewAnchorType
1132 = mapAnchorType(rShape
.GetAnchor().GetAnchorId());
1133 syncProperty(&rShape
, RES_ANCHOR
, MID_ANCHOR_ANCHORTYPE
,
1134 uno::Any(aNewAnchorType
), pObj
);
1138 SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: The anchor of the "
1139 "shape different from the textframe!");
1144 SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: unhandled which-id: "
1149 pItem
= aIter
.NextItem();
1150 } while (pItem
&& (0 != pItem
->Which()));
1152 if (aTextBoxSet
.Count())
1154 auto aGuard
= SwTextBoxLockGuard(*rShape
.GetOtherTextBoxFormats());
1155 pFormat
->SetFormatAttr(aTextBoxSet
);
1157 DoTextBoxZOrderCorrection(&rShape
, pObj
);
1160 void SwTextBoxHelper::updateTextBoxMargin(SdrObject
* pObj
)
1164 uno::Reference
<drawing::XShape
> xShape(pObj
->getUnoShape(), uno::UNO_QUERY
);
1167 uno::Reference
<beans::XPropertySet
> const xPropertySet(xShape
, uno::UNO_QUERY
);
1169 auto pParentFormat
= getOtherTextBoxFormat(getOtherTextBoxFormat(xShape
), RES_FLYFRMFMT
);
1174 syncProperty(pParentFormat
, UNO_NAME_TEXT_LEFTDIST
,
1175 xPropertySet
->getPropertyValue(UNO_NAME_TEXT_LEFTDIST
), pObj
);
1176 syncProperty(pParentFormat
, UNO_NAME_TEXT_RIGHTDIST
,
1177 xPropertySet
->getPropertyValue(UNO_NAME_TEXT_RIGHTDIST
), pObj
);
1178 syncProperty(pParentFormat
, UNO_NAME_TEXT_UPPERDIST
,
1179 xPropertySet
->getPropertyValue(UNO_NAME_TEXT_UPPERDIST
), pObj
);
1180 syncProperty(pParentFormat
, UNO_NAME_TEXT_LOWERDIST
,
1181 xPropertySet
->getPropertyValue(UNO_NAME_TEXT_LOWERDIST
), pObj
);
1183 // Sync the text aligning
1184 syncProperty(pParentFormat
, UNO_NAME_TEXT_VERTADJUST
,
1185 xPropertySet
->getPropertyValue(UNO_NAME_TEXT_VERTADJUST
), pObj
);
1186 syncProperty(pParentFormat
, UNO_NAME_TEXT_HORZADJUST
,
1187 xPropertySet
->getPropertyValue(UNO_NAME_TEXT_HORZADJUST
), pObj
);
1189 // tdf137803: Sync autogrow:
1190 const bool bIsAutoGrow
1191 = xPropertySet
->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT
).get
<bool>();
1192 const bool bIsAutoWrap
= xPropertySet
->getPropertyValue(UNO_NAME_TEXT_WORDWRAP
).get
<bool>();
1194 syncProperty(pParentFormat
, RES_FRM_SIZE
, MID_FRMSIZE_IS_AUTO_HEIGHT
, uno::Any(bIsAutoGrow
),
1197 syncProperty(pParentFormat
, RES_FRM_SIZE
, MID_FRMSIZE_WIDTH_TYPE
,
1198 uno::Any(bIsAutoWrap
? text::SizeType::FIX
: text::SizeType::MIN
), pObj
);
1200 changeAnchor(pParentFormat
, pObj
);
1201 DoTextBoxZOrderCorrection(pParentFormat
, pObj
);
1204 bool SwTextBoxHelper::changeAnchor(SwFrameFormat
* pShape
, SdrObject
* pObj
)
1206 if (auto pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
))
1208 if (!isAnchorSyncNeeded(pShape
, pFormat
))
1210 doTextBoxPositioning(pShape
, pObj
);
1211 DoTextBoxZOrderCorrection(pShape
, pObj
);
1212 if (pShape
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
1213 && pFormat
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR
1214 && pFormat
->GetVertOrient().GetRelationOrient() != text::RelOrientation::PRINT_AREA
)
1216 SwFormatVertOrient aTmp
= pFormat
->GetVertOrient();
1217 aTmp
.SetRelationOrient(text::RelOrientation::PRINT_AREA
);
1218 pFormat
->SetFormatAttr(aTmp
);
1224 const SwFormatAnchor
& rOldAnch
= pFormat
->GetAnchor();
1225 const SwFormatAnchor
& rNewAnch
= pShape
->GetAnchor();
1227 const auto pOldCnt
= rOldAnch
.GetContentAnchor();
1228 const auto pNewCnt
= rNewAnch
.GetContentAnchor();
1230 const uno::Any
aShapeHorRelOrient(pShape
->GetHoriOrient().GetRelationOrient());
1234 auto aGuard
= SwTextBoxLockGuard(*pShape
->GetOtherTextBoxFormats());
1235 ::sw::UndoGuard
const UndoGuard(pShape
->GetDoc()->GetIDocumentUndoRedo());
1236 rtl::Reference
<SwXTextFrame
> const xPropertySet
1237 = SwXTextFrame::CreateXTextFrame(*pFormat
->GetDoc(), pFormat
);
1238 if (pOldCnt
&& rNewAnch
.GetAnchorId() == RndStdIds::FLY_AT_PAGE
1239 && rNewAnch
.GetPageNum())
1241 uno::Any
aValue(text::TextContentAnchorType_AT_PAGE
);
1242 xPropertySet
->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
, aShapeHorRelOrient
);
1243 xPropertySet
->setPropertyValue(UNO_NAME_ANCHOR_TYPE
, aValue
);
1244 xPropertySet
->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO
,
1245 uno::Any(rNewAnch
.GetPageNum()));
1247 else if (rOldAnch
.GetAnchorId() == RndStdIds::FLY_AT_PAGE
&& pNewCnt
)
1249 if (rNewAnch
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
1252 uno::Any
aValue(text::TextContentAnchorType_AT_CHARACTER
);
1253 xPropertySet
->setPropertyValue(UNO_NAME_ANCHOR_TYPE
, aValue
);
1254 xPropertySet
->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
,
1255 uno::Any(text::RelOrientation::CHAR
));
1256 xPropertySet
->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION
,
1257 uno::Any(text::RelOrientation::PRINT_AREA
));
1258 SwFormatAnchor
aPos(pFormat
->GetAnchor());
1259 aPos
.SetAnchor(pNewCnt
);
1260 pFormat
->SetFormatAttr(aPos
);
1264 uno::Any
aValue(mapAnchorType(rNewAnch
.GetAnchorId()));
1265 xPropertySet
->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
,
1266 aShapeHorRelOrient
);
1267 xPropertySet
->setPropertyValue(UNO_NAME_ANCHOR_TYPE
, aValue
);
1268 pFormat
->SetFormatAttr(rNewAnch
);
1273 if (rNewAnch
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
1276 uno::Any
aValue(text::TextContentAnchorType_AT_CHARACTER
);
1277 xPropertySet
->setPropertyValue(UNO_NAME_ANCHOR_TYPE
, aValue
);
1278 xPropertySet
->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
,
1279 uno::Any(text::RelOrientation::CHAR
));
1280 xPropertySet
->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION
,
1281 uno::Any(text::RelOrientation::PRINT_AREA
));
1282 SwFormatAnchor
aPos(pFormat
->GetAnchor());
1283 aPos
.SetAnchor(pNewCnt
);
1284 pFormat
->SetFormatAttr(aPos
);
1288 xPropertySet
->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION
,
1289 aShapeHorRelOrient
);
1290 if (rNewAnch
.GetAnchorId() == RndStdIds::FLY_AT_PAGE
1291 && rNewAnch
.GetPageNum() == 0)
1293 pFormat
->SetFormatAttr(SwFormatAnchor(RndStdIds::FLY_AT_PAGE
, 1));
1296 pFormat
->SetFormatAttr(pShape
->GetAnchor());
1300 catch (uno::Exception
& e
)
1302 SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << e
.Message
);
1305 doTextBoxPositioning(pShape
, pObj
);
1306 DoTextBoxZOrderCorrection(pShape
, pObj
);
1313 bool SwTextBoxHelper::doTextBoxPositioning(SwFrameFormat
* pShape
, SdrObject
* pObj
)
1315 // Set the position of the textboxes according to the position of its shape-pair
1316 const bool bIsGroupObj
= (pObj
!= pShape
->FindRealSdrObject()) && pObj
;
1317 if (auto pFormat
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
))
1319 // Do not create undo entry for the positioning
1320 ::sw::UndoGuard
const UndoGuard(pShape
->GetDoc()->GetIDocumentUndoRedo());
1321 auto aGuard
= SwTextBoxLockGuard(*pShape
->GetOtherTextBoxFormats());
1322 // Special treatment for AS_CHAR textboxes:
1323 if (pShape
->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
1325 // Get the text area of the shape
1326 tools::Rectangle aRect
1327 = getRelativeTextRectangle(pObj
? pObj
: pShape
->FindRealSdrObject());
1329 // Get the left spacing of the text area of the shape
1330 auto nLeftSpace
= pShape
->GetLRSpace().GetLeft();
1332 // Set the textbox position at the X-axis:
1333 SwFormatHoriOrient
aNewHOri(pFormat
->GetHoriOrient());
1334 if (bIsGroupObj
&& aNewHOri
.GetHoriOrient() != text::HoriOrientation::NONE
)
1335 aNewHOri
.SetHoriOrient(text::HoriOrientation::NONE
);
1336 aNewHOri
.SetPos(aRect
.Left() + nLeftSpace
1337 + (bIsGroupObj
? pObj
->GetRelativePos().getX() : 0));
1338 SwFormatVertOrient
aNewVOri(pFormat
->GetVertOrient());
1340 // Special handling of group textboxes
1343 // There are the following cases:
1344 // case 1: The textbox should be in that position where the shape is.
1345 // case 2: The shape has negative offset so that have to be subtracted
1346 // case 3: The shape and its parent shape also has negative offset, so subtract
1348 ((pObj
->GetRelativePos().getY()) > 0
1349 ? (pShape
->GetVertOrient().GetPos() > 0
1350 ? pObj
->GetRelativePos().getY()
1351 : pObj
->GetRelativePos().getY() - pShape
->GetVertOrient().GetPos())
1352 : (pShape
->GetVertOrient().GetPos() > 0
1353 ? 0 // Is this can be a variation?
1354 : pObj
->GetRelativePos().getY() - pShape
->GetVertOrient().GetPos()))
1359 // Simple textboxes: vertical position equals to the vertical offset of the shape
1361 ((pShape
->GetVertOrient().GetPos()) > 0 ? pShape
->GetVertOrient().GetPos() : 0)
1365 // Special cases when the shape is aligned to the line
1366 if (pShape
->GetVertOrient().GetVertOrient() != text::VertOrientation::NONE
)
1368 aNewVOri
.SetVertOrient(text::VertOrientation::NONE
);
1369 switch (pShape
->GetVertOrient().GetVertOrient())
1371 // Top aligned shape
1372 case text::VertOrientation::TOP
:
1373 case text::VertOrientation::CHAR_TOP
:
1374 case text::VertOrientation::LINE_TOP
:
1376 aNewVOri
.SetPos(aNewVOri
.GetPos() - pShape
->GetFrameSize().GetHeight());
1379 // Bottom aligned shape
1380 case text::VertOrientation::BOTTOM
:
1381 case text::VertOrientation::CHAR_BOTTOM
:
1382 case text::VertOrientation::LINE_BOTTOM
:
1384 aNewVOri
.SetPos(aNewVOri
.GetPos() + pShape
->GetFrameSize().GetHeight());
1387 // Center aligned shape
1388 case text::VertOrientation::CENTER
:
1389 case text::VertOrientation::CHAR_CENTER
:
1390 case text::VertOrientation::LINE_CENTER
:
1392 aNewVOri
.SetPos(aNewVOri
.GetPos()
1393 + std::lroundf(pShape
->GetFrameSize().GetHeight() / 2));
1401 pFormat
->SetFormatAttr(aNewHOri
);
1402 pFormat
->SetFormatAttr(aNewVOri
);
1404 // Other cases when the shape has different anchor from AS_CHAR
1407 // Text area of the shape
1408 tools::Rectangle aRect
1409 = getRelativeTextRectangle(pObj
? pObj
: pShape
->FindRealSdrObject());
1411 // X Offset of the shape spacing
1412 auto nLeftSpace
= pShape
->GetLRSpace().GetLeft();
1414 // Set the same position as the (child) shape has
1415 SwFormatHoriOrient
aNewHOri(pShape
->GetHoriOrient());
1416 if (bIsGroupObj
&& aNewHOri
.GetHoriOrient() != text::HoriOrientation::NONE
)
1417 aNewHOri
.SetHoriOrient(text::HoriOrientation::NONE
);
1420 (bIsGroupObj
&& pObj
? pObj
->GetRelativePos().getX() : aNewHOri
.GetPos())
1422 SwFormatVertOrient
aNewVOri(pShape
->GetVertOrient());
1424 (bIsGroupObj
&& pObj
? pObj
->GetRelativePos().getY() : aNewVOri
.GetPos())
1427 // Get the distance of the child shape inside its parent
1428 const auto& nInshapePos
1429 = pObj
? pObj
->GetRelativePos() - pShape
->FindRealSdrObject()->GetRelativePos()
1432 // Special case: the shape has relative position from the page
1433 if (pShape
->GetHoriOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME
1434 && pShape
->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_PAGE
)
1436 aNewHOri
.SetRelationOrient(text::RelOrientation::PAGE_FRAME
);
1437 aNewHOri
.SetPos(pShape
->GetHoriOrient().GetPos() + nInshapePos
.getX()
1441 if (pShape
->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME
1442 && pShape
->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_PAGE
)
1444 aNewVOri
.SetRelationOrient(text::RelOrientation::PAGE_FRAME
);
1445 aNewVOri
.SetPos(pShape
->GetVertOrient().GetPos() + nInshapePos
.getY()
1449 // Other special case: shape is inside a table or floating table following the text flow
1450 if (pShape
->GetFollowTextFlow().GetValue() && pShape
->GetAnchor().GetAnchorNode()
1451 && pShape
->GetAnchor().GetAnchorNode()->FindTableNode())
1457 = pShape
->GetAnchor().GetAnchorNode()->FindTableNode()->FindFlyStartNode())
1459 if (auto pFlyFormat
= pFly
->GetFlyFormat())
1461 nTableOffset
.setX(pFlyFormat
->GetHoriOrient().GetPos());
1462 nTableOffset
.setY(pFlyFormat
->GetVertOrient().GetPos());
1468 auto pTableNode
= pShape
->GetAnchor().GetAnchorNode()->FindTableNode();
1469 if (auto pTableFormat
= pTableNode
->GetTable().GetFrameFormat())
1471 nTableOffset
.setX(pTableFormat
->GetHoriOrient().GetPos());
1472 nTableOffset
.setY(pTableFormat
->GetVertOrient().GetPos());
1476 // Add the table positions to the textbox.
1477 aNewHOri
.SetPos(aNewHOri
.GetPos() + nTableOffset
.getX() + nLeftSpace
);
1478 if (pShape
->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME
1479 || pShape
->GetVertOrient().GetRelationOrient()
1480 == text::RelOrientation::PAGE_PRINT_AREA
)
1481 aNewVOri
.SetPos(aNewVOri
.GetPos() + nTableOffset
.getY());
1484 pFormat
->SetFormatAttr(aNewHOri
);
1485 pFormat
->SetFormatAttr(aNewVOri
);
1493 bool SwTextBoxHelper::syncTextBoxSize(SwFrameFormat
* pShape
, SdrObject
* pObj
)
1495 if (!pShape
|| !pObj
)
1498 if (auto pTextBox
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
))
1500 auto aGuard
= SwTextBoxLockGuard(*pShape
->GetOtherTextBoxFormats());
1501 const auto& rSize
= getRelativeTextRectangle(pObj
).GetSize();
1502 if (!rSize
.IsEmpty())
1504 SwFormatFrameSize
aSize(pTextBox
->GetFrameSize());
1505 aSize
.SetSize(rSize
);
1506 return pTextBox
->SetFormatAttr(aSize
);
1513 bool SwTextBoxHelper::DoTextBoxZOrderCorrection(SwFrameFormat
* pShape
, const SdrObject
* pObj
)
1515 // TODO: do this with group shape textboxes.
1516 SdrObject
* pShpObj
= nullptr;
1518 pShpObj
= pShape
->FindRealSdrObject();
1522 auto pTextBox
= getOtherTextBoxFormat(pShape
, RES_DRAWFRMFMT
, pObj
);
1525 SdrObject
* pFrmObj
= pTextBox
->FindRealSdrObject();
1528 // During loading there is no ready SdrObj for z-ordering, so create and cache it here
1530 = SwXTextFrame::GetOrCreateSdrObject(*dynamic_cast<SwFlyFrameFormat
*>(pTextBox
));
1534 // Get the draw model from the doc
1535 SwDrawModel
* pDrawModel
1536 = pShape
->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1539 // Not really sure this will work on all pages, but it seems it will.
1540 auto pPage
= pDrawModel
->GetPage(0);
1541 // Recalc all Z-orders
1542 pPage
->RecalcObjOrdNums();
1543 // Here is a counter avoiding running to in infinity:
1544 sal_uInt16 nIterator
= 0;
1545 // If the shape is behind the frame, is good, but if there are some objects
1546 // between of them that is wrong so put the frame exactly one level higher
1548 if (pFrmObj
->GetOrdNum() > pShpObj
->GetOrdNum())
1549 pPage
->SetObjectOrdNum(pFrmObj
->GetOrdNum(), pShpObj
->GetOrdNum() + 1);
1551 // Else, if the frame is behind the shape, bring to the front of it.
1552 while (pFrmObj
->GetOrdNum() <= pShpObj
->GetOrdNum())
1554 pPage
->SetObjectOrdNum(pFrmObj
->GetOrdNum(), pFrmObj
->GetOrdNum() + 1);
1555 // If there is any problem with the indexes, do not run over the infinity
1556 if (pPage
->GetObjCount() == pFrmObj
->GetOrdNum())
1559 if (nIterator
> 300)
1560 break; // Do not run to infinity
1562 pPage
->RecalcObjOrdNums();
1563 return true; // Success
1565 SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1566 "No Valid Draw model for SdrObject for the shape!");
1568 SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1569 "No Valid SdrObject for the frame!");
1571 SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1572 "No Valid SdrObject for the shape!");
1577 void SwTextBoxHelper::synchronizeGroupTextBoxProperty(bool pFunc(SwFrameFormat
*, SdrObject
*),
1578 SwFrameFormat
* pFormat
, SdrObject
* pObj
)
1580 if (auto pChildren
= pObj
->getChildrenOfSdrObject())
1582 for (size_t i
= 0; i
< pChildren
->GetObjCount(); ++i
)
1583 synchronizeGroupTextBoxProperty(pFunc
, pFormat
, pChildren
->GetObj(i
));
1587 (*pFunc
)(pFormat
, pObj
);
1591 std::vector
<SwFrameFormat
*> SwTextBoxHelper::CollectTextBoxes(const SdrObject
* pGroupObject
,
1592 SwFrameFormat
* pFormat
)
1594 std::vector
<SwFrameFormat
*> vRet
;
1595 if (auto pChildren
= pGroupObject
->getChildrenOfSdrObject())
1597 for (size_t i
= 0; i
< pChildren
->GetObjCount(); ++i
)
1599 auto pChildTextBoxes
= CollectTextBoxes(pChildren
->GetObj(i
), pFormat
);
1600 for (auto& rChildTextBox
: pChildTextBoxes
)
1601 vRet
.push_back(rChildTextBox
);
1606 if (isTextBox(pFormat
, RES_DRAWFRMFMT
, pGroupObject
))
1607 vRet
.push_back(getOtherTextBoxFormat(pFormat
, RES_DRAWFRMFMT
, pGroupObject
));
1612 bool SwTextBoxHelper::isAnchorSyncNeeded(const SwFrameFormat
* pFirst
, const SwFrameFormat
* pSecond
)
1620 if (pFirst
== pSecond
)
1623 if (!pFirst
->GetOtherTextBoxFormats())
1626 if (!pSecond
->GetOtherTextBoxFormats())
1629 if (pFirst
->GetOtherTextBoxFormats() != pSecond
->GetOtherTextBoxFormats())
1632 if (pFirst
->GetOtherTextBoxFormats()->GetOwnerShape() == pSecond
1633 || pFirst
== pSecond
->GetOtherTextBoxFormats()->GetOwnerShape())
1635 const auto& rShapeAnchor
1636 = pFirst
->Which() == RES_DRAWFRMFMT
? pFirst
->GetAnchor() : pSecond
->GetAnchor();
1637 const auto& rFrameAnchor
1638 = pFirst
->Which() == RES_FLYFRMFMT
? pFirst
->GetAnchor() : pSecond
->GetAnchor();
1640 if (rShapeAnchor
.GetAnchorId() == rFrameAnchor
.GetAnchorId())
1642 if (rShapeAnchor
.GetAnchorNode() && rFrameAnchor
.GetAnchorNode())
1644 if (*rShapeAnchor
.GetContentAnchor() != *rFrameAnchor
.GetContentAnchor())
1650 if (rShapeAnchor
.GetAnchorId() == RndStdIds::FLY_AT_PAGE
1651 && rFrameAnchor
.GetAnchorId() == RndStdIds::FLY_AT_PAGE
)
1653 if (rShapeAnchor
.GetPageNum() == rFrameAnchor
.GetPageNum())
1662 if (rShapeAnchor
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
1663 && rFrameAnchor
.GetAnchorId() == RndStdIds::FLY_AT_CHAR
)
1665 if (rShapeAnchor
.GetAnchorNode() && rFrameAnchor
.GetAnchorNode())
1667 if (*rShapeAnchor
.GetContentAnchor() != *rFrameAnchor
.GetContentAnchor())
1678 SwTextBoxNode::SwTextBoxNode(SwFrameFormat
* pOwnerShape
)
1680 assert(pOwnerShape
);
1681 assert(pOwnerShape
->Which() == RES_DRAWFRMFMT
);
1683 m_bIsCloningInProgress
= false;
1686 m_pOwnerShapeFormat
= pOwnerShape
;
1687 if (!m_pTextBoxes
.empty())
1688 m_pTextBoxes
.clear();
1691 SwTextBoxNode::~SwTextBoxNode()
1693 if (m_pTextBoxes
.size() != 0)
1695 SAL_WARN("sw.core", "SwTextBoxNode::~SwTextBoxNode(): Text-Box-Vector still not empty!");
1700 void SwTextBoxNode::AddTextBox(SdrObject
* pDrawObject
, SwFrameFormat
* pNewTextBox
)
1702 assert(pNewTextBox
);
1703 assert(pNewTextBox
->Which() == RES_FLYFRMFMT
);
1705 assert(pDrawObject
);
1707 SwTextBoxElement aElem
;
1708 aElem
.m_pDrawObject
= pDrawObject
;
1709 aElem
.m_pTextBoxFormat
= pNewTextBox
;
1711 for (const auto& rE
: m_pTextBoxes
)
1713 if (rE
.m_pDrawObject
== pDrawObject
|| rE
.m_pTextBoxFormat
== pNewTextBox
)
1715 SAL_WARN("sw.core", "SwTextBoxNode::AddTextBox(): Already exist!");
1720 auto pSwFlyDraw
= dynamic_cast<SwFlyDrawObj
*>(pDrawObject
);
1723 pSwFlyDraw
->SetTextBox(true);
1725 m_pTextBoxes
.push_back(aElem
);
1728 void SwTextBoxNode::DelTextBox(const SdrObject
* pDrawObject
, bool bDelFromDoc
)
1730 assert(pDrawObject
);
1731 if (m_pTextBoxes
.empty())
1734 for (auto it
= m_pTextBoxes
.begin(); it
!= m_pTextBoxes
.end();)
1736 if (it
->m_pDrawObject
== pDrawObject
)
1740 it
->m_pTextBoxFormat
->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
1741 it
->m_pTextBoxFormat
);
1742 // What about m_pTextBoxes? So, when the DelLayoutFormat() removes the format
1743 // then the ~SwFrameFormat() will call this method again to remove the entry.
1748 it
= m_pTextBoxes
.erase(it
);
1755 SAL_WARN("sw.core", "SwTextBoxNode::DelTextBox(): Not found!");
1758 void SwTextBoxNode::DelTextBox(const SwFrameFormat
* pTextBox
, bool bDelFromDoc
)
1760 if (m_pTextBoxes
.empty())
1763 for (auto it
= m_pTextBoxes
.begin(); it
!= m_pTextBoxes
.end();)
1765 if (it
->m_pTextBoxFormat
== pTextBox
)
1769 it
->m_pTextBoxFormat
->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
1770 it
->m_pTextBoxFormat
);
1771 // What about m_pTextBoxes? So, when the DelLayoutFormat() removes the format
1772 // then the ~SwFrameFormat() will call this method again to remove the entry.
1777 it
= m_pTextBoxes
.erase(it
);
1784 SAL_WARN("sw.core", "SwTextBoxNode::DelTextBox(): Not found!");
1787 SwFrameFormat
* SwTextBoxNode::GetTextBox(const SdrObject
* pDrawObject
) const
1789 assert(pDrawObject
);
1790 assert(m_pOwnerShapeFormat
);
1792 if (auto& pTextBoxes
= m_pOwnerShapeFormat
->GetOtherTextBoxFormats())
1794 if (size_t(pTextBoxes
.use_count()) != pTextBoxes
->GetTextBoxCount() + size_t(1))
1796 SAL_WARN("sw.core", "SwTextBoxNode::GetTextBox(): RefCount and TexBox count mismatch!");
1803 if (!m_pTextBoxes
.empty())
1805 for (auto it
= m_pTextBoxes
.begin(); it
!= m_pTextBoxes
.end(); it
++)
1807 if (it
->m_pDrawObject
== pDrawObject
)
1809 return it
->m_pTextBoxFormat
;
1812 SAL_WARN("sw.core", "SwTextBoxNode::GetTextBox(): Not found!");
1818 void SwTextBoxNode::ClearAll()
1820 // If this called from ~SwDoc(), then only the address entries
1821 // have to be removed, the format will be deleted by the
1822 // the mpSpzFrameFormatTable->DeleteAndDestroyAll() in ~SwDoc()!
1823 if (m_pOwnerShapeFormat
->GetDoc()->IsInDtor())
1825 m_pTextBoxes
.clear();
1830 sal_uInt16 nLoopCount
= 0;
1832 // Reference not enough, copy needed.
1833 const size_t nTextBoxCount
= m_pTextBoxes
.size();
1835 // For loop has problems: When one entry deleted, the iterator has
1836 // to be refreshed according to the new situation. So using While() instead.
1837 while (!m_pTextBoxes
.empty())
1839 // Delete the last textbox of the vector from the doc
1840 // (what will call deregister in ~SwFrameFormat()
1841 m_pOwnerShapeFormat
->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
1842 m_pTextBoxes
.back().m_pTextBoxFormat
);
1844 // Check if we are looping
1845 if (nLoopCount
> (nTextBoxCount
+ 1))
1847 SAL_WARN("sw.core", "SwTextBoxNode::ClearAll(): Maximum loop count reached!");
1856 // Ensure the vector is empty.
1857 if (!m_pTextBoxes
.empty())
1859 SAL_WARN("sw.core", "SwTextBoxNode::ClearAll(): Text-Box-Vector still not empty!");
1864 bool SwTextBoxNode::IsGroupTextBox() const { return m_pTextBoxes
.size() > 1; }
1866 std::map
<SdrObject
*, SwFrameFormat
*> SwTextBoxNode::GetAllTextBoxes() const
1868 std::map
<SdrObject
*, SwFrameFormat
*> aRet
;
1869 for (auto& rElem
: m_pTextBoxes
)
1871 aRet
.emplace(rElem
.m_pDrawObject
, rElem
.m_pTextBoxFormat
);
1876 void SwTextBoxNode::Clone(SwDoc
* pDoc
, const SwFormatAnchor
& rNewAnc
, SwFrameFormat
* o_pTarget
,
1877 bool bSetAttr
, bool bMakeFrame
) const
1879 if (!o_pTarget
|| !pDoc
)
1882 if (o_pTarget
->Which() != RES_DRAWFRMFMT
)
1885 if (m_bIsCloningInProgress
)
1888 m_bIsCloningInProgress
= true;
1890 Clone_Impl(pDoc
, rNewAnc
, o_pTarget
, m_pOwnerShapeFormat
->FindSdrObject(),
1891 o_pTarget
->FindSdrObject(), bSetAttr
, bMakeFrame
);
1893 m_bIsCloningInProgress
= false;
1895 for (auto& rElem
: m_pTextBoxes
)
1897 SwTextBoxHelper::changeAnchor(m_pOwnerShapeFormat
, rElem
.m_pDrawObject
);
1898 SwTextBoxHelper::doTextBoxPositioning(m_pOwnerShapeFormat
, rElem
.m_pDrawObject
);
1899 SwTextBoxHelper::DoTextBoxZOrderCorrection(m_pOwnerShapeFormat
, rElem
.m_pDrawObject
);
1900 SwTextBoxHelper::syncTextBoxSize(m_pOwnerShapeFormat
, rElem
.m_pDrawObject
);
1904 void SwTextBoxNode::Clone_Impl(SwDoc
* pDoc
, const SwFormatAnchor
& rNewAnc
, SwFrameFormat
* o_pTarget
,
1905 const SdrObject
* pSrcObj
, SdrObject
* pDestObj
, bool bSetAttr
,
1906 bool bMakeFrame
) const
1908 if (!pSrcObj
|| !pDestObj
)
1911 auto pSrcList
= pSrcObj
->getChildrenOfSdrObject();
1912 auto pDestList
= pDestObj
->getChildrenOfSdrObject();
1914 if (pSrcList
&& pDestList
)
1916 if (pSrcList
->GetObjCount() != pDestList
->GetObjCount())
1918 SAL_WARN("sw.core", "SwTextBoxNode::Clone_Impl(): Difference between the shapes!");
1922 for (size_t i
= 0; i
< pSrcList
->GetObjCount(); ++i
)
1924 Clone_Impl(pDoc
, rNewAnc
, o_pTarget
, pSrcList
->GetObj(i
), pDestList
->GetObj(i
),
1925 bSetAttr
, bMakeFrame
);
1930 if (!pSrcList
&& !pDestList
)
1932 if (auto pSrcFormat
= GetTextBox(pSrcObj
))
1934 SwFormatAnchor
aNewAnchor(rNewAnc
);
1935 if (aNewAnchor
.GetAnchorId() == RndStdIds::FLY_AS_CHAR
)
1937 aNewAnchor
.SetType(RndStdIds::FLY_AT_CHAR
);
1943 if (auto pTargetFormat
= pDoc
->getIDocumentLayoutAccess().CopyLayoutFormat(
1944 *pSrcFormat
, aNewAnchor
, bSetAttr
, bMakeFrame
))
1946 if (!o_pTarget
->GetOtherTextBoxFormats())
1948 auto pNewTextBoxes
= std::make_shared
<SwTextBoxNode
>(SwTextBoxNode(o_pTarget
));
1949 o_pTarget
->SetOtherTextBoxFormats(pNewTextBoxes
);
1950 pNewTextBoxes
->AddTextBox(pDestObj
, pTargetFormat
);
1951 pTargetFormat
->SetOtherTextBoxFormats(pNewTextBoxes
);
1955 o_pTarget
->GetOtherTextBoxFormats()->AddTextBox(pDestObj
, pTargetFormat
);
1956 pTargetFormat
->SetOtherTextBoxFormats(o_pTarget
->GetOtherTextBoxFormats());
1958 o_pTarget
->SetFormatAttr(pTargetFormat
->GetContent());
1964 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */