LibreOffice Module sw (master)  1
textboxhelper.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  */
9 
10 #include <textboxhelper.hxx>
11 #include <fmtcntnt.hxx>
12 #include <fmtanchr.hxx>
13 #include <fmtcnct.hxx>
14 #include <fmtornt.hxx>
15 #include <fmtfsize.hxx>
16 #include <doc.hxx>
18 #include <IDocumentState.hxx>
19 #include <docsh.hxx>
20 #include <unocoll.hxx>
21 #include <unoframe.hxx>
22 #include <unodraw.hxx>
23 #include <unotextrange.hxx>
24 #include <cmdid.h>
25 #include <unomid.h>
26 #include <unoprnms.hxx>
27 #include <mvsave.hxx>
28 #include <fmtsrnd.hxx>
29 #include <fmtfollowtextflow.hxx>
30 #include <frmfmt.hxx>
31 #include <frameformats.hxx>
32 #include <dflyobj.hxx>
33 #include <swtable.hxx>
34 
35 #include <editeng/unoprnms.hxx>
36 #include <editeng/memberids.h>
37 #include <svx/svdoashp.hxx>
38 #include <svx/svdpage.hxx>
39 #include <svx/svdogrp.hxx>
40 #include <svl/itemiter.hxx>
42 #include <sal/log.hxx>
43 #include <tools/UnitConversion.hxx>
44 #include <svx/swframetypes.hxx>
45 #include <drawdoc.hxx>
46 #include <IDocumentUndoRedo.hxx>
48 #include <frmatr.hxx>
49 
50 #include <com/sun/star/document/XActionLockable.hpp>
51 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
52 #include <com/sun/star/text/SizeType.hpp>
53 #include <com/sun/star/text/WrapTextMode.hpp>
54 #include <com/sun/star/text/XTextDocument.hpp>
55 #include <com/sun/star/text/XTextFrame.hpp>
56 #include <com/sun/star/table/BorderLine2.hpp>
57 #include <com/sun/star/text/WritingMode.hpp>
58 #include <com/sun/star/text/WritingMode2.hpp>
59 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
60 #include <com/sun/star/style/ParagraphAdjust.hpp>
61 
62 using namespace com::sun::star;
63 
64 void SwTextBoxHelper::create(SwFrameFormat* pShape, SdrObject* pObject, bool bCopyText)
65 {
66  assert(pShape);
67  assert(pObject);
68 
69  const bool bIsGroupObj = dynamic_cast<SdrObjGroup*>(pObject->getParentSdrObjectFromSdrObject());
70 
71  // If TextBox wasn't enabled previously
72  if (pShape->GetOtherTextBoxFormats() && pShape->GetOtherTextBoxFormats()->GetTextBox(pObject))
73  return;
74 
75  // Store the current text content of the shape
76  OUString sCopyableText;
77 
78  if (bCopyText)
79  {
80  if (pObject)
81  {
82  uno::Reference<text::XText> xSrcCnt(pObject->getWeakUnoShape().get(), uno::UNO_QUERY);
83  auto xCur = xSrcCnt->createTextCursor();
84  xCur->gotoStart(false);
85  xCur->gotoEnd(true);
86  sCopyableText = xCur->getText()->getString();
87  }
88  }
89 
90  // Create the associated TextFrame and insert it into the document.
91  uno::Reference<text::XTextContent> xTextFrame(
93  uno::UNO_QUERY);
94  uno::Reference<text::XTextDocument> xTextDocument(
95  pShape->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
96  uno::Reference<text::XTextContentAppend> xTextContentAppend(xTextDocument->getText(),
97  uno::UNO_QUERY);
98  try
99  {
100  uno::Reference<text::XTextContent> XSourceShape(pObject->getUnoShape(),
101  uno::UNO_QUERY_THROW);
102  xTextContentAppend->insertTextContentWithProperties(
103  xTextFrame, uno::Sequence<beans::PropertyValue>(), XSourceShape->getAnchor());
104  }
105  catch (uno::Exception&)
106  {
107  xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>());
108  }
109  // Link FLY and DRAW formats, so it becomes a text box (needed for syncProperty calls).
110  uno::Reference<text::XTextFrame> xRealTextFrame(xTextFrame, uno::UNO_QUERY);
111  auto pTextFrame = dynamic_cast<SwXTextFrame*>(xRealTextFrame.get());
112  assert(nullptr != pTextFrame);
113  SwFrameFormat* pFormat = pTextFrame->GetFrameFormat();
114 
115  assert(nullptr != dynamic_cast<SwDrawFrameFormat*>(pShape));
116  assert(nullptr != dynamic_cast<SwFlyFrameFormat*>(pFormat));
117 
118  if (!pShape->GetOtherTextBoxFormats())
119  {
120  auto pTextBox = std::make_shared<SwTextBoxNode>(SwTextBoxNode(pShape));
121  pTextBox->AddTextBox(pObject, pFormat);
122  pShape->SetOtherTextBoxFormats(pTextBox);
123  pFormat->SetOtherTextBoxFormats(pTextBox);
124  }
125  else
126  {
127  auto pTextBox = pShape->GetOtherTextBoxFormats();
128  pTextBox->AddTextBox(pObject, pFormat);
129  pShape->SetOtherTextBoxFormats(pTextBox);
130  pFormat->SetOtherTextBoxFormats(pTextBox);
131  }
132  // Initialize properties.
133  uno::Reference<beans::XPropertySet> xPropertySet(xTextFrame, uno::UNO_QUERY);
134  uno::Any aEmptyBorder{ table::BorderLine2() };
135  xPropertySet->setPropertyValue(UNO_NAME_TOP_BORDER, aEmptyBorder);
136  xPropertySet->setPropertyValue(UNO_NAME_BOTTOM_BORDER, aEmptyBorder);
137  xPropertySet->setPropertyValue(UNO_NAME_LEFT_BORDER, aEmptyBorder);
138  xPropertySet->setPropertyValue(UNO_NAME_RIGHT_BORDER, aEmptyBorder);
139 
140  xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::Any(sal_Int32(100)));
141 
142  xPropertySet->setPropertyValue(UNO_NAME_SIZE_TYPE, uno::Any(text::SizeType::FIX));
143 
144  xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::Any(text::WrapTextMode_THROUGH));
145 
146  uno::Reference<container::XNamed> xNamed(xTextFrame, uno::UNO_QUERY);
147  xNamed->setName(pShape->GetDoc()->GetUniqueFrameName());
148 
149  // Link its text range to the original shape.
150  uno::Reference<text::XTextRange> xTextBox(xTextFrame, uno::UNO_QUERY_THROW);
151  SwUnoInternalPaM aInternalPaM(*pShape->GetDoc());
152  if (sw::XTextRangeToSwPaM(aInternalPaM, xTextBox))
153  {
154  SwAttrSet aSet(pShape->GetAttrSet());
155  SwFormatContent aContent(aInternalPaM.GetNode().StartOfSectionNode());
156  aSet.Put(aContent);
157  pShape->SetFormatAttr(aSet);
158  }
159 
160  DoTextBoxZOrderCorrection(pShape, pObject);
161 
162  // Also initialize the properties, which are not constant, but inherited from the shape's ones.
163  uno::Reference<drawing::XShape> xShape(pObject->getUnoShape(), uno::UNO_QUERY);
164  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any(xShape->getSize()), pObject);
165 
166  uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
167  syncProperty(pShape, RES_FOLLOW_TEXT_FLOW, MID_FOLLOW_TEXT_FLOW,
168  xShapePropertySet->getPropertyValue(UNO_NAME_IS_FOLLOWING_TEXT_FLOW), pObject);
169  syncProperty(pShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
170  xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE), pObject);
171  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
172  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT), pObject);
173  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
174  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION), pObject);
175  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
176  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT), pObject);
177  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
178  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION), pObject);
179  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
180  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION), pObject);
181  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
182  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION), pObject);
183  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
184  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT), pObject);
185  syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0,
186  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST), pObject);
187  text::WritingMode eMode;
188  if (xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE) >>= eMode)
189  syncProperty(pShape, RES_FRAMEDIR, 0, uno::Any(sal_Int16(eMode)), pObject);
190 
191  if (bIsGroupObj)
192  doTextBoxPositioning(pShape, pObject);
193 
194  // Check if the shape had text before and move it to the new textframe
195  if (!bCopyText || sCopyableText.isEmpty())
196  return;
197 
198  if (pObject)
199  {
200  auto pSourceText = dynamic_cast<SdrTextObj*>(pObject);
201  uno::Reference<text::XTextRange> xDestText(xRealTextFrame, uno::UNO_QUERY);
202 
203  xDestText->setString(sCopyableText);
204 
205  if (pSourceText)
206  pSourceText->SetText(OUString());
207 
208  pShape->GetDoc()->getIDocumentState().SetModified();
209  }
210 }
211 
212 void SwTextBoxHelper::set(SwFrameFormat* pShapeFormat, SdrObject* pObj,
213  uno::Reference<text::XTextFrame> xNew)
214 {
215  // Do not set invalid data
216  assert(pShapeFormat && pObj && xNew);
217  // Firstly find the format of the new textbox.
218  SwFrameFormat* pFormat = nullptr;
219  if (auto pTextFrame = dynamic_cast<SwXTextFrame*>(xNew.get()))
220  pFormat = pTextFrame->GetFrameFormat();
221  if (!pFormat)
222  return;
223  std::vector<std::pair<beans::Property, uno::Any>> aOldProps;
224  // If there is a format, check if the shape already has a textbox assigned to.
225  if (auto pTextBoxNode = pShapeFormat->GetOtherTextBoxFormats())
226  {
227  // If it has a texbox, destroy it.
228  if (pTextBoxNode->GetTextBox(pObj))
229  {
230  auto xOldFrame
231  = pObj->getUnoShape()->queryInterface(cppu::UnoType<text::XTextRange>::get());
232  if (xOldFrame.hasValue())
233  {
234  uno::Reference<beans::XPropertySet> xOldprops(xOldFrame, uno::UNO_QUERY);
235  uno::Reference<beans::XPropertyState> xOldPropStates(xOldFrame, uno::UNO_QUERY);
236  for (auto& rProp : xOldprops->getPropertySetInfo()->getProperties())
237  {
238  try
239  {
240  if (xOldPropStates->getPropertyState(rProp.Name)
241  == beans::PropertyState::PropertyState_DIRECT_VALUE)
242  aOldProps.push_back(
243  std::pair(rProp, xOldprops->getPropertyValue(rProp.Name)));
244  }
245  catch (...)
246  {
247  }
248  }
249  }
250  destroy(pShapeFormat, pObj);
251  }
252  // And set the new one.
253  pTextBoxNode->AddTextBox(pObj, pFormat);
254  pFormat->SetOtherTextBoxFormats(pTextBoxNode);
255  }
256  else
257  {
258  // If the shape do not have a texbox node and textbox,
259  // create that for the shape.
260  auto pTextBox = std::shared_ptr<SwTextBoxNode>(new SwTextBoxNode(pShapeFormat));
261  pTextBox->AddTextBox(pObj, pFormat);
262  pShapeFormat->SetOtherTextBoxFormats(pTextBox);
263  pFormat->SetOtherTextBoxFormats(pTextBox);
264  }
265  // Initialize its properties
266  uno::Reference<beans::XPropertySet> xPropertySet(xNew, uno::UNO_QUERY);
267  uno::Any aEmptyBorder{ table::BorderLine2() };
268  xPropertySet->setPropertyValue(UNO_NAME_TOP_BORDER, aEmptyBorder);
269  xPropertySet->setPropertyValue(UNO_NAME_BOTTOM_BORDER, aEmptyBorder);
270  xPropertySet->setPropertyValue(UNO_NAME_LEFT_BORDER, aEmptyBorder);
271  xPropertySet->setPropertyValue(UNO_NAME_RIGHT_BORDER, aEmptyBorder);
272  xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::Any(sal_Int32(100)));
273  xPropertySet->setPropertyValue(UNO_NAME_SIZE_TYPE, uno::Any(text::SizeType::FIX));
274  xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::Any(text::WrapTextMode_THROUGH));
275  // Add a new name to it
276  uno::Reference<container::XNamed> xNamed(xNew, uno::UNO_QUERY);
277  xNamed->setName(pShapeFormat->GetDoc()->GetUniqueFrameName());
278  // And sync. properties.
279  uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
280  syncProperty(pShapeFormat, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any(xShape->getSize()), pObj);
281  uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
282  syncProperty(pShapeFormat, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
283  xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE), pObj);
284  syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
285  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT), pObj);
286  syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
287  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION), pObj);
288  syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
289  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT), pObj);
290  syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
291  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION), pObj);
292  syncProperty(pShapeFormat, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
293  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION), pObj);
294  syncProperty(pShapeFormat, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
295  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION), pObj);
296  syncProperty(pShapeFormat, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
297  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT), pObj);
298  drawing::TextVerticalAdjust aVertAdj = drawing::TextVerticalAdjust_CENTER;
299  if ((uno::Reference<beans::XPropertyState>(xShape, uno::UNO_QUERY_THROW))
300  ->getPropertyState(UNO_NAME_TEXT_VERT_ADJUST)
301  != beans::PropertyState::PropertyState_DEFAULT_VALUE)
302  {
303  aVertAdj = xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST)
304  .get<drawing::TextVerticalAdjust>();
305  }
306  xPropertySet->setPropertyValue(UNO_NAME_TEXT_VERT_ADJUST, uno::Any(aVertAdj));
307  text::WritingMode eMode;
308  if (xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE) >>= eMode)
309  syncProperty(pShapeFormat, RES_FRAMEDIR, 0, uno::Any(sal_Int16(eMode)), pObj);
310  if (aOldProps.size())
311  {
312  for (auto& rProp : aOldProps)
313  {
314  try
315  {
316  xPropertySet->setPropertyValue(rProp.first.Name, rProp.second);
317  }
318  catch (...)
319  {
320  }
321  }
322  }
323  if (pFormat->GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
324  && pFormat->GetAnchor().GetPageNum() == 0)
325  {
326  pFormat->SetFormatAttr(SwFormatAnchor(RndStdIds::FLY_AT_PAGE, 1));
327  }
328  // Do sync for the new textframe.
329  synchronizeGroupTextBoxProperty(&changeAnchor, pShapeFormat, pObj);
330  synchronizeGroupTextBoxProperty(&syncTextBoxSize, pShapeFormat, pObj);
331 
332  updateTextBoxMargin(pObj);
333 }
334 
335 void SwTextBoxHelper::destroy(const SwFrameFormat* pShape, const SdrObject* pObject)
336 {
337  // If a TextBox was enabled previously
338  auto pTextBox = pShape->GetOtherTextBoxFormats();
339  if (pTextBox && pTextBox->IsTextBoxActive(pObject))
340  {
341  // Unlink the TextBox's text range from the original shape.
342  pTextBox->SetTextBoxInactive(pObject);
343 
344  // Delete the associated TextFrame.
345  pTextBox->DelTextBox(pObject, true);
346  }
347 }
348 
349 bool SwTextBoxHelper::isTextBox(const SwFrameFormat* pFormat, sal_uInt16 nType,
350  const SdrObject* pObject)
351 {
352  SolarMutexGuard aGuard;
353  assert(nType == RES_FLYFRMFMT || nType == RES_DRAWFRMFMT);
354  if (!pFormat || pFormat->Which() != nType)
355  return false;
356 
357  auto pTextBox = pFormat->GetOtherTextBoxFormats();
358  if (!pTextBox)
359  return false;
360 
361  if (nType == RES_DRAWFRMFMT)
362  {
363  if (pObject)
364  return pTextBox->GetTextBox(pObject);
365  if (auto pObj = pFormat->FindRealSdrObject())
366  return pTextBox->GetTextBox(pObj);
367  }
368 
369  if (nType == RES_FLYFRMFMT)
370  {
371  return pTextBox->GetOwnerShape();
372  }
373 
374  return false;
375 }
376 
378 {
379  if (!pObj)
380  return false;
381 
382  uno::Reference<drawing::XShape> xShape(pObj->getWeakUnoShape().get(), uno::UNO_QUERY);
383  if (!xShape)
384  return false;
386 }
387 
388 sal_Int32 SwTextBoxHelper::getCount(SdrPage const* pPage)
389 {
390  sal_Int32 nRet = 0;
391  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
392  {
393  SdrObject* p = pPage->GetObj(i);
394  if (p && p->IsTextBox())
395  continue;
396  ++nRet;
397  }
398  return nRet;
399 }
400 
401 sal_Int32 SwTextBoxHelper::getCount(const SwDoc& rDoc)
402 {
403  sal_Int32 nRet = 0;
404  const SwFrameFormats& rSpzFrameFormats = *rDoc.GetSpzFrameFormats();
405  for (const auto pFormat : rSpzFrameFormats)
406  {
407  if (isTextBox(pFormat, RES_FLYFRMFMT))
408  ++nRet;
409  }
410  return nRet;
411 }
412 
413 uno::Any SwTextBoxHelper::getByIndex(SdrPage const* pPage, sal_Int32 nIndex)
414 {
415  if (nIndex < 0)
416  throw lang::IndexOutOfBoundsException();
417 
418  SdrObject* pRet = nullptr;
419  sal_Int32 nCount = 0; // Current logical index.
420  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
421  {
422  SdrObject* p = pPage->GetObj(i);
423  if (p && p->IsTextBox())
424  continue;
425  if (nCount == nIndex)
426  {
427  pRet = p;
428  break;
429  }
430  ++nCount;
431  }
432 
433  if (!pRet)
434  throw lang::IndexOutOfBoundsException();
435 
436  return uno::Any(uno::Reference<drawing::XShape>(pRet->getUnoShape(), uno::UNO_QUERY));
437 }
438 
439 sal_Int32 SwTextBoxHelper::getOrdNum(const SdrObject* pObject)
440 {
441  if (const SdrPage* pPage = pObject->getSdrPageFromSdrObject())
442  {
443  sal_Int32 nOrder = 0; // Current logical order.
444  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
445  {
446  SdrObject* p = pPage->GetObj(i);
447  if (p && p->IsTextBox())
448  continue;
449  if (p == pObject)
450  return nOrder;
451  ++nOrder;
452  }
453  }
454 
455  SAL_WARN("sw.core", "SwTextBoxHelper::getOrdNum: no page or page doesn't contain the object");
456  return pObject->GetOrdNum();
457 }
458 
459 void SwTextBoxHelper::getShapeWrapThrough(const SwFrameFormat* pTextBox, bool& rWrapThrough)
460 {
462  if (pShape)
463  rWrapThrough = pShape->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
464 }
465 
467  sal_uInt16 nType, const SdrObject* pObject)
468 {
469  SolarMutexGuard aGuard;
470  if (!isTextBox(pFormat, nType, pObject))
471  return nullptr;
472 
473  if (nType == RES_DRAWFRMFMT)
474  {
475  if (pObject)
476  return pFormat->GetOtherTextBoxFormats()->GetTextBox(pObject);
477  if (pFormat->FindRealSdrObject())
478  return pFormat->GetOtherTextBoxFormats()->GetTextBox(pFormat->FindRealSdrObject());
479  return nullptr;
480  }
481  if (nType == RES_FLYFRMFMT)
482  {
483  return pFormat->GetOtherTextBoxFormats()->GetOwnerShape();
484  }
485  return nullptr;
486 }
487 
488 SwFrameFormat* SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference<drawing::XShape> const& xShape)
489 {
490  auto pShape = dynamic_cast<SwXShape*>(xShape.get());
491  if (!pShape)
492  return nullptr;
493 
494  SwFrameFormat* pFormat = pShape->GetFrameFormat();
495  return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT,
497 }
498 
499 uno::Reference<text::XTextFrame>
500 SwTextBoxHelper::getUnoTextFrame(uno::Reference<drawing::XShape> const& xShape)
501 {
502  if (xShape)
503  {
504  auto pFrameFormat = SwTextBoxHelper::getOtherTextBoxFormat(xShape);
505  if (pFrameFormat)
506  {
507  auto pSdrObj = pFrameFormat->FindSdrObject();
508  if (pSdrObj)
509  {
510  return { pSdrObj->getUnoShape(), uno::UNO_QUERY };
511  }
512  }
513  }
514  return {};
515 }
516 
517 template <typename T>
518 static void lcl_queryInterface(const SwFrameFormat* pShape, uno::Any& rAny, SdrObject* pObj)
519 {
520  if (SwFrameFormat* pFormat
522  {
523  uno::Reference<T> const xInterface(
524  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
525  rAny <<= xInterface;
526  }
527 }
528 
530  SdrObject* pObj)
531 {
532  uno::Any aRet;
533 
535  {
536  lcl_queryInterface<text::XTextAppend>(pShape, aRet, pObj);
537  }
538  else if (rType == cppu::UnoType<css::text::XText>::get())
539  {
540  lcl_queryInterface<text::XText>(pShape, aRet, pObj);
541  }
542  else if (rType == cppu::UnoType<css::text::XTextRange>::get())
543  {
544  lcl_queryInterface<text::XTextRange>(pShape, aRet, pObj);
545  }
546 
547  return aRet;
548 }
549 
551 {
552  tools::Rectangle aRet;
553  aRet.SetEmpty();
554 
555  assert(pShape);
556 
557  auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pShape);
558  if (pCustomShape)
559  {
560  // Need to temporarily release the lock acquired in
561  // SdXMLShapeContext::AddShape(), otherwise we get an empty rectangle,
562  // see EnhancedCustomShapeEngine::getTextBounds().
563  uno::Reference<document::XActionLockable> xLockable(pCustomShape->getUnoShape(),
564  uno::UNO_QUERY);
565  sal_Int16 nLocks = 0;
566  if (xLockable.is())
567  nLocks = xLockable->resetActionLocks();
568  pCustomShape->GetTextBounds(aRet);
569  if (nLocks)
570  xLockable->setActionLocks(nLocks);
571  }
572  else if (pShape)
573  {
574  // fallback - get *any* bound rect we can possibly get hold of
575  aRet = pShape->GetCurrentBoundRect();
576  }
577 
578  if (pShape)
579  {
580  // Relative, so count the logic (reference) rectangle, see the EnhancedCustomShape2d ctor.
581  Point aPoint(pShape->GetSnapRect().Center());
582  Size aSize(pShape->GetLogicRect().GetSize());
583  aPoint.AdjustX(-(aSize.Width() / 2));
584  aPoint.AdjustY(-(aSize.Height() / 2));
585  tools::Rectangle aLogicRect(aPoint, aSize);
586  aRet.Move(-1 * aLogicRect.Left(), -1 * aLogicRect.Top());
587  }
588 
589  return aRet;
590 }
591 
592 void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rPropertyName,
593  const css::uno::Any& rValue, SdrObject* pObj)
594 {
595  // Textframes does not have valid horizontal adjust property, so map it to paragraph adjust property
596  if (rPropertyName == UNO_NAME_TEXT_HORZADJUST)
597  {
598  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
599  if (!pFormat)
600  return;
601 
602  auto xTextFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat);
603  uno::Reference<text::XTextCursor> xCursor = xTextFrame->getText()->createTextCursor();
604 
605  // Select all paragraphs in the textframe
606  xCursor->gotoStart(false);
607  xCursor->gotoEnd(true);
608  uno::Reference<beans::XPropertySet> xFrameParaProps(xCursor, uno::UNO_QUERY);
609 
610  // And simply map the property
611  const auto eValue = rValue.get<drawing::TextHorizontalAdjust>();
612  switch (eValue)
613  {
614  case drawing::TextHorizontalAdjust::TextHorizontalAdjust_CENTER:
615  xFrameParaProps->setPropertyValue(
617  uno::Any(style::ParagraphAdjust::ParagraphAdjust_CENTER)); //3
618  break;
619  case drawing::TextHorizontalAdjust::TextHorizontalAdjust_LEFT:
620  xFrameParaProps->setPropertyValue(
622  uno::Any(style::ParagraphAdjust::ParagraphAdjust_LEFT)); //0
623  break;
624  case drawing::TextHorizontalAdjust::TextHorizontalAdjust_RIGHT:
625  xFrameParaProps->setPropertyValue(
627  uno::Any(style::ParagraphAdjust::ParagraphAdjust_RIGHT)); //1
628  break;
629  default:
630  SAL_WARN("sw.core",
631  "SwTextBoxHelper::syncProperty: unhandled TextHorizontalAdjust: "
632  << static_cast<sal_Int32>(eValue));
633  break;
634  }
635  return;
636  }
637 
638  if (rPropertyName == u"CustomShapeGeometry")
639  {
640  // CustomShapeGeometry changes the textbox position offset and size, so adjust both.
641  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any());
642 
643  SdrObject* pObject = pObj ? pObj : pShape->FindRealSdrObject();
644  if (pObject)
645  {
646  tools::Rectangle aRectangle(pObject->GetSnapRect());
647  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
648  uno::Any(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Left()))));
649  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
650  uno::Any(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Top()))));
651  }
652 
653  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
654  if (!pFormat)
655  return;
656 
657  comphelper::SequenceAsHashMap aCustomShapeGeometry(rValue);
658  auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
659  if (it == aCustomShapeGeometry.end())
660  {
661  it = aCustomShapeGeometry.find("TextRotateAngle");
662  }
663 
664  if (it != aCustomShapeGeometry.end())
665  {
666  auto nAngle = it->second.has<sal_Int32>() ? it->second.get<sal_Int32>() : 0;
667  if (nAngle == 0)
668  {
669  nAngle = it->second.has<double>() ? it->second.get<double>() : 0;
670  }
671 
672  sal_Int16 nDirection = 0;
673  switch (nAngle)
674  {
675  case -90:
676  nDirection = text::WritingMode2::TB_RL;
677  break;
678  case -270:
679  nDirection = text::WritingMode2::BT_LR;
680  break;
681  default:
682  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled property value: "
683  "CustomShapeGeometry:TextPreRotateAngle: "
684  << nAngle);
685  break;
686  }
687 
688  if (nDirection)
689  {
690  syncProperty(pShape, RES_FRAMEDIR, 0, uno::Any(nDirection), pObj);
691  }
692  }
693  }
694  else if (rPropertyName == UNO_NAME_TEXT_VERT_ADJUST)
695  syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0, rValue, pObj);
696  else if (rPropertyName == UNO_NAME_TEXT_AUTOGROWHEIGHT)
697  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, rValue, pObj);
698  else if (rPropertyName == UNO_NAME_TEXT_LEFTDIST)
699  syncProperty(pShape, RES_BOX, LEFT_BORDER_DISTANCE, rValue, pObj);
700  else if (rPropertyName == UNO_NAME_TEXT_RIGHTDIST)
701  syncProperty(pShape, RES_BOX, RIGHT_BORDER_DISTANCE, rValue, pObj);
702  else if (rPropertyName == UNO_NAME_TEXT_UPPERDIST)
703  syncProperty(pShape, RES_BOX, TOP_BORDER_DISTANCE, rValue, pObj);
704  else if (rPropertyName == UNO_NAME_TEXT_LOWERDIST)
705  syncProperty(pShape, RES_BOX, BOTTOM_BORDER_DISTANCE, rValue, pObj);
706  else if (rPropertyName == UNO_NAME_TEXT_WRITINGMODE)
707  {
708  text::WritingMode eMode;
709  sal_Int16 eMode2;
710  if (rValue >>= eMode)
711  syncProperty(pShape, RES_FRAMEDIR, 0, uno::Any(sal_Int16(eMode)), pObj);
712  else if (rValue >>= eMode2)
713  syncProperty(pShape, RES_FRAMEDIR, 0, uno::Any(eMode2), pObj);
714  }
715  else
716  SAL_INFO("sw.core", "SwTextBoxHelper::syncProperty: unhandled property: "
717  << static_cast<OUString>(rPropertyName));
718 }
719 
720 void SwTextBoxHelper::getProperty(SwFrameFormat const* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
721  css::uno::Any& rValue)
722 {
723  if (!pShape)
724  return;
725 
726  nMemberID &= ~CONVERT_TWIPS;
727 
728  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
729  if (!pFormat)
730  return;
731 
732  if (nWID != RES_CHAIN)
733  return;
734 
735  switch (nMemberID)
736  {
737  case MID_CHAIN_PREVNAME:
738  case MID_CHAIN_NEXTNAME:
739  {
740  const SwFormatChain& rChain = pFormat->GetChain();
741  rChain.QueryValue(rValue, nMemberID);
742  }
743  break;
744  case MID_CHAIN_NAME:
745  rValue <<= pFormat->GetName();
746  break;
747  default:
748  SAL_WARN("sw.core", "SwTextBoxHelper::getProperty: unhandled member-id: "
749  << o3tl::narrowing<sal_uInt16>(nMemberID));
750  break;
751  }
752 }
753 
754 css::uno::Any SwTextBoxHelper::getProperty(SwFrameFormat const* pShape, const OUString& rPropName)
755 {
756  if (!pShape)
757  return {};
758 
759  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
760  if (!pFormat)
761  return {};
762 
763  uno::Reference<beans::XPropertySet> const xPropertySet(
764  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
765 
766  return xPropertySet->getPropertyValue(rPropName);
767 }
768 
769 void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
770  const css::uno::Any& rValue, SdrObject* pObj)
771 {
772  // No shape yet? Then nothing to do, initial properties are set by create().
773  if (!pShape)
774  return;
775 
776  uno::Any aValue(rValue);
777  nMemberID &= ~CONVERT_TWIPS;
778 
779  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
780  if (!pFormat)
781  return;
782 
783  OUString aPropertyName;
784  bool bAdjustX = false;
785  bool bAdjustY = false;
786  bool bAdjustSize = false;
787  switch (nWID)
788  {
789  case RES_HORI_ORIENT:
790  switch (nMemberID)
791  {
793  aPropertyName = UNO_NAME_HORI_ORIENT;
794  break;
796  if (pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
797  aPropertyName = UNO_NAME_HORI_ORIENT_RELATION;
798  else
799  return;
800  break;
802  aPropertyName = UNO_NAME_HORI_ORIENT_POSITION;
803  bAdjustX = true;
804  break;
805  default:
806  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
807  << o3tl::narrowing<sal_uInt16>(nMemberID)
808  << " (which-id: " << nWID << ")");
809  break;
810  }
811  break;
812  case RES_LR_SPACE:
813  {
814  switch (nMemberID)
815  {
816  case MID_L_MARGIN:
817  aPropertyName = UNO_NAME_LEFT_MARGIN;
818  break;
819  case MID_R_MARGIN:
820  aPropertyName = UNO_NAME_RIGHT_MARGIN;
821  break;
822  default:
823  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
824  << o3tl::narrowing<sal_uInt16>(nMemberID)
825  << " (which-id: " << nWID << ")");
826  break;
827  }
828  break;
829  }
830  case RES_VERT_ORIENT:
831  switch (nMemberID)
832  {
834  aPropertyName = UNO_NAME_VERT_ORIENT;
835  break;
837  if (pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
838  aPropertyName = UNO_NAME_VERT_ORIENT_RELATION;
839  else
840  return;
841  break;
843  aPropertyName = UNO_NAME_VERT_ORIENT_POSITION;
844  bAdjustY = true;
845  break;
846  default:
847  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
848  << o3tl::narrowing<sal_uInt16>(nMemberID)
849  << " (which-id: " << nWID << ")");
850  break;
851  }
852  break;
853  case RES_FRM_SIZE:
854  switch (nMemberID)
855  {
857  aPropertyName = UNO_NAME_WIDTH_TYPE;
858  break;
860  aPropertyName = UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT;
861  break;
863  aPropertyName = UNO_NAME_RELATIVE_HEIGHT_RELATION;
864  break;
866  aPropertyName = UNO_NAME_RELATIVE_WIDTH_RELATION;
867  break;
868  default:
869  aPropertyName = UNO_NAME_SIZE;
870  bAdjustSize = true;
871  break;
872  }
873  break;
874  case RES_ANCHOR:
875  switch (nMemberID)
876  {
878  {
879  changeAnchor(pShape, pObj);
880  return;
881  }
882  break;
883  default:
884  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
885  << o3tl::narrowing<sal_uInt16>(nMemberID)
886  << " (which-id: " << nWID << ")");
887  break;
888  }
889  break;
890  case FN_TEXT_RANGE:
891  {
892  uno::Reference<text::XTextRange> xRange;
893  rValue >>= xRange;
894  SwUnoInternalPaM aInternalPaM(*pFormat->GetDoc());
895  if (sw::XTextRangeToSwPaM(aInternalPaM, xRange))
896  {
897  SwFormatAnchor aAnchor(pFormat->GetAnchor());
898  aAnchor.SetAnchor(aInternalPaM.Start());
899  pFormat->SetFormatAttr(aAnchor);
900  }
901  }
902  break;
903  case RES_CHAIN:
904  switch (nMemberID)
905  {
906  case MID_CHAIN_PREVNAME:
907  aPropertyName = UNO_NAME_CHAIN_PREV_NAME;
908  break;
909  case MID_CHAIN_NEXTNAME:
910  aPropertyName = UNO_NAME_CHAIN_NEXT_NAME;
911  break;
912  default:
913  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
914  << o3tl::narrowing<sal_uInt16>(nMemberID)
915  << " (which-id: " << nWID << ")");
916  break;
917  }
918  break;
920  aPropertyName = UNO_NAME_TEXT_VERT_ADJUST;
921  break;
922  case RES_BOX:
923  switch (nMemberID)
924  {
926  aPropertyName = UNO_NAME_LEFT_BORDER_DISTANCE;
927  break;
929  aPropertyName = UNO_NAME_RIGHT_BORDER_DISTANCE;
930  break;
931  case TOP_BORDER_DISTANCE:
932  aPropertyName = UNO_NAME_TOP_BORDER_DISTANCE;
933  break;
935  aPropertyName = UNO_NAME_BOTTOM_BORDER_DISTANCE;
936  break;
937  default:
938  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
939  << o3tl::narrowing<sal_uInt16>(nMemberID)
940  << " (which-id: " << nWID << ")");
941  break;
942  }
943  break;
944  case RES_OPAQUE:
945  aPropertyName = UNO_NAME_OPAQUE;
946  break;
947  case RES_FRAMEDIR:
948  aPropertyName = UNO_NAME_WRITING_MODE;
949  break;
951  switch (nMemberID)
952  {
953  case MID_ALLOW_OVERLAP:
954  aPropertyName = UNO_NAME_ALLOW_OVERLAP;
955  break;
956  default:
957  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
958  << o3tl::narrowing<sal_uInt16>(nMemberID)
959  << " (which-id: " << nWID << ")");
960  break;
961  }
962  break;
963  default:
964  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled which-id: "
965  << nWID << " (member-id: "
966  << o3tl::narrowing<sal_uInt16>(nMemberID) << ")");
967  break;
968  }
969 
970  if (aPropertyName.isEmpty())
971  return;
972 
973  // Position/size should be the text position/size, not the shape one as-is.
974  if (bAdjustX || bAdjustY || bAdjustSize)
975  {
976  changeAnchor(pShape, pObj);
977  tools::Rectangle aRect
978  = getRelativeTextRectangle(pObj ? pObj : pShape->FindRealSdrObject());
979  if (!aRect.IsEmpty())
980  {
981  if (bAdjustX || bAdjustY)
982  {
983  sal_Int32 nValue;
984  if (aValue >>= nValue)
985  {
986  nValue += convertTwipToMm100(bAdjustX ? aRect.Left() : aRect.Top());
987  aValue <<= nValue;
988  }
989  }
990  else if (bAdjustSize)
991  {
992  awt::Size aSize(convertTwipToMm100(aRect.getWidth()),
993  convertTwipToMm100(aRect.getHeight()));
994  aValue <<= aSize;
995  }
996  }
997  }
998 
999  uno::Reference<beans::XPropertySet> const xPropertySet(
1000  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
1001  xPropertySet->setPropertyValue(aPropertyName, aValue);
1002 }
1003 
1005  std::map<const SwFrameFormat*, const SwFrameFormat*>& rLinks)
1006 {
1007  for (const auto pFormat : rFormats)
1008  {
1009  if (SwFrameFormat* pTextBox = getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
1010  rLinks[pFormat] = pTextBox;
1011  }
1012 }
1013 
1014 void SwTextBoxHelper::restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrameFormat*>& rNew,
1015  SavedLink& rSavedLinks)
1016 {
1017  std::size_t i = 0;
1018  for (const auto& rIt : rOld)
1019  {
1020  auto aTextBoxIt = rSavedLinks.find(rIt.GetFormat());
1021  if (aTextBoxIt != rSavedLinks.end())
1022  {
1023  std::size_t j = 0;
1024  for (const auto& rJt : rOld)
1025  {
1026  if (rJt.GetFormat() == aTextBoxIt->second)
1027  rNew[i]->SetFormatAttr(rNew[j]->GetContent());
1028  ++j;
1029  }
1030  }
1031  ++i;
1032  }
1033 }
1034 
1035 text::TextContentAnchorType SwTextBoxHelper::mapAnchorType(const RndStdIds& rAnchorID)
1036 {
1037  text::TextContentAnchorType aAnchorType;
1038  switch (rAnchorID)
1039  {
1040  case RndStdIds::FLY_AS_CHAR:
1041  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER;
1042  break;
1043  case RndStdIds::FLY_AT_CHAR:
1044  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER;
1045  break;
1046  case RndStdIds::FLY_AT_PARA:
1047  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH;
1048  break;
1049  case RndStdIds::FLY_AT_PAGE:
1050  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PAGE;
1051  break;
1052  case RndStdIds::FLY_AT_FLY:
1053  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_FRAME;
1054  break;
1055  default:
1056  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH;
1057  SAL_WARN("sw.core", "SwTextBoxHelper::mapAnchorType: Unknown AnchorType!");
1058  break;
1059  }
1060  return aAnchorType;
1061 }
1062 
1064  SdrObject* pObj)
1065 {
1066  SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT, pObj);
1067  if (!pFormat)
1068  return;
1069 
1070  const bool bInlineAnchored = rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR;
1071  const bool bLayoutInCell
1072  = rShape.GetFollowTextFlow().GetValue() && rShape.GetAnchor().GetContentAnchor()
1074  SfxItemSet aTextBoxSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange);
1075 
1076  SfxItemIter aIter(rSet);
1077  const SfxPoolItem* pItem = aIter.GetCurItem();
1078 
1079  do
1080  {
1081  switch (pItem->Which())
1082  {
1083  case RES_VERT_ORIENT:
1084  {
1085  // The new position can be with anchor changing so sync it!
1086  const text::TextContentAnchorType aNewAnchorType
1087  = mapAnchorType(rShape.GetAnchor().GetAnchorId());
1088  syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType),
1089  pObj);
1090  if (bInlineAnchored || bLayoutInCell)
1091  return;
1093 
1094  tools::Rectangle aRect
1095  = getRelativeTextRectangle(pObj ? pObj : rShape.FindRealSdrObject());
1096  if (!aRect.IsEmpty())
1097  aOrient.SetPos(aOrient.GetPos() + aRect.Top());
1098 
1099  if (rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
1100  && rShape.GetAnchor().GetPageNum() != 0)
1101  aOrient.SetRelationOrient(rShape.GetVertOrient().GetRelationOrient());
1102  aTextBoxSet.Put(aOrient);
1103 
1104  // restore height (shrunk for extending beyond the page bottom - tdf#91260)
1105  SwFormatFrameSize aSize(pFormat->GetFrameSize());
1106  if (!aRect.IsEmpty())
1107  {
1108  aSize.SetHeight(aRect.getHeight());
1109  aTextBoxSet.Put(aSize);
1110  }
1111  }
1112  break;
1113  case RES_HORI_ORIENT:
1114  {
1115  // The new position can be with anchor changing so sync it!
1116  const text::TextContentAnchorType aNewAnchorType
1117  = mapAnchorType(rShape.GetAnchor().GetAnchorId());
1118  syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType),
1119  pObj);
1120  if (bInlineAnchored || bLayoutInCell)
1121  return;
1123 
1124  tools::Rectangle aRect
1125  = getRelativeTextRectangle(pObj ? pObj : rShape.FindRealSdrObject());
1126  if (!aRect.IsEmpty())
1127  aOrient.SetPos(aOrient.GetPos() + aRect.Left());
1128 
1129  if (rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
1130  && rShape.GetAnchor().GetPageNum() != 0)
1131  aOrient.SetRelationOrient(rShape.GetHoriOrient().GetRelationOrient());
1132  aTextBoxSet.Put(aOrient);
1133  }
1134  break;
1135  case RES_FRM_SIZE:
1136  {
1137  // In case the shape got resized, then we need to adjust both
1138  // the position and the size of the textbox (e.g. larger
1139  // rounded edges of a rectangle -> need to push right/down the
1140  // textbox).
1141  SwFormatVertOrient aVertOrient(rShape.GetVertOrient());
1142  SwFormatHoriOrient aHoriOrient(rShape.GetHoriOrient());
1143  SwFormatFrameSize aSize(pFormat->GetFrameSize());
1144 
1145  tools::Rectangle aRect
1146  = getRelativeTextRectangle(pObj ? pObj : rShape.FindRealSdrObject());
1147  if (!aRect.IsEmpty())
1148  {
1149  if (!bInlineAnchored)
1150  {
1151  aVertOrient.SetPos(
1152  (pObj ? pObj->GetRelativePos().getX() : aVertOrient.GetPos())
1153  + aRect.Top());
1154  aHoriOrient.SetPos(
1155  (pObj ? pObj->GetRelativePos().getY() : aHoriOrient.GetPos())
1156  + aRect.Left());
1157 
1158  aTextBoxSet.Put(aVertOrient);
1159  aTextBoxSet.Put(aHoriOrient);
1160  }
1161 
1162  aSize.SetWidth(aRect.getWidth());
1163  aSize.SetHeight(aRect.getHeight());
1164  aTextBoxSet.Put(aSize);
1165  }
1166  }
1167  break;
1168  case RES_ANCHOR:
1169  {
1170  if (pItem->StaticWhichCast(RES_ANCHOR) == rShape.GetAnchor())
1171  // the anchor have to be synced
1172  {
1173  const text::TextContentAnchorType aNewAnchorType
1174  = mapAnchorType(rShape.GetAnchor().GetAnchorId());
1175  syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
1176  uno::Any(aNewAnchorType), pObj);
1177  }
1178  else
1179  {
1180  SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: The anchor of the "
1181  "shape different from the textframe!");
1182  }
1183  }
1184  break;
1185  default:
1186  SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: unhandled which-id: "
1187  << pItem->Which());
1188  break;
1189  }
1190 
1191  pItem = aIter.NextItem();
1192  } while (pItem && (0 != pItem->Which()));
1193 
1194  if (aTextBoxSet.Count())
1195  pFormat->SetFormatAttr(aTextBoxSet);
1196 
1197  DoTextBoxZOrderCorrection(&rShape, pObj);
1198 }
1199 
1201 {
1202  if (!pObj)
1203  return;
1204  uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
1205  if (!xShape)
1206  return;
1207  uno::Reference<beans::XPropertySet> const xPropertySet(xShape, uno::UNO_QUERY);
1208 
1209  auto pParentFormat = getOtherTextBoxFormat(getOtherTextBoxFormat(xShape), RES_FLYFRMFMT);
1210  if (!pParentFormat)
1211  return;
1212 
1213  // Sync the padding
1214  syncProperty(pParentFormat, UNO_NAME_TEXT_LEFTDIST,
1215  xPropertySet->getPropertyValue(UNO_NAME_TEXT_LEFTDIST), pObj);
1216  syncProperty(pParentFormat, UNO_NAME_TEXT_RIGHTDIST,
1217  xPropertySet->getPropertyValue(UNO_NAME_TEXT_RIGHTDIST), pObj);
1218  syncProperty(pParentFormat, UNO_NAME_TEXT_UPPERDIST,
1219  xPropertySet->getPropertyValue(UNO_NAME_TEXT_UPPERDIST), pObj);
1220  syncProperty(pParentFormat, UNO_NAME_TEXT_LOWERDIST,
1221  xPropertySet->getPropertyValue(UNO_NAME_TEXT_LOWERDIST), pObj);
1222 
1223  // Sync the text aligning
1224  syncProperty(pParentFormat, UNO_NAME_TEXT_VERTADJUST,
1225  xPropertySet->getPropertyValue(UNO_NAME_TEXT_VERTADJUST), pObj);
1226  syncProperty(pParentFormat, UNO_NAME_TEXT_HORZADJUST,
1227  xPropertySet->getPropertyValue(UNO_NAME_TEXT_HORZADJUST), pObj);
1228 
1229  // tdf137803: Sync autogrow:
1230  const bool bIsAutoGrow
1231  = xPropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT).get<bool>();
1232  const bool bIsAutoWrap = xPropertySet->getPropertyValue(UNO_NAME_TEXT_WORDWRAP).get<bool>();
1233 
1234  syncProperty(pParentFormat, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, uno::Any(bIsAutoGrow),
1235  pObj);
1236 
1237  syncProperty(pParentFormat, RES_FRM_SIZE, MID_FRMSIZE_WIDTH_TYPE,
1238  uno::Any(bIsAutoWrap ? text::SizeType::FIX : text::SizeType::MIN), pObj);
1239 
1240  changeAnchor(pParentFormat, pObj);
1241  DoTextBoxZOrderCorrection(pParentFormat, pObj);
1242 }
1243 
1245 {
1246  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
1247  {
1248  const SwFormatAnchor& rOldAnch = pFormat->GetAnchor();
1249  const SwFormatAnchor& rNewAnch = pShape->GetAnchor();
1250 
1251  const auto pOldCnt = rOldAnch.GetContentAnchor();
1252  const auto pNewCnt = rNewAnch.GetContentAnchor();
1253 
1254  const uno::Any aShapeHorRelOrient(pShape->GetHoriOrient().GetRelationOrient());
1255 
1256  try
1257  {
1258  ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
1259  uno::Reference<beans::XPropertySet> const xPropertySet(
1260  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
1261  if (pOldCnt && rNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE
1262  && rNewAnch.GetPageNum())
1263  {
1264  uno::Any aValue(text::TextContentAnchorType_AT_PAGE);
1265  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION, aShapeHorRelOrient);
1266  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1267  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
1268  uno::Any(rNewAnch.GetPageNum()));
1269  }
1270  else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE && pNewCnt)
1271  {
1272  if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1273  {
1274  uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
1275  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1276  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1277  uno::Any(text::RelOrientation::CHAR));
1278  xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION,
1279  uno::Any(text::RelOrientation::PRINT_AREA));
1280  SwFormatAnchor aPos(pFormat->GetAnchor());
1281  aPos.SetAnchor(pNewCnt);
1282  pFormat->SetFormatAttr(aPos);
1283  }
1284  else
1285  {
1286  uno::Any aValue(mapAnchorType(rNewAnch.GetAnchorId()));
1287  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1288  aShapeHorRelOrient);
1289  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1290  pFormat->SetFormatAttr(rNewAnch);
1291  }
1292  }
1293  else
1294  {
1295  if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1296  {
1297  uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
1298  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1299  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1300  uno::Any(text::RelOrientation::CHAR));
1301  xPropertySet->setPropertyValue(UNO_NAME_VERT_ORIENT_RELATION,
1302  uno::Any(text::RelOrientation::PRINT_AREA));
1303  SwFormatAnchor aPos(pFormat->GetAnchor());
1304  aPos.SetAnchor(pNewCnt);
1305  pFormat->SetFormatAttr(aPos);
1306  }
1307  else
1308  {
1309  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1310  aShapeHorRelOrient);
1311  pFormat->SetFormatAttr(pShape->GetAnchor());
1312  }
1313  }
1314  }
1315  catch (uno::Exception& e)
1316  {
1317  SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << e.Message);
1318  }
1319 
1320  return doTextBoxPositioning(pShape, pObj) && DoTextBoxZOrderCorrection(pShape, pObj);
1321  }
1322 
1323  return false;
1324 }
1325 
1327 {
1328  // Set the position of the textboxes according to the position of its shape-pair
1329  const bool bIsGroupObj = (pObj != pShape->FindRealSdrObject()) && pObj;
1330  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
1331  {
1332  // Do not create undo entry for the positioning
1333  ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
1334 
1335  // Special treatment for AS_CHAR textboxes:
1336  if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1337  {
1338  // Get the text area of the shape
1339  tools::Rectangle aRect
1340  = getRelativeTextRectangle(pObj ? pObj : pShape->FindRealSdrObject());
1341 
1342  // Get the left spacing of the text area of the shape
1343  auto nLeftSpace = pShape->GetLRSpace().GetLeft();
1344 
1345  // Set the textbox position at the X-axis:
1346  SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient());
1347  aNewHOri.SetPos(aRect.Left() + nLeftSpace
1348  + (bIsGroupObj ? pObj->GetRelativePos().getX() : 0));
1349  SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
1350 
1351  // Special handling of group textboxes
1352  if (bIsGroupObj)
1353  {
1354  // There are the following cases:
1355  // case 1: The textbox should be in that position where the shape is.
1356  // case 2: The shape has negative offset so that have to be subtracted
1357  // case 3: The shape and its parent shape also has negative offset, so subtract
1358  aNewVOri.SetPos(
1359  ((pObj->GetRelativePos().getY()) > 0
1360  ? (pShape->GetVertOrient().GetPos() > 0
1361  ? pObj->GetRelativePos().getY()
1362  : pObj->GetRelativePos().getY() - pShape->GetVertOrient().GetPos())
1363  : (pShape->GetVertOrient().GetPos() > 0
1364  ? 0 // Is this can be a variation?
1365  : pObj->GetRelativePos().getY() - pShape->GetVertOrient().GetPos()))
1366  + aRect.Top());
1367  }
1368  else
1369  {
1370  // Simple textboxes: vertical position equals to the vertical offset of the shape
1371  aNewVOri.SetPos(
1372  ((pShape->GetVertOrient().GetPos()) > 0 ? pShape->GetVertOrient().GetPos() : 0)
1373  + aRect.Top());
1374  }
1375 
1376  // Special cases when the shape is aligned to the line
1378  {
1379  aNewVOri.SetVertOrient(text::VertOrientation::NONE);
1380  switch (pShape->GetVertOrient().GetVertOrient())
1381  {
1382  // Top aligned shape
1383  case text::VertOrientation::TOP:
1384  case text::VertOrientation::CHAR_TOP:
1385  case text::VertOrientation::LINE_TOP:
1386  {
1387  aNewVOri.SetPos(aNewVOri.GetPos() - pShape->GetFrameSize().GetHeight());
1388  break;
1389  }
1390  // Bottom aligned shape
1391  case text::VertOrientation::BOTTOM:
1392  case text::VertOrientation::CHAR_BOTTOM:
1393  case text::VertOrientation::LINE_BOTTOM:
1394  {
1395  aNewVOri.SetPos(aNewVOri.GetPos() + pShape->GetFrameSize().GetHeight());
1396  break;
1397  }
1398  // Center aligned shape
1399  case text::VertOrientation::CENTER:
1400  case text::VertOrientation::CHAR_CENTER:
1401  case text::VertOrientation::LINE_CENTER:
1402  {
1403  aNewVOri.SetPos(aNewVOri.GetPos()
1404  + std::lroundf(pShape->GetFrameSize().GetHeight() / 2));
1405  break;
1406  }
1407  default:
1408  break;
1409  }
1410  }
1411 
1412  pFormat->SetFormatAttr(aNewHOri);
1413  pFormat->SetFormatAttr(aNewVOri);
1414  }
1415  // Other cases when the shape has different anchor from AS_CHAR
1416  else
1417  {
1418  // Text area of the shape
1419  tools::Rectangle aRect
1420  = getRelativeTextRectangle(pObj ? pObj : pShape->FindRealSdrObject());
1421 
1422  // X Offset of the shape spacing
1423  auto nLeftSpace = pShape->GetLRSpace().GetLeft();
1424 
1425  // Set the same position as the (child) shape has
1426  SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
1427  aNewHOri.SetPos(
1428  (bIsGroupObj && pObj ? pObj->GetRelativePos().getX() : aNewHOri.GetPos())
1429  + aRect.Left());
1430  SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
1431  aNewVOri.SetPos(
1432  (bIsGroupObj && pObj ? pObj->GetRelativePos().getY() : aNewVOri.GetPos())
1433  + aRect.Top());
1434 
1435  // Get the distance of the child shape inside its parent
1436  const auto& nInshapePos
1437  = pObj ? pObj->GetRelativePos() - pShape->FindRealSdrObject()->GetRelativePos()
1438  : Point();
1439 
1440  // Special case: the shape has relative position from the page
1441  if (pShape->GetHoriOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME
1442  && pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_PAGE)
1443  {
1444  aNewHOri.SetRelationOrient(text::RelOrientation::PAGE_FRAME);
1445  aNewHOri.SetPos(pShape->GetHoriOrient().GetPos() + nInshapePos.getX()
1446  + aRect.Left());
1447  }
1448 
1449  if (pShape->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME
1450  && pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_PAGE)
1451  {
1452  aNewVOri.SetRelationOrient(text::RelOrientation::PAGE_FRAME);
1453  aNewVOri.SetPos(pShape->GetVertOrient().GetPos() + nInshapePos.getY()
1454  + aRect.Top());
1455  }
1456 
1457  // Other special case: shape is inside a table or floating table following the text flow
1458  if (pShape->GetFollowTextFlow().GetValue() && pShape->GetAnchor().GetContentAnchor()
1460  {
1461  // Table position
1462  Point nTableOffset;
1463  // Floating table
1464  if (auto pFly = pShape->GetAnchor()
1465  .GetContentAnchor()
1466  ->nNode.GetNode()
1467  .FindTableNode()
1468  ->FindFlyStartNode())
1469  {
1470  if (auto pFlyFormat = pFly->GetFlyFormat())
1471  {
1472  nTableOffset.setX(pFlyFormat->GetHoriOrient().GetPos());
1473  nTableOffset.setY(pFlyFormat->GetVertOrient().GetPos());
1474  }
1475  }
1476  else
1477  // Normal table
1478  {
1479  auto pTableNode
1481  if (auto pTableFormat = pTableNode->GetTable().GetFrameFormat())
1482  {
1483  nTableOffset.setX(pTableFormat->GetHoriOrient().GetPos());
1484  nTableOffset.setY(pTableFormat->GetVertOrient().GetPos());
1485  }
1486  }
1487 
1488  // Add the table positions to the textbox.
1489  aNewHOri.SetPos(aNewHOri.GetPos() + nTableOffset.getX() + nLeftSpace);
1490  if (pShape->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME
1491  || pShape->GetVertOrient().GetRelationOrient()
1492  == text::RelOrientation::PAGE_PRINT_AREA)
1493  aNewVOri.SetPos(aNewVOri.GetPos() + nTableOffset.getY());
1494  }
1495 
1496  pFormat->SetFormatAttr(aNewHOri);
1497  pFormat->SetFormatAttr(aNewVOri);
1498  }
1499  return true;
1500  }
1501 
1502  return false;
1503 }
1504 
1506 {
1507  if (!pShape || !pObj)
1508  return false;
1509 
1510  if (auto pTextBox = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj))
1511  {
1512  const auto& rSize = getRelativeTextRectangle(pObj).GetSize();
1513  if (!rSize.IsEmpty())
1514  {
1515  SwFormatFrameSize aSize(pTextBox->GetFrameSize());
1516  aSize.SetSize(rSize);
1517  return pTextBox->SetFormatAttr(aSize);
1518  }
1519  }
1520 
1521  return false;
1522 }
1523 
1525 {
1526  // TODO: do this with group shape textboxes.
1527  SdrObject* pShpObj = nullptr;
1528 
1529  pShpObj = pShape->FindRealSdrObject();
1530 
1531  if (pShpObj)
1532  {
1533  auto pTextBox = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT, pObj);
1534  SdrObject* pFrmObj = pTextBox->FindRealSdrObject();
1535  if (!pFrmObj)
1536  {
1537  // During loading there is no ready SdrObj for z-ordering, so create and cache it here
1538  pFrmObj
1539  = SwXTextFrame::GetOrCreateSdrObject(*dynamic_cast<SwFlyFrameFormat*>(pTextBox));
1540  }
1541  if (pFrmObj)
1542  {
1543  // Get the draw model from the doc
1544  SwDrawModel* pDrawModel
1546  if (pDrawModel)
1547  {
1548  // Not really sure this will work on all pages, but it seems it will.
1549  auto pPage = pDrawModel->GetPage(0);
1550  // Recalc all Z-orders
1551  pPage->RecalcObjOrdNums();
1552  // Here is a counter avoiding running to in infinity:
1553  sal_uInt16 nIterator = 0;
1554  // If the shape is behind the frame, is good, but if there are some objects
1555  // between of them that is wrong so put the frame exactly one level higher
1556  // than the shape.
1557  if (pFrmObj->GetOrdNum() > pShpObj->GetOrdNum())
1558  pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pShpObj->GetOrdNum() + 1);
1559  else
1560  // Else, if the frame is behind the shape, bring to the front of it.
1561  while (pFrmObj->GetOrdNum() <= pShpObj->GetOrdNum())
1562  {
1563  pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pFrmObj->GetOrdNum() + 1);
1564  // If there is any problem with the indexes, do not run over the infinity
1565  if (pPage->GetObjCount() == pFrmObj->GetOrdNum())
1566  break;
1567  ++nIterator;
1568  if (nIterator > 300)
1569  break; // Do not run to infinity
1570  }
1571  pPage->RecalcObjOrdNums();
1572  return true; // Success
1573  }
1574  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1575  "No Valid Draw model for SdrObject for the shape!");
1576  }
1577  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1578  "No Valid SdrObject for the frame!");
1579  }
1580  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1581  "No Valid SdrObject for the shape!");
1582 
1583  return false;
1584 }
1585 
1587  SwFrameFormat* pFormat, SdrObject* pObj)
1588 {
1589  if (auto pChildren = pObj->getChildrenOfSdrObject())
1590  {
1591  for (size_t i = 0; i < pChildren->GetObjCount(); ++i)
1592  synchronizeGroupTextBoxProperty(pFunc, pFormat, pChildren->GetObj(i));
1593  }
1594  else
1595  {
1596  (*pFunc)(pFormat, pObj);
1597  }
1598 }
1599 
1600 std::vector<SwFrameFormat*> SwTextBoxHelper::CollectTextBoxes(const SdrObject* pGroupObject,
1601  SwFrameFormat* pFormat)
1602 {
1603  std::vector<SwFrameFormat*> vRet;
1604  if (auto pChildren = pGroupObject->getChildrenOfSdrObject())
1605  {
1606  for (size_t i = 0; i < pChildren->GetObjCount(); ++i)
1607  {
1608  auto pChildTextBoxes = CollectTextBoxes(pChildren->GetObj(i), pFormat);
1609  for (auto& rChildTextBox : pChildTextBoxes)
1610  vRet.push_back(rChildTextBox);
1611  }
1612  }
1613  else
1614  {
1615  if (isTextBox(pFormat, RES_DRAWFRMFMT, pGroupObject))
1616  vRet.push_back(getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT, pGroupObject));
1617  }
1618  return vRet;
1619 }
1620 
1622 {
1623  assert(pOwnerShape);
1624  assert(pOwnerShape->Which() == RES_DRAWFRMFMT);
1625 
1626  m_pOwnerShapeFormat = pOwnerShape;
1627  if (!m_pTextBoxes.empty())
1628  m_pTextBoxes.clear();
1629 }
1630 
1631 SwTextBoxNode::~SwTextBoxNode() { m_pTextBoxes.clear(); }
1632 
1633 void SwTextBoxNode::AddTextBox(SdrObject* pDrawObject, SwFrameFormat* pNewTextBox)
1634 {
1635  assert(pNewTextBox);
1636  assert(pNewTextBox->Which() == RES_FLYFRMFMT);
1637 
1638  assert(pDrawObject);
1639 
1640  SwTextBoxElement aElem;
1641  aElem.m_bIsActive = true;
1642  aElem.m_pDrawObject = pDrawObject;
1643  aElem.m_pTextBoxFormat = pNewTextBox;
1644  auto pSwFlyDraw = dynamic_cast<SwFlyDrawObj*>(pDrawObject);
1645  if (pSwFlyDraw)
1646  {
1647  pSwFlyDraw->SetTextBox(true);
1648  }
1649  m_pTextBoxes.push_back(aElem);
1650 }
1651 
1652 void SwTextBoxNode::DelTextBox(const SdrObject* pDrawObject, bool bDelFromDoc)
1653 {
1654  assert(pDrawObject);
1655  if (m_pTextBoxes.empty())
1656  return;
1657 
1658  for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end();)
1659  {
1660  if (it->m_pDrawObject == pDrawObject)
1661  {
1662  if (bDelFromDoc)
1663  {
1664  m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
1665  it->m_pTextBoxFormat);
1666  // What about m_pTextBoxes? So, when the DelLayoutFormat() removes the format
1667  // then the ~SwFrameFormat() will call this method again to remove the entry.
1668  break;
1669  }
1670  else
1671  {
1672  it = m_pTextBoxes.erase(it);
1673  break;
1674  }
1675  }
1676  ++it;
1677  }
1678 }
1679 
1680 void SwTextBoxNode::DelTextBox(const SwFrameFormat* pTextBox, bool bDelFromDoc)
1681 {
1682  if (m_pTextBoxes.empty())
1683  return;
1684 
1685  for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end();)
1686  {
1687  if (it->m_pTextBoxFormat == pTextBox)
1688  {
1689  if (bDelFromDoc)
1690  {
1691  m_pOwnerShapeFormat->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(
1692  it->m_pTextBoxFormat);
1693  // What about m_pTextBoxes? So, when the DelLayoutFormat() removes the format
1694  // then the ~SwFrameFormat() will call this method again to remove the entry.
1695  break;
1696  }
1697  else
1698  {
1699  it = m_pTextBoxes.erase(it);
1700  break;
1701  }
1702  }
1703  ++it;
1704  }
1705 }
1706 
1708 {
1709  assert(pDrawObject);
1710  if (!m_pTextBoxes.empty())
1711  {
1712  for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
1713  {
1714  if (it->m_pDrawObject == pDrawObject)
1715  {
1716  return it->m_pTextBoxFormat;
1717  }
1718  }
1719  }
1720  return nullptr;
1721 }
1722 
1723 bool SwTextBoxNode::IsTextBoxActive(const SdrObject* pDrawObject) const
1724 {
1725  assert(pDrawObject);
1726 
1727  if (!m_pTextBoxes.empty())
1728  {
1729  for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
1730  {
1731  if (it->m_pDrawObject == pDrawObject)
1732  {
1733  return it->m_bIsActive;
1734  }
1735  }
1736  }
1737  return false;
1738 }
1739 
1741 {
1742  assert(pDrawObject);
1743 
1744  if (!m_pTextBoxes.empty())
1745  {
1746  for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
1747  {
1748  if (it->m_pDrawObject == pDrawObject)
1749  {
1750  it->m_bIsActive = true;
1751  }
1752  }
1753  }
1754 }
1755 
1757 {
1758  assert(pDrawObject);
1759 
1760  if (!m_pTextBoxes.empty())
1761  {
1762  for (auto it = m_pTextBoxes.begin(); it != m_pTextBoxes.end(); it++)
1763  {
1764  if (it->m_pDrawObject == pDrawObject)
1765  {
1766  it->m_bIsActive = false;
1767  }
1768  }
1769  }
1770 }
1771 
1772 bool SwTextBoxNode::IsGroupTextBox() const { return m_pTextBoxes.size() > 1; }
1773 
1774 std::map<SdrObject*, SwFrameFormat*> SwTextBoxNode::GetAllTextBoxes() const
1775 {
1776  std::map<SdrObject*, SwFrameFormat*> aRet;
1777  for (auto& rElem : m_pTextBoxes)
1778  {
1779  aRet.emplace(rElem.m_pDrawObject, rElem.m_pTextBoxFormat);
1780  }
1781  return aRet;
1782 }
1783 
1784 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static SwFrameFormat * getOtherTextBoxFormat(const SwFrameFormat *pFormat, sal_uInt16 nType, const SdrObject *pObject=nullptr)
If we have an associated TextFrame, then return that.
bool GetValue() const
void SetTextBox(bool bIsTextBox)
Definition: dflyobj.hxx:52
void SetPos(const Point &rPoint)
constexpr TypedWhichId< SvxFrameDirectionItem > RES_FRAMEDIR(120)
#define MID_CHAIN_NAME
Definition: unomid.h:58
static sal_Int32 getCount(const SwDoc &rDoc)
Count number of shapes in the document, excluding TextBoxes.
SwFrameFormat * GetTextBox(const SdrObject *pDrawObject) const
static css::uno::Any getByIndex(SdrPage const *pPage, sal_Int32 nIndex)
Get a shape by index, excluding TextBoxes.
virtual const tools::Rectangle & GetCurrentBoundRect() const
void SetHeight(tools::Long n)
#define UNO_NAME_HORI_ORIENT_POSITION
Definition: unoprnms.hxx:267
constexpr OUStringLiteral UNO_NAME_TEXT_HORZADJUST
static void lcl_queryInterface(const SwFrameFormat *pShape, uno::Any &rAny, SdrObject *pObj)
SwDocShell * GetDocShell()
Definition: doc.hxx:1351
#define UNO_NAME_BOTTOM_BORDER
Definition: unoprnms.hxx:360
tools::Long getWidth() const
virtual SdrObjList * getChildrenOfSdrObject() const
static bool hasTextFrame(const SdrObject *pObj)
Returns true if the SdrObject has a SwTextFrame otherwise false.
#define UNO_NAME_RELATIVE_HEIGHT_RELATION
Definition: unoprnms.hxx:193
constexpr tools::Long Left() const
virtual bool QueryValue(css::uno::Any &rVal, sal_uInt8 nMemberId=0) const override
Definition: atrfrm.cxx:2148
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
SwNodeIndex nNode
Definition: pam.hxx:38
#define UNO_NAME_IS_FOLLOWING_TEXT_FLOW
Definition: unoprnms.hxx:744
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
#define UNO_NAME_ALLOW_OVERLAP
Definition: unoprnms.hxx:870
constexpr TypedWhichId< SdrTextVertAdjustItem > RES_TEXT_VERT_ADJUST(130)
sal_uInt16 GetPageNum() const
Definition: fmtanchr.hxx:66
SwTwips GetPos() const
Definition: fmtornt.hxx:92
virtual void SetModified()=0
Must be called manually at changes of format.
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
virtual Point GetRelativePos() const
#define MID_VERTORIENT_RELATION
Definition: unomid.h:35
static sal_Int32 getOrdNum(const SdrObject *pObject)
Get the order of the shape, excluding TextBoxes.
SdrObject * GetObj(size_t nNum) const
const css::uno::WeakReference< css::drawing::XShape > & getWeakUnoShape() const
void RecalcObjOrdNums()
Definition: doc.hxx:187
virtual bool IsTextBox() const
size_t GetObjCount() const
OUString GetUniqueFrameName() const
Definition: doclay.cxx:1377
#define RIGHT_BORDER_DISTANCE
constexpr OUStringLiteral UNO_NAME_TEXT_UPPERDIST
Textboxes are basically textframe + shape pairs.
SwNode & GetNode() const
Definition: ndindex.hxx:119
Content, content of frame (header, footer, fly).
Definition: fmtcntnt.hxx:31
constexpr TypedWhichId< SvxOpaqueItem > RES_OPAQUE(99)
#define UNO_NAME_WRITING_MODE
Definition: unoprnms.hxx:694
#define UNO_NAME_ANCHOR_PAGE_NO
Definition: unoprnms.hxx:230
#define UNO_NAME_VERT_ORIENT
Definition: unoprnms.hxx:332
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:55
EmbeddedObjectRef * pObject
WhichRangesContainer const aFrameFormatSetRange(svl::Items< RES_FRMATR_BEGIN, RES_FRMATR_END-1, RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1, XATTR_FILL_FIRST, XATTR_FILL_LAST >)
static css::uno::Any queryInterface(const SwFrameFormat *pShape, const css::uno::Type &rType, SdrObject *pObj)
Get interface of a shape's TextBox, if there is any.
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:743
std::map< const SwFrameFormat *, const SwFrameFormat * > SavedLink
Maps a draw format to a fly format.
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(156)
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
Definition: doc.cxx:155
void AddTextBox(SdrObject *pDrawObject, SwFrameFormat *pNewTextBox)
constexpr OUStringLiteral UNO_NAME_TEXT_VERTADJUST
constexpr OUStringLiteral UNO_NAME_TEXT_LEFTDIST
virtual const tools::Rectangle & GetSnapRect() const
constexpr auto convertTwipToMm100(N n)
tools::Long getHeight() const
static css::uno::Reference< css::text::XTextFrame > getUnoTextFrame(css::uno::Reference< css::drawing::XShape > const &xShape)
If we have an associated TextFrame, then return its XTextFrame.
constexpr TypedWhichId< SwFormatVertOrient > RES_VERT_ORIENT(102)
#define UNO_NAME_RELATIVE_WIDTH_RELATION
Definition: unoprnms.hxx:191
constexpr TypedWhichId< SwDrawFrameFormat > RES_DRAWFRMFMT(159)
#define UNO_NAME_CHAIN_NEXT_NAME
Definition: unoprnms.hxx:234
#define MID_FRMSIZE_SIZE
Definition: unomid.h:70
constexpr TypedWhichId< SwFormatHoriOrient > RES_HORI_ORIENT(103)
SdrPage * getSdrPageFromSdrObject() const
constexpr OUStringLiteral UNO_NAME_FILL_TRANSPARENCE
#define MID_FOLLOW_TEXT_FLOW
Definition: unomid.h:152
const OUString & GetName() const
Definition: format.hxx:131
int nCount
#define UNO_NAME_SIZE
Definition: unoprnms.hxx:306
virtual css::uno::Reference< css::drawing::XShape > getUnoShape()
Mode eMode
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType, const SdrObject *pObject=nullptr)
Is the frame format a text box?
#define UNO_NAME_VERT_ORIENT_RELATION
Definition: unoprnms.hxx:335
static tools::Rectangle getRelativeTextRectangle(SdrObject *pShape)
Return the textbox rectangle of a draw shape (in relative twips).
#define FN_TEXT_RANGE
Definition: cmdid.h:817
constexpr TypedWhichId< SwFormatWrapInfluenceOnObjPos > RES_WRAP_INFLUENCE_ON_OBJPOS(125)
Specific frame formats (frames, DrawObjects).
constexpr bool IsEmpty() const
#define LEFT_BORDER_DISTANCE
static void saveLinks(const SwFrameFormats &rFormats, std::map< const SwFrameFormat *, const SwFrameFormat * > &rLinks)
Saves the current shape -> textbox links in a map, so they can be restored later. ...
constexpr OUStringLiteral UNO_NAME_TEXT_WORDWRAP
#define UNO_NAME_HORI_ORIENT
Definition: unoprnms.hxx:263
#define MID_CHAIN_NEXTNAME
Definition: unomid.h:57
static void synchronizeGroupTextBoxProperty(bool pFunc(SwFrameFormat *, SdrObject *), SwFrameFormat *pFormat, SdrObject *pObj)
Calls the method given by pFunc with every textboxes of the group given by pFormat.
#define MID_L_MARGIN
const SwFormatFollowTextFlow & GetFollowTextFlow(bool=true) const
#define MID_ANCHOR_ANCHORTYPE
Definition: unomid.h:43
Style of a layout element.
Definition: frmfmt.hxx:59
#define MID_HORIORIENT_POSITION
Definition: unomid.h:40
static void updateTextBoxMargin(SdrObject *pObj)
Copy shape attributes to the text frame.
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
int i
#define UNO_NAME_RIGHT_BORDER
Definition: unoprnms.hxx:358
T & StaticWhichCast(TypedWhichId< T > nId)
#define MID_FRMSIZE_WIDTH_TYPE
Definition: unomid.h:86
static void set(SwFrameFormat *pShape, SdrObject *pObject, css::uno::Reference< css::text::XTextFrame > xNew)
Sets the given textframe as textbox for the given (group member) shape.
constexpr OUStringLiteral UNO_NAME_TEXT_RIGHTDIST
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:108
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
static void restoreLinks(std::set< ZSortFly > &rOld, std::vector< SwFrameFormat * > &rNew, SavedLink &rSavedLinks)
Undo the effect of saveLinks() + individual resetLink() calls.
#define UNO_NAME_PARA_ADJUST
Definition: unoprnms.hxx:173
constexpr OUStringLiteral UNO_NAME_TEXT_AUTOGROWHEIGHT
#define MID_VERTORIENT_POSITION
Definition: unomid.h:36
SwTextBoxNode()=delete
void SetPos(SwTwips nNew)
Definition: fmtornt.hxx:60
FlyAnchors.
Definition: fmtanchr.hxx:34
tools::Long GetLeft() const
const SdrPage * GetPage(sal_uInt16 nPgNum) const
virtual const SwDrawModel * GetDrawModel() const =0
Draw Model and id accessors.
float u
#define BOTTOM_BORDER_DISTANCE
static bool syncTextBoxSize(SwFrameFormat *pShape, SdrObject *pObj)
Sets the correct size of textframe depending on the given SdrObject.
static css::text::TextContentAnchorType mapAnchorType(const RndStdIds &rAnchorID)
There are two types of enum of anchor type, so this function maps this.
static void getProperty(SwFrameFormat const *pShape, sal_uInt16 nWID, sal_uInt8 nMemberID, css::uno::Any &rValue)
Get a property of the underlying TextFrame.
css::uno::Reference< css::frame::XModel3 > GetBaseModel() const
sal_uInt32 GetOrdNum() const
IDocumentState const & getIDocumentState() const
Definition: doc.cxx:394
css::text::WrapTextMode GetSurround() const
Definition: fmtsrnd.hxx:51
constexpr tools::Long Top() const
#define UNO_NAME_LEFT_BORDER
Definition: unoprnms.hxx:357
Connection (text flow) between two FlyFrames.
Definition: fmtcnct.hxx:31
#define MID_R_MARGIN
#define MID_FRMSIZE_IS_AUTO_HEIGHT
Definition: unomid.h:77
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:139
static bool changeAnchor(SwFrameFormat *pShape, SdrObject *pObj)
Sets the anchor of the associated textframe of the given shape, and returns true on success...
tools::Long GetHeight() const
#define UNO_NAME_LEFT_BORDER_DISTANCE
Definition: unoprnms.hxx:362
#define UNO_NAME_CHAIN_PREV_NAME
Definition: unoprnms.hxx:235
bool XTextRangeToSwPaM(SwUnoInternalPaM &rToFill, const uno::Reference< text::XTextRange > &xTextRange,::sw::TextRangeMode const eMode)
Definition: unoobj2.cxx:1107
#define UNO_NAME_RIGHT_MARGIN
Definition: unoprnms.hxx:69
constexpr Point Center() const
#define UNO_NAME_TOP_BORDER
Definition: unoprnms.hxx:359
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:448
#define UNO_NAME_TOP_BORDER_DISTANCE
Definition: unoprnms.hxx:364
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:82
#define UNO_NAME_TEXT_VERT_ADJUST
Definition: unoprnms.hxx:859
#define UNO_NAME_SURROUND
Definition: unoprnms.hxx:313
#define MID_HORIORIENT_ORIENT
Definition: unomid.h:38
#define MID_FRMSIZE_REL_HEIGHT_RELATION
Definition: unomid.h:88
constexpr Size GetSize() const
constexpr TypedWhichId< SwFormatChain > RES_CHAIN(114)
#define MID_CHAIN_PREVNAME
Definition: unomid.h:56
const SwFormatChain & GetChain(bool=true) const
Definition: fmtcnct.hxx:70
iterator find(const OUString &rKey)
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:88
#define UNO_NAME_LEFT_MARGIN
Definition: unoprnms.hxx:68
#define MID_VERTORIENT_ORIENT
Definition: unomid.h:34
unsigned char sal_uInt8
#define UNO_NAME_BOTTOM_BORDER_DISTANCE
Definition: unoprnms.hxx:365
#define UNO_NAME_ANCHOR_TYPE
Definition: unoprnms.hxx:228
bool IsTextBoxActive(const SdrObject *pDrawObject) const
SwTwips GetPos() const
Definition: fmtornt.hxx:59
#define MID_FRMSIZE_REL_WIDTH_RELATION
Definition: unomid.h:87
#define SAL_INFO(area, stream)
void SetOtherTextBoxFormats(const std::shared_ptr< SwTextBoxNode > &rNew)
Definition: frmfmt.hxx:106
void SetTextBoxActive(const SdrObject *pDrawObject)
bool IsGroupTextBox() const
static void destroy(const SwFrameFormat *pShape, const SdrObject *pObject)
Destroy a TextBox for a shape.
#define UNO_NAME_HORI_ORIENT_RELATION
Definition: unoprnms.hxx:266
static SW_DLLPUBLIC css::uno::Reference< css::text::XTextFrame > CreateXTextFrame(SwDoc &rDoc, SwFrameFormat *pFrameFormat)
Definition: unoframe.cxx:3220
#define TOP_BORDER_DISTANCE
void SetSize(const Size &rSize)
void * p
static css::uno::Reference< css::uno::XInterface > MakeInstance(SwServiceType nObjectType, SwDoc &rDoc)
Definition: unocoll.cxx:517
bool GetTextBounds(tools::Rectangle &rTextBound) const
constexpr TypedWhichId< SvxLRSpaceItem > RES_LR_SPACE(91)
static void syncFlyFrameAttr(SwFrameFormat &rShape, SfxItemSet const &rSet, SdrObject *pObj)
Similar to syncProperty(), but used by the internal API (e.g. for UI purposes).
sal_Int16 GetVertOrient() const
Definition: fmtornt.hxx:54
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
SdrObject * getParentSdrObjectFromSdrObject() const
SwTableNode * FindTableNode()
Search table node, in which it is.
Definition: node.cxx:358
void SetPos(SwTwips nNew)
Definition: fmtornt.hxx:93
#define UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT
Definition: unoprnms.hxx:594
#define MID_HORIORIENT_RELATION
Definition: unomid.h:39
const SwStartNode * FindFlyStartNode() const
Definition: node.hxx:200
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
#define SAL_WARN(area, stream)
RndStdIds
#define UNO_NAME_SIZE_TYPE
Definition: unoprnms.hxx:261
virtual const tools::Rectangle & GetLogicRect() const
static void create(SwFrameFormat *pShape, SdrObject *pObject, bool bCopyText=false)
Create a TextBox for a shape.
static bool DoTextBoxZOrderCorrection(SwFrameFormat *pShape, const SdrObject *pObj)
constexpr OUStringLiteral UNO_NAME_TEXT_LOWERDIST
#define UNO_NAME_RIGHT_BORDER_DISTANCE
Definition: unoprnms.hxx:363
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:136
#define UNO_NAME_WIDTH_TYPE
Definition: unoprnms.hxx:745
#define UNO_NAME_VERT_ORIENT_POSITION
Definition: unoprnms.hxx:334
static void syncProperty(SwFrameFormat *pShape, sal_uInt16 nWID, sal_uInt8 nMemberID, const css::uno::Any &rValue, SdrObject *pObj=nullptr)
Sync property of TextBox with the one of the shape.
constexpr TypedWhichId< SwFormatFollowTextFlow > RES_FOLLOW_TEXT_FLOW(123)
const std::shared_ptr< SwTextBoxNode > & GetOtherTextBoxFormats() const
Definition: frmfmt.hxx:105
static std::vector< SwFrameFormat * > CollectTextBoxes(const SdrObject *pGroupObject, SwFrameFormat *pFormat)
Collect all textboxes of the group given by the pGroupObj Parameter.
constexpr OUStringLiteral UNO_NAME_TEXT_WRITINGMODE
std::map< SdrObject *, SwFrameFormat * > GetAllTextBoxes() const
#define UNO_NAME_OPAQUE
Definition: unoprnms.hxx:285
sal_uInt16 Which() const
SdrObject * FindRealSdrObject()
Definition: atrfrm.cxx:2763
void SetTextBoxInactive(const SdrObject *pDrawObject)
constexpr TypedWhichId< SwFormatAnchor > RES_ANCHOR(104)
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1318
sal_Int16 nValue
void DelTextBox(const SdrObject *pDrawObject, bool bDelFromDoc=false)
#define MID_ALLOW_OVERLAP
Definition: unomid.h:149
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1585
#define CONVERT_TWIPS
static void getShapeWrapThrough(const SwFrameFormat *pTextBox, bool &rWrapThrough)
If pTextBox is a textbox, then set rWrapThrough to the surround of its shape.
static bool doTextBoxPositioning(SwFrameFormat *pShape, SdrObject *pObj)
Does the positioning for the associated textframe of the shape, and returns true on success...
const SvxLRSpaceItem & GetLRSpace(bool=true) const
Definition: frmatr.hxx:74