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 <frmfmt.hxx>
30 #include <frameformats.hxx>
31 
32 #include <editeng/unoprnms.hxx>
33 #include <editeng/memberids.h>
34 #include <svx/svdoashp.hxx>
35 #include <svx/svdpage.hxx>
36 #include <svl/itemiter.hxx>
38 #include <sal/log.hxx>
39 #include <tools/UnitConversion.hxx>
40 #include <svx/swframetypes.hxx>
41 #include <drawdoc.hxx>
42 #include <IDocumentUndoRedo.hxx>
44 
45 #include <com/sun/star/document/XActionLockable.hpp>
46 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
47 #include <com/sun/star/text/SizeType.hpp>
48 #include <com/sun/star/text/TextContentAnchorType.hpp>
49 #include <com/sun/star/text/WrapTextMode.hpp>
50 #include <com/sun/star/text/XTextDocument.hpp>
51 #include <com/sun/star/text/XTextFrame.hpp>
52 #include <com/sun/star/table/BorderLine2.hpp>
53 #include <com/sun/star/text/WritingMode.hpp>
54 #include <com/sun/star/text/WritingMode2.hpp>
55 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
56 #include <com/sun/star/style/ParagraphAdjust.hpp>
57 
58 using namespace com::sun::star;
59 
60 void SwTextBoxHelper::create(SwFrameFormat* pShape, bool bCopyText)
61 {
62  // If TextBox wasn't enabled previously
63  if (pShape->GetAttrSet().HasItem(RES_CNTNT) && pShape->GetOtherTextBoxFormat())
64  return;
65 
66  // Store the current text content of the shape
67  OUString sCopyableText;
68 
69  if (bCopyText)
70  {
71  if (auto pSdrShape = pShape->FindRealSdrObject())
72  {
73  uno::Reference<text::XText> xSrcCnt(pSdrShape->getWeakUnoShape(), uno::UNO_QUERY);
74  auto xCur = xSrcCnt->createTextCursor();
75  xCur->gotoStart(false);
76  xCur->gotoEnd(true);
77  sCopyableText = xCur->getText()->getString();
78  }
79  }
80 
81  // Create the associated TextFrame and insert it into the document.
82  uno::Reference<text::XTextContent> xTextFrame(
84  uno::UNO_QUERY);
85  uno::Reference<text::XTextDocument> xTextDocument(
86  pShape->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
87  uno::Reference<text::XTextContentAppend> xTextContentAppend(xTextDocument->getText(),
88  uno::UNO_QUERY);
89  try
90  {
91  SdrObject* pSourceSDRShape = pShape->FindRealSdrObject();
92  uno::Reference<text::XTextContent> XSourceShape(pSourceSDRShape->getUnoShape(),
93  uno::UNO_QUERY_THROW);
94  xTextContentAppend->insertTextContentWithProperties(
95  xTextFrame, uno::Sequence<beans::PropertyValue>(), XSourceShape->getAnchor());
96  }
97  catch (uno::Exception&)
98  {
99  xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>());
100  }
101  // Link FLY and DRAW formats, so it becomes a text box (needed for syncProperty calls).
102  uno::Reference<text::XTextFrame> xRealTextFrame(xTextFrame, uno::UNO_QUERY);
103  auto pTextFrame = dynamic_cast<SwXTextFrame*>(xRealTextFrame.get());
104  assert(nullptr != pTextFrame);
105  SwFrameFormat* pFormat = pTextFrame->GetFrameFormat();
106 
107  assert(nullptr != dynamic_cast<SwDrawFrameFormat*>(pShape));
108  assert(nullptr != dynamic_cast<SwFlyFrameFormat*>(pFormat));
109 
110  pShape->SetOtherTextBoxFormat(pFormat);
111  pFormat->SetOtherTextBoxFormat(pShape);
112 
113  // Initialize properties.
114  uno::Reference<beans::XPropertySet> xPropertySet(xTextFrame, uno::UNO_QUERY);
115  uno::Any aEmptyBorder = uno::makeAny(table::BorderLine2());
116  xPropertySet->setPropertyValue(UNO_NAME_TOP_BORDER, aEmptyBorder);
117  xPropertySet->setPropertyValue(UNO_NAME_BOTTOM_BORDER, aEmptyBorder);
118  xPropertySet->setPropertyValue(UNO_NAME_LEFT_BORDER, aEmptyBorder);
119  xPropertySet->setPropertyValue(UNO_NAME_RIGHT_BORDER, aEmptyBorder);
120 
121  xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::makeAny(sal_Int32(100)));
122 
123  xPropertySet->setPropertyValue(UNO_NAME_SIZE_TYPE, uno::makeAny(text::SizeType::FIX));
124 
125  xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
126 
127  uno::Reference<container::XNamed> xNamed(xTextFrame, uno::UNO_QUERY);
128  xNamed->setName(pShape->GetDoc()->GetUniqueFrameName());
129 
130  // Link its text range to the original shape.
131  uno::Reference<text::XTextRange> xTextBox(xTextFrame, uno::UNO_QUERY_THROW);
132  SwUnoInternalPaM aInternalPaM(*pShape->GetDoc());
133  if (sw::XTextRangeToSwPaM(aInternalPaM, xTextBox))
134  {
135  SwAttrSet aSet(pShape->GetAttrSet());
136  SwFormatContent aContent(aInternalPaM.GetNode().StartOfSectionNode());
137  aSet.Put(aContent);
138  pShape->SetFormatAttr(aSet);
139  }
140 
141  DoTextBoxZOrderCorrection(pShape);
142  // Also initialize the properties, which are not constant, but inherited from the shape's ones.
143  uno::Reference<drawing::XShape> xShape(pShape->FindRealSdrObject()->getUnoShape(),
144  uno::UNO_QUERY);
145  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::makeAny(xShape->getSize()));
146 
147  uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
148  syncProperty(pShape, RES_FOLLOW_TEXT_FLOW, MID_FOLLOW_TEXT_FLOW,
149  xShapePropertySet->getPropertyValue(UNO_NAME_IS_FOLLOWING_TEXT_FLOW));
150  syncProperty(pShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
151  xShapePropertySet->getPropertyValue(UNO_NAME_ANCHOR_TYPE));
152  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
153  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT));
154  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
155  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION));
156  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
157  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT));
158  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
159  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION));
160  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
161  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION));
162  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
163  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION));
164  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
165  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT));
166  syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0,
167  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST));
168  text::WritingMode eMode;
169  if (xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_WRITINGMODE) >>= eMode)
170  syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)));
171 
172  // Check if the shape had text before and move it to the new textframe
173  if (!bCopyText || sCopyableText.isEmpty())
174  return;
175 
176  auto pSdrShape = pShape->FindRealSdrObject();
177  if (pSdrShape)
178  {
179  auto pSourceText = dynamic_cast<SdrTextObj*>(pSdrShape);
180  uno::Reference<text::XTextRange> xDestText(xRealTextFrame, uno::UNO_QUERY);
181 
182  xDestText->setString(sCopyableText);
183 
184  if (pSourceText)
185  pSourceText->SetText(OUString());
186 
187  pShape->GetDoc()->getIDocumentState().SetModified();
188  }
189 }
190 
192 {
193  // If a TextBox was enabled previously
194  if (pShape->GetAttrSet().HasItem(RES_CNTNT))
195  {
196  SwFrameFormat* pFormat = pShape->GetOtherTextBoxFormat();
197 
198  // Unlink the TextBox's text range from the original shape.
199  pShape->ResetFormatAttr(RES_CNTNT);
200 
201  // Delete the associated TextFrame.
202  if (pFormat)
203  pShape->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(pFormat);
204  }
205 }
206 
207 bool SwTextBoxHelper::isTextBox(const SwFrameFormat* pFormat, sal_uInt16 nType)
208 {
209  assert(nType == RES_FLYFRMFMT || nType == RES_DRAWFRMFMT);
210  if (!pFormat || pFormat->Which() != nType || !pFormat->GetAttrSet().HasItem(RES_CNTNT))
211  return false;
212 
213  sal_uInt16 nOtherType = (pFormat->Which() == RES_FLYFRMFMT) ? sal_uInt16(RES_DRAWFRMFMT)
214  : sal_uInt16(RES_FLYFRMFMT);
215  SwFrameFormat* pOtherFormat = pFormat->GetOtherTextBoxFormat();
216  if (!pOtherFormat)
217  return false;
218 
219  assert(pOtherFormat->Which() == nOtherType);
220  if (pOtherFormat->Which() != nOtherType)
221  return false;
222 
223  const SwFormatContent& rContent = pFormat->GetContent();
224  return pOtherFormat->GetAttrSet().HasItem(RES_CNTNT) && pOtherFormat->GetContent() == rContent;
225 }
226 
228 {
229  if (!pObj)
230  return false;
231 
232  uno::Reference<drawing::XShape> xShape(pObj->getWeakUnoShape(), uno::UNO_QUERY);
233  if (!xShape)
234  return false;
236 }
237 
238 sal_Int32 SwTextBoxHelper::getCount(SdrPage const* pPage)
239 {
240  sal_Int32 nRet = 0;
241  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
242  {
243  SdrObject* p = pPage->GetObj(i);
244  if (p && p->IsTextBox())
245  continue;
246  ++nRet;
247  }
248  return nRet;
249 }
250 
251 sal_Int32 SwTextBoxHelper::getCount(const SwDoc& rDoc)
252 {
253  sal_Int32 nRet = 0;
254  const SwFrameFormats& rSpzFrameFormats = *rDoc.GetSpzFrameFormats();
255  for (const auto pFormat : rSpzFrameFormats)
256  {
257  if (isTextBox(pFormat, RES_FLYFRMFMT))
258  ++nRet;
259  }
260  return nRet;
261 }
262 
263 uno::Any SwTextBoxHelper::getByIndex(SdrPage const* pPage, sal_Int32 nIndex)
264 {
265  if (nIndex < 0)
266  throw lang::IndexOutOfBoundsException();
267 
268  SdrObject* pRet = nullptr;
269  sal_Int32 nCount = 0; // Current logical index.
270  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
271  {
272  SdrObject* p = pPage->GetObj(i);
273  if (p && p->IsTextBox())
274  continue;
275  if (nCount == nIndex)
276  {
277  pRet = p;
278  break;
279  }
280  ++nCount;
281  }
282 
283  if (!pRet)
284  throw lang::IndexOutOfBoundsException();
285 
286  return uno::makeAny(uno::Reference<drawing::XShape>(pRet->getUnoShape(), uno::UNO_QUERY));
287 }
288 
289 sal_Int32 SwTextBoxHelper::getOrdNum(const SdrObject* pObject)
290 {
291  if (const SdrPage* pPage = pObject->getSdrPageFromSdrObject())
292  {
293  sal_Int32 nOrder = 0; // Current logical order.
294  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
295  {
296  SdrObject* p = pPage->GetObj(i);
297  if (p && p->IsTextBox())
298  continue;
299  if (p == pObject)
300  return nOrder;
301  ++nOrder;
302  }
303  }
304 
305  SAL_WARN("sw.core", "SwTextBoxHelper::getOrdNum: no page or page doesn't contain the object");
306  return pObject->GetOrdNum();
307 }
308 
309 void SwTextBoxHelper::getShapeWrapThrough(const SwFrameFormat* pTextBox, bool& rWrapThrough)
310 {
312  if (pShape)
313  rWrapThrough = pShape->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
314 }
315 
317  sal_uInt16 nType)
318 {
319  if (!isTextBox(pFormat, nType))
320  return nullptr;
321  return pFormat->GetOtherTextBoxFormat();
322 }
323 
324 SwFrameFormat* SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference<drawing::XShape> const& xShape)
325 {
326  auto pShape = dynamic_cast<SwXShape*>(xShape.get());
327  if (!pShape)
328  return nullptr;
329 
330  SwFrameFormat* pFormat = pShape->GetFrameFormat();
331  return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT);
332 }
333 
334 uno::Reference<text::XTextFrame>
335 SwTextBoxHelper::getUnoTextFrame(uno::Reference<drawing::XShape> const& xShape)
336 {
337  if (xShape)
338  {
339  auto pFrameFormat = SwTextBoxHelper::getOtherTextBoxFormat(xShape);
340  if (pFrameFormat)
341  {
342  auto pSdrObj = pFrameFormat->FindSdrObject();
343  if (pSdrObj && pSdrObj->IsTextBox())
344  {
345  return uno::Reference<css::text::XTextFrame>(pSdrObj->getUnoShape(),
346  uno::UNO_QUERY);
347  }
348  }
349  }
350  return uno::Reference<css::text::XTextFrame>();
351 }
352 
353 template <typename T> static void lcl_queryInterface(const SwFrameFormat* pShape, uno::Any& rAny)
354 {
356  {
357  uno::Reference<T> const xInterface(
358  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
359  rAny <<= xInterface;
360  }
361 }
362 
364 {
365  uno::Any aRet;
366 
368  {
369  lcl_queryInterface<text::XTextAppend>(pShape, aRet);
370  }
371  else if (rType == cppu::UnoType<css::text::XText>::get())
372  {
373  lcl_queryInterface<text::XText>(pShape, aRet);
374  }
375  else if (rType == cppu::UnoType<css::text::XTextRange>::get())
376  {
377  lcl_queryInterface<text::XTextRange>(pShape, aRet);
378  }
379 
380  return aRet;
381 }
382 
384 {
385  tools::Rectangle aRet;
386  aRet.SetEmpty();
387  auto pSdrShape = pShape->FindRealSdrObject();
388  auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pSdrShape);
389  if (pCustomShape)
390  {
391  // Need to temporarily release the lock acquired in
392  // SdXMLShapeContext::AddShape(), otherwise we get an empty rectangle,
393  // see EnhancedCustomShapeEngine::getTextBounds().
394  uno::Reference<document::XActionLockable> xLockable(pCustomShape->getUnoShape(),
395  uno::UNO_QUERY);
396  sal_Int16 nLocks = 0;
397  if (xLockable.is())
398  nLocks = xLockable->resetActionLocks();
399  pCustomShape->GetTextBounds(aRet);
400  if (nLocks)
401  xLockable->setActionLocks(nLocks);
402  }
403  else if (pSdrShape)
404  {
405  // fallback - get *any* bound rect we can possibly get hold of
406  aRet = pSdrShape->GetCurrentBoundRect();
407  }
408 
409  if (!bAbsolute && pSdrShape)
410  {
411  // Relative, so count the logic (reference) rectangle, see the EnhancedCustomShape2d ctor.
412  Point aPoint(pSdrShape->GetSnapRect().Center());
413  Size aSize(pSdrShape->GetLogicRect().GetSize());
414  aPoint.AdjustX(-(aSize.Width() / 2));
415  aPoint.AdjustY(-(aSize.Height() / 2));
416  tools::Rectangle aLogicRect(aPoint, aSize);
417  aRet.Move(-1 * aLogicRect.Left(), -1 * aLogicRect.Top());
418  }
419 
420  return aRet;
421 }
422 
423 void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rPropertyName,
424  const css::uno::Any& rValue)
425 {
426  // Textframes does not have valid horizontal adjust property, so map it to paragraph adjust property
427  if (rPropertyName == UNO_NAME_TEXT_HORZADJUST)
428  {
429  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
430  if (!pFormat)
431  return;
432 
433  auto xTextFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat);
434  uno::Reference<text::XTextCursor> xCursor = xTextFrame->getText()->createTextCursor();
435 
436  // Select all paragraphs in the textframe
437  xCursor->gotoStart(false);
438  xCursor->gotoEnd(true);
439  uno::Reference<beans::XPropertySet> xFrameParaProps(xCursor, uno::UNO_QUERY);
440 
441  // And simply map the property
442  const auto eValue = rValue.get<drawing::TextHorizontalAdjust>();
443  switch (eValue)
444  {
445  case drawing::TextHorizontalAdjust::TextHorizontalAdjust_CENTER:
446  xFrameParaProps->setPropertyValue(
448  uno::makeAny(style::ParagraphAdjust::ParagraphAdjust_CENTER)); //3
449  break;
450  case drawing::TextHorizontalAdjust::TextHorizontalAdjust_LEFT:
451  xFrameParaProps->setPropertyValue(
453  uno::makeAny(style::ParagraphAdjust::ParagraphAdjust_LEFT)); //0
454  break;
455  case drawing::TextHorizontalAdjust::TextHorizontalAdjust_RIGHT:
456  xFrameParaProps->setPropertyValue(
458  uno::makeAny(style::ParagraphAdjust::ParagraphAdjust_RIGHT)); //1
459  break;
460  default:
461  SAL_WARN("sw.core",
462  "SwTextBoxHelper::syncProperty: unhandled TextHorizontalAdjust: "
463  << static_cast<sal_Int32>(eValue));
464  break;
465  }
466  return;
467  }
468 
469  if (rPropertyName == u"CustomShapeGeometry")
470  {
471  // CustomShapeGeometry changes the textbox position offset and size, so adjust both.
472  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any());
473 
474  SdrObject* pObject = pShape->FindRealSdrObject();
475  if (pObject)
476  {
477  tools::Rectangle aRectangle(pObject->GetSnapRect());
478  syncProperty(
480  uno::makeAny(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Left()))));
481  syncProperty(
483  uno::makeAny(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Top()))));
484  }
485 
486  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
487  if (!pFormat)
488  return;
489 
490  comphelper::SequenceAsHashMap aCustomShapeGeometry(rValue);
491  auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
492  if (it == aCustomShapeGeometry.end())
493  {
494  it = aCustomShapeGeometry.find("TextRotateAngle");
495  }
496 
497  if (it != aCustomShapeGeometry.end())
498  {
499  auto nAngle = it->second.has<sal_Int32>() ? it->second.get<sal_Int32>() : 0;
500  if (nAngle == 0)
501  {
502  nAngle = it->second.has<double>() ? it->second.get<double>() : 0;
503  }
504 
505  sal_Int16 nDirection = 0;
506  switch (nAngle)
507  {
508  case -90:
509  nDirection = text::WritingMode2::TB_RL;
510  break;
511  case -270:
512  nDirection = text::WritingMode2::BT_LR;
513  break;
514  default:
515  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled property value: "
516  "CustomShapeGeometry:TextPreRotateAngle: "
517  << nAngle);
518  break;
519  }
520 
521  if (nDirection)
522  {
523  syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(nDirection));
524  }
525  }
526  }
527  else if (rPropertyName == UNO_NAME_TEXT_VERT_ADJUST)
528  syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0, rValue);
529  else if (rPropertyName == UNO_NAME_TEXT_AUTOGROWHEIGHT)
530  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, rValue);
531  else if (rPropertyName == UNO_NAME_TEXT_LEFTDIST)
532  syncProperty(pShape, RES_BOX, LEFT_BORDER_DISTANCE, rValue);
533  else if (rPropertyName == UNO_NAME_TEXT_RIGHTDIST)
534  syncProperty(pShape, RES_BOX, RIGHT_BORDER_DISTANCE, rValue);
535  else if (rPropertyName == UNO_NAME_TEXT_UPPERDIST)
536  syncProperty(pShape, RES_BOX, TOP_BORDER_DISTANCE, rValue);
537  else if (rPropertyName == UNO_NAME_TEXT_LOWERDIST)
538  syncProperty(pShape, RES_BOX, BOTTOM_BORDER_DISTANCE, rValue);
539  else if (rPropertyName == UNO_NAME_TEXT_WRITINGMODE)
540  {
541  text::WritingMode eMode;
542  sal_Int16 eMode2;
543  if (rValue >>= eMode)
544  syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(sal_Int16(eMode)));
545  else if (rValue >>= eMode2)
546  syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(eMode2));
547  }
548  else
549  SAL_INFO("sw.core", "SwTextBoxHelper::syncProperty: unhandled property: "
550  << static_cast<OUString>(rPropertyName));
551 }
552 
553 void SwTextBoxHelper::getProperty(SwFrameFormat const* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
554  css::uno::Any& rValue)
555 {
556  if (!pShape)
557  return;
558 
559  nMemberID &= ~CONVERT_TWIPS;
560 
561  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
562  if (!pFormat)
563  return;
564 
565  if (nWID != RES_CHAIN)
566  return;
567 
568  switch (nMemberID)
569  {
570  case MID_CHAIN_PREVNAME:
571  case MID_CHAIN_NEXTNAME:
572  {
573  const SwFormatChain& rChain = pFormat->GetChain();
574  rChain.QueryValue(rValue, nMemberID);
575  }
576  break;
577  case MID_CHAIN_NAME:
578  rValue <<= pFormat->GetName();
579  break;
580  default:
581  SAL_WARN("sw.core", "SwTextBoxHelper::getProperty: unhandled member-id: "
582  << o3tl::narrowing<sal_uInt16>(nMemberID));
583  break;
584  }
585 }
586 
587 css::uno::Any SwTextBoxHelper::getProperty(SwFrameFormat const* pShape, const OUString& rPropName)
588 {
589  if (!pShape)
590  return uno::Any();
591 
592  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
593  if (!pFormat)
594  return uno::Any();
595 
596  uno::Reference<beans::XPropertySet> const xPropertySet(
597  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
598 
599  return xPropertySet->getPropertyValue(rPropName);
600 }
601 
602 void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
603  const css::uno::Any& rValue)
604 {
605  // No shape yet? Then nothing to do, initial properties are set by create().
606  if (!pShape)
607  return;
608 
609  uno::Any aValue(rValue);
610  nMemberID &= ~CONVERT_TWIPS;
611 
612  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
613  if (!pFormat)
614  return;
615 
616  OUString aPropertyName;
617  bool bAdjustX = false;
618  bool bAdjustY = false;
619  bool bAdjustSize = false;
620  switch (nWID)
621  {
622  case RES_HORI_ORIENT:
623  switch (nMemberID)
624  {
626  aPropertyName = UNO_NAME_HORI_ORIENT;
627  break;
629  if (pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
630  aPropertyName = UNO_NAME_HORI_ORIENT_RELATION;
631  else
632  return;
633  break;
635  aPropertyName = UNO_NAME_HORI_ORIENT_POSITION;
636  bAdjustX = true;
637  break;
638  default:
639  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
640  << o3tl::narrowing<sal_uInt16>(nMemberID)
641  << " (which-id: " << nWID << ")");
642  break;
643  }
644  break;
645  case RES_LR_SPACE:
646  {
647  switch (nMemberID)
648  {
649  case MID_L_MARGIN:
650  aPropertyName = UNO_NAME_LEFT_MARGIN;
651  break;
652  case MID_R_MARGIN:
653  aPropertyName = UNO_NAME_RIGHT_MARGIN;
654  break;
655  default:
656  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
657  << o3tl::narrowing<sal_uInt16>(nMemberID)
658  << " (which-id: " << nWID << ")");
659  break;
660  }
661  break;
662  }
663  case RES_VERT_ORIENT:
664  switch (nMemberID)
665  {
667  aPropertyName = UNO_NAME_VERT_ORIENT;
668  break;
670  if (pShape->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
671  aPropertyName = UNO_NAME_VERT_ORIENT_RELATION;
672  else
673  return;
674  break;
676  aPropertyName = UNO_NAME_VERT_ORIENT_POSITION;
677  bAdjustY = true;
678  break;
679  default:
680  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
681  << o3tl::narrowing<sal_uInt16>(nMemberID)
682  << " (which-id: " << nWID << ")");
683  break;
684  }
685  break;
686  case RES_FRM_SIZE:
687  switch (nMemberID)
688  {
690  aPropertyName = UNO_NAME_WIDTH_TYPE;
691  break;
693  aPropertyName = UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT;
694  break;
696  aPropertyName = UNO_NAME_RELATIVE_HEIGHT_RELATION;
697  break;
699  aPropertyName = UNO_NAME_RELATIVE_WIDTH_RELATION;
700  break;
701  default:
702  aPropertyName = UNO_NAME_SIZE;
703  bAdjustSize = true;
704  break;
705  }
706  break;
707  case RES_ANCHOR:
708  switch (nMemberID)
709  {
711  {
712  setWrapThrough(pShape);
713  changeAnchor(pShape);
714  doTextBoxPositioning(pShape);
715 
716  return;
717  }
718  break;
719  default:
720  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
721  << o3tl::narrowing<sal_uInt16>(nMemberID)
722  << " (which-id: " << nWID << ")");
723  break;
724  }
725  break;
726  case FN_TEXT_RANGE:
727  {
728  uno::Reference<text::XTextRange> xRange;
729  rValue >>= xRange;
730  SwUnoInternalPaM aInternalPaM(*pFormat->GetDoc());
731  if (sw::XTextRangeToSwPaM(aInternalPaM, xRange))
732  {
733  SwFormatAnchor aAnchor(pFormat->GetAnchor());
734  aAnchor.SetAnchor(aInternalPaM.Start());
735  pFormat->SetFormatAttr(aAnchor);
736  }
737  }
738  break;
739  case RES_CHAIN:
740  switch (nMemberID)
741  {
742  case MID_CHAIN_PREVNAME:
743  aPropertyName = UNO_NAME_CHAIN_PREV_NAME;
744  break;
745  case MID_CHAIN_NEXTNAME:
746  aPropertyName = UNO_NAME_CHAIN_NEXT_NAME;
747  break;
748  default:
749  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
750  << o3tl::narrowing<sal_uInt16>(nMemberID)
751  << " (which-id: " << nWID << ")");
752  break;
753  }
754  break;
756  aPropertyName = UNO_NAME_TEXT_VERT_ADJUST;
757  break;
758  case RES_BOX:
759  switch (nMemberID)
760  {
762  aPropertyName = UNO_NAME_LEFT_BORDER_DISTANCE;
763  break;
765  aPropertyName = UNO_NAME_RIGHT_BORDER_DISTANCE;
766  break;
767  case TOP_BORDER_DISTANCE:
768  aPropertyName = UNO_NAME_TOP_BORDER_DISTANCE;
769  break;
771  aPropertyName = UNO_NAME_BOTTOM_BORDER_DISTANCE;
772  break;
773  default:
774  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
775  << o3tl::narrowing<sal_uInt16>(nMemberID)
776  << " (which-id: " << nWID << ")");
777  break;
778  }
779  break;
780  case RES_OPAQUE:
781  aPropertyName = UNO_NAME_OPAQUE;
782  break;
783  case RES_FRAMEDIR:
784  aPropertyName = UNO_NAME_WRITING_MODE;
785  break;
787  switch (nMemberID)
788  {
789  case MID_ALLOW_OVERLAP:
790  aPropertyName = UNO_NAME_ALLOW_OVERLAP;
791  break;
792  default:
793  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled member-id: "
794  << o3tl::narrowing<sal_uInt16>(nMemberID)
795  << " (which-id: " << nWID << ")");
796  break;
797  }
798  break;
799  default:
800  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: unhandled which-id: "
801  << nWID << " (member-id: "
802  << o3tl::narrowing<sal_uInt16>(nMemberID) << ")");
803  break;
804  }
805 
806  if (aPropertyName.isEmpty())
807  return;
808 
809  // Position/size should be the text position/size, not the shape one as-is.
810  if (bAdjustX || bAdjustY || bAdjustSize)
811  {
812  tools::Rectangle aRect = getTextRectangle(pShape, /*bAbsolute=*/false);
813  if (!aRect.IsEmpty())
814  {
815  if (bAdjustX || bAdjustY)
816  {
817  sal_Int32 nValue;
818  if (aValue >>= nValue)
819  {
820  if (bAdjustX)
821  nValue += convertTwipToMm100(aRect.getX());
822  else if (bAdjustY)
823  nValue += convertTwipToMm100(aRect.getY());
824  aValue <<= nValue;
825  }
826  }
827  else if (bAdjustSize)
828  {
829  awt::Size aSize(convertTwipToMm100(aRect.getWidth()),
830  convertTwipToMm100(aRect.getHeight()));
831  aValue <<= aSize;
832  }
833  }
834  }
835 
836  uno::Reference<beans::XPropertySet> const xPropertySet(
837  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
838  xPropertySet->setPropertyValue(aPropertyName, aValue);
839 }
840 
842  std::map<const SwFrameFormat*, const SwFrameFormat*>& rLinks)
843 {
844  for (const auto pFormat : rFormats)
845  {
846  if (SwFrameFormat* pTextBox = getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
847  rLinks[pFormat] = pTextBox;
848  }
849 }
850 
851 void SwTextBoxHelper::restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrameFormat*>& rNew,
852  SavedLink& rSavedLinks)
853 {
854  std::size_t i = 0;
855  for (const auto& rIt : rOld)
856  {
857  auto aTextBoxIt = rSavedLinks.find(rIt.GetFormat());
858  if (aTextBoxIt != rSavedLinks.end())
859  {
860  std::size_t j = 0;
861  for (const auto& rJt : rOld)
862  {
863  if (rJt.GetFormat() == aTextBoxIt->second)
864  rNew[i]->SetFormatAttr(rNew[j]->GetContent());
865  ++j;
866  }
867  }
868  ++i;
869  }
870 }
871 
872 text::TextContentAnchorType SwTextBoxHelper::mapAnchorType(const RndStdIds& rAnchorID)
873 {
874  text::TextContentAnchorType aAnchorType;
875  switch (rAnchorID)
876  {
877  case RndStdIds::FLY_AS_CHAR:
878  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AS_CHARACTER;
879  break;
880  case RndStdIds::FLY_AT_CHAR:
881  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_CHARACTER;
882  break;
883  case RndStdIds::FLY_AT_PARA:
884  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH;
885  break;
886  case RndStdIds::FLY_AT_PAGE:
887  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PAGE;
888  break;
889  case RndStdIds::FLY_AT_FLY:
890  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_FRAME;
891  break;
892  default:
893  aAnchorType = text::TextContentAnchorType::TextContentAnchorType_AT_PARAGRAPH;
894  SAL_WARN("sw.core", "SwTextBoxHelper::mapAnchorType: Unknown AnchorType!");
895  break;
896  }
897  return aAnchorType;
898 }
899 
901 {
902  SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT);
903  if (!pFormat)
904  return;
905 
906  const bool bInlineAnchored = rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR;
907  SfxItemSet aTextBoxSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange);
908 
909  SfxItemIter aIter(rSet);
910  const SfxPoolItem* pItem = aIter.GetCurItem();
911 
912  do
913  {
914  switch (pItem->Which())
915  {
916  case RES_VERT_ORIENT:
917  {
918  // The new position can be with anchor changing so sync it!
919  const text::TextContentAnchorType aNewAnchorType
920  = mapAnchorType(rShape.GetAnchor().GetAnchorId());
921  syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType));
922  if (bInlineAnchored)
923  return;
925 
926  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
927  if (!aRect.IsEmpty())
928  aOrient.SetPos(aOrient.GetPos() + aRect.getY());
929 
930  if (rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
931  && rShape.GetAnchor().GetPageNum() != 0)
932  aOrient.SetRelationOrient(rShape.GetVertOrient().GetRelationOrient());
933  aTextBoxSet.Put(aOrient);
934 
935  // restore height (shrunk for extending beyond the page bottom - tdf#91260)
936  SwFormatFrameSize aSize(pFormat->GetFrameSize());
937  if (!aRect.IsEmpty())
938  {
939  aSize.SetHeight(aRect.getHeight());
940  aTextBoxSet.Put(aSize);
941  }
942  }
943  break;
944  case RES_HORI_ORIENT:
945  {
946  // The new position can be with anchor changing so sync it!
947  const text::TextContentAnchorType aNewAnchorType
948  = mapAnchorType(rShape.GetAnchor().GetAnchorId());
949  syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE, uno::Any(aNewAnchorType));
950  if (bInlineAnchored)
951  return;
953 
954  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
955  if (!aRect.IsEmpty())
956  aOrient.SetPos(aOrient.GetPos() + aRect.getX());
957 
958  if (rShape.GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PAGE
959  && rShape.GetAnchor().GetPageNum() != 0)
960  aOrient.SetRelationOrient(rShape.GetHoriOrient().GetRelationOrient());
961  aTextBoxSet.Put(aOrient);
962  }
963  break;
964  case RES_FRM_SIZE:
965  {
966  // In case the shape got resized, then we need to adjust both
967  // the position and the size of the textbox (e.g. larger
968  // rounded edges of a rectangle -> need to push right/down the
969  // textbox).
970  SwFormatVertOrient aVertOrient(rShape.GetVertOrient());
971  SwFormatHoriOrient aHoriOrient(rShape.GetHoriOrient());
972  SwFormatFrameSize aSize(pFormat->GetFrameSize());
973 
974  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
975  if (!aRect.IsEmpty())
976  {
977  if (!bInlineAnchored)
978  {
979  aVertOrient.SetPos(aVertOrient.GetPos() + aRect.getY());
980  aHoriOrient.SetPos(aHoriOrient.GetPos() + aRect.getX());
981 
982  aTextBoxSet.Put(aVertOrient);
983  aTextBoxSet.Put(aHoriOrient);
984  }
985 
986  aSize.SetWidth(aRect.getWidth());
987  aSize.SetHeight(aRect.getHeight());
988  aTextBoxSet.Put(aSize);
989  }
990  }
991  break;
992  case RES_ANCHOR:
993  {
994  if (pItem->StaticWhichCast(RES_ANCHOR) == rShape.GetAnchor())
995  // the anchor have to be synced
996  {
997  const text::TextContentAnchorType aNewAnchorType
998  = mapAnchorType(rShape.GetAnchor().GetAnchorId());
999  syncProperty(&rShape, RES_ANCHOR, MID_ANCHOR_ANCHORTYPE,
1000  uno::Any(aNewAnchorType));
1001  }
1002  else
1003  {
1004  SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: The anchor of the "
1005  "shape different from the textframe!");
1006  }
1007  }
1008  break;
1009  default:
1010  SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: unhandled which-id: "
1011  << pItem->Which());
1012  break;
1013  }
1014 
1015  pItem = aIter.NextItem();
1016  } while (pItem && (0 != pItem->Which()));
1017 
1018  if (aTextBoxSet.Count())
1019  pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
1020 
1021  DoTextBoxZOrderCorrection(&rShape);
1022 }
1023 
1025 {
1026  if (!pObj)
1027  return;
1028  uno::Reference<drawing::XShape> xShape(pObj->getUnoShape(), uno::UNO_QUERY);
1029  if (!xShape)
1030  return;
1031  uno::Reference<beans::XPropertySet> const xPropertySet(xShape, uno::UNO_QUERY);
1032 
1033  auto pParentFormat = getOtherTextBoxFormat(getOtherTextBoxFormat(xShape), RES_FLYFRMFMT);
1034  if (!pParentFormat)
1035  return;
1036 
1037  // Sync the padding
1038  syncProperty(pParentFormat, UNO_NAME_TEXT_LEFTDIST,
1039  xPropertySet->getPropertyValue(UNO_NAME_TEXT_LEFTDIST));
1040  syncProperty(pParentFormat, UNO_NAME_TEXT_RIGHTDIST,
1041  xPropertySet->getPropertyValue(UNO_NAME_TEXT_RIGHTDIST));
1042  syncProperty(pParentFormat, UNO_NAME_TEXT_UPPERDIST,
1043  xPropertySet->getPropertyValue(UNO_NAME_TEXT_UPPERDIST));
1044  syncProperty(pParentFormat, UNO_NAME_TEXT_LOWERDIST,
1045  xPropertySet->getPropertyValue(UNO_NAME_TEXT_LOWERDIST));
1046 
1047  // Sync the text aligning
1048  syncProperty(pParentFormat, UNO_NAME_TEXT_VERTADJUST,
1049  xPropertySet->getPropertyValue(UNO_NAME_TEXT_VERTADJUST));
1050  syncProperty(pParentFormat, UNO_NAME_TEXT_HORZADJUST,
1051  xPropertySet->getPropertyValue(UNO_NAME_TEXT_HORZADJUST));
1052 
1053  // tdf137803: Sync autogrow:
1054  const bool bIsAutoGrow
1055  = xPropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT).get<bool>();
1056  const bool bIsAutoWrap = xPropertySet->getPropertyValue(UNO_NAME_TEXT_WORDWRAP).get<bool>();
1057 
1058  syncProperty(pParentFormat, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, uno::Any(bIsAutoGrow));
1059 
1060  syncProperty(pParentFormat, RES_FRM_SIZE, MID_FRMSIZE_WIDTH_TYPE,
1061  uno::Any(bIsAutoWrap ? text::SizeType::FIX : text::SizeType::MIN));
1062 }
1063 
1065 {
1066  OUString sErrMsg;
1067  if (isTextBoxShapeHasValidTextFrame(pShape))
1068  {
1069  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
1070  {
1071  ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
1072  if (auto xFrame = SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat))
1073  try
1074  {
1075  uno::Reference<beans::XPropertySet> const xPropertySet(xFrame, uno::UNO_QUERY);
1076  xPropertySet->setPropertyValue(UNO_NAME_SURROUND,
1077  uno::makeAny(text::WrapTextMode_THROUGH));
1078  return true;
1079  }
1080  catch (uno::Exception& e)
1081  {
1082  sErrMsg = "Exception caught: " + e.Message;
1083  }
1084  else
1085  sErrMsg = "No XTextFrame!";
1086  }
1087  else
1088  sErrMsg = "No Other TextBox Format!";
1089  }
1090  else
1091  sErrMsg = "Not a Valid TextBox object!";
1092 
1093  SAL_WARN("sw.core", "SwTextBoxHelper::setWrapThrough: " << sErrMsg);
1094  return false;
1095 }
1096 
1098 {
1099  if (isTextBoxShapeHasValidTextFrame(pShape))
1100  {
1101  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
1102  {
1103  const SwFormatAnchor& rOldAnch = pFormat->GetAnchor();
1104  const SwFormatAnchor& rNewAnch = pShape->GetAnchor();
1105 
1106  const auto pOldCnt = rOldAnch.GetContentAnchor();
1107  const auto pNewCnt = rNewAnch.GetContentAnchor();
1108 
1109  const uno::Any aShapeHorRelOrient
1111 
1112  if (isAnchorTypeDifferent(pShape))
1113  {
1114  try
1115  {
1116  ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
1117  uno::Reference<beans::XPropertySet> const xPropertySet(
1118  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
1119  uno::UNO_QUERY);
1120  if (pOldCnt && rNewAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE
1121  && rNewAnch.GetPageNum())
1122  {
1123  uno::Any aValue(text::TextContentAnchorType_AT_PAGE);
1124  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1125  aShapeHorRelOrient);
1126  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1127  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_PAGE_NO,
1128  uno::Any(rNewAnch.GetPageNum()));
1129  }
1130  else if (rOldAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE && pNewCnt)
1131  {
1132  if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1133  {
1134  uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
1135  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1136  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1137  uno::Any(text::RelOrientation::CHAR));
1138  xPropertySet->setPropertyValue(
1140  uno::Any(text::RelOrientation::PRINT_AREA));
1141  SwFormatAnchor aPos(pFormat->GetAnchor());
1142  aPos.SetAnchor(pNewCnt);
1143  pFormat->SetFormatAttr(aPos);
1144  }
1145  else
1146  {
1147  uno::Any aValue(mapAnchorType(rNewAnch.GetAnchorId()));
1148  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1149  aShapeHorRelOrient);
1150  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1151  pFormat->SetFormatAttr(rNewAnch);
1152  }
1153  }
1154  else
1155  {
1156  if (rNewAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1157  {
1158  uno::Any aValue(text::TextContentAnchorType_AT_CHARACTER);
1159  xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, aValue);
1160  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1161  uno::Any(text::RelOrientation::CHAR));
1162  xPropertySet->setPropertyValue(
1164  uno::Any(text::RelOrientation::PRINT_AREA));
1165  SwFormatAnchor aPos(pFormat->GetAnchor());
1166  aPos.SetAnchor(pNewCnt);
1167  pFormat->SetFormatAttr(aPos);
1168  }
1169  else
1170  {
1171  xPropertySet->setPropertyValue(UNO_NAME_HORI_ORIENT_RELATION,
1172  aShapeHorRelOrient);
1173  pFormat->SetFormatAttr(pShape->GetAnchor());
1174  }
1175  }
1176  }
1177  catch (uno::Exception& e)
1178  {
1179  SAL_WARN("sw.core", "SwTextBoxHelper::changeAnchor(): " << e.Message);
1180  }
1181  }
1182 
1183  return doTextBoxPositioning(pShape) && DoTextBoxZOrderCorrection(pShape);
1184  }
1185  }
1186  return false;
1187 }
1188 
1190 {
1191  if (isTextBoxShapeHasValidTextFrame(pShape))
1192  {
1193  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
1194  {
1195  ::sw::UndoGuard const UndoGuard(pShape->GetDoc()->GetIDocumentUndoRedo());
1196  if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1197  {
1198  tools::Rectangle aRect(getTextRectangle(pShape, false));
1199 
1200  SwFormatHoriOrient aNewHOri(pFormat->GetHoriOrient());
1201  aNewHOri.SetPos(aRect.getX());
1202 
1203  SwFormatVertOrient aNewVOri(pFormat->GetVertOrient());
1204  aNewVOri.SetPos(aRect.getY() + pShape->GetVertOrient().GetPos());
1205 
1206  // tdf#140598: Do not apply wrong rectangle position.
1207  if (aRect.TopLeft() != Point(0, 0))
1208  {
1209  pFormat->SetFormatAttr(aNewHOri);
1210  pFormat->SetFormatAttr(aNewVOri);
1211  }
1212  else
1213  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!");
1214  }
1215  else
1216  {
1217  tools::Rectangle aRect(getTextRectangle(pShape, false));
1218 
1219  // tdf#140598: Do not apply wrong rectangle position.
1220  if (aRect.TopLeft() != Point(0, 0))
1221  {
1222  SwFormatHoriOrient aNewHOri(pShape->GetHoriOrient());
1223  aNewHOri.SetPos(aNewHOri.GetPos() + aRect.getX());
1224  SwFormatVertOrient aNewVOri(pShape->GetVertOrient());
1225  aNewVOri.SetPos(aNewVOri.GetPos() + aRect.getY());
1226 
1227  pFormat->SetFormatAttr(aNewHOri);
1228  pFormat->SetFormatAttr(aNewVOri);
1229  }
1230  else
1231  SAL_WARN("sw.core", "SwTextBoxHelper::syncProperty: Repositioning failed!");
1232  }
1233  return true;
1234  }
1235  }
1236  return false;
1237 }
1238 
1240 {
1241  std::optional<bool> bRet;
1242  if (isTextBoxShapeHasValidTextFrame(pShape))
1243  {
1244  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
1245  {
1246  if (pShape->GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1247  bRet = (pFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AT_CHAR
1248  && pFormat->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR);
1249  else
1250  bRet = pFormat->GetAnchor().GetAnchorId() != pShape->GetAnchor().GetAnchorId();
1251  }
1252  }
1253  return bRet;
1254 }
1255 
1257 {
1258  if (pShape && pShape->Which() == RES_DRAWFRMFMT)
1259  if (auto pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
1260  if (pFormat && pFormat->Which() == RES_FLYFRMFMT)
1261  return true;
1262  else
1263  SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: "
1264  "Shape does not have valid textframe!");
1265  else
1266  SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: "
1267  "Shape does not have associated frame!");
1268  else
1269  SAL_WARN("sw.core", "SwTextBoxHelper::isTextBoxShapeHasValidTextFrame: Not valid shape!");
1270  return false;
1271 }
1272 
1274 {
1275  if (isTextBoxShapeHasValidTextFrame(pShape))
1276  {
1277  if (SdrObject* pShpObj = pShape->FindRealSdrObject())
1278  {
1279  if (SdrObject* pFrmObj
1280  = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT)->FindRealSdrObject())
1281  {
1282  // Get the draw model from the doc
1283  SwDrawModel* pDrawModel
1285  if (pDrawModel)
1286  {
1287  // Not really sure this will work all page, but it seems it will.
1288  auto pPage = pDrawModel->GetPage(0);
1289  // Recalc all Zorders
1290  pPage->RecalcObjOrdNums();
1291  // If the shape is behind the frame, is good, but if there are some objects
1292  // between of them that is wrong so put the frame exactly one level higher
1293  // than the shape.
1294  if (pFrmObj->GetOrdNum() > pShpObj->GetOrdNum())
1295  pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pShpObj->GetOrdNum() + 1);
1296  else
1297  // Else, if the frame is behind the shape, bring to the front of it.
1298  while (pFrmObj->GetOrdNum() <= pShpObj->GetOrdNum())
1299  {
1300  pPage->SetObjectOrdNum(pFrmObj->GetOrdNum(), pFrmObj->GetOrdNum() + 1);
1301  // If there is any problem with the indexes, do not run over the infinity
1302  if (pPage->GetObjCount() == pFrmObj->GetOrdNum())
1303  break;
1304  }
1305  pPage->RecalcObjOrdNums();
1306  return true; // Success
1307  }
1308  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1309  "No Valid Draw model for SdrObject for the shape!");
1310  }
1311  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1312  "No Valid SdrObject for the frame!");
1313  }
1314  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1315  "No Valid SdrObject for the shape!");
1316  }
1317  SAL_WARN("sw.core", "SwTextBoxHelper::DoTextBoxZOrderCorrection(): "
1318  "No Valid TextFrame!");
1319 
1320  return false;
1321 }
1322 
1323 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
constexpr TypedWhichId< SvxFrameDirectionItem > RES_FRAMEDIR(120)
#define MID_CHAIN_NAME
Definition: unomid.h:58
const css::uno::WeakReference< css::uno::XInterface > & getWeakUnoShape() const
#define UNO_NAME_TEXT_WORDWRAP
static sal_Int32 getCount(const SwDoc &rDoc)
Count number of shapes in the document, excluding TextBoxes.
static css::uno::Any getByIndex(SdrPage const *pPage, sal_Int32 nIndex)
Get a shape by index, excluding TextBoxes.
static bool isTextBoxShapeHasValidTextFrame(SwFrameFormat *pShape)
Returns true if the given shape has a valid textframe.
static std::optional< bool > isAnchorTypeDifferent(SwFrameFormat *pShape)
Returns true if the anchor different for the given shape, and the associated textframe of the given s...
void SetHeight(tools::Long n)
#define UNO_NAME_HORI_ORIENT_POSITION
Definition: unoprnms.hxx:264
#define UNO_NAME_TEXT_RIGHTDIST
SwDocShell * GetDocShell()
Definition: doc.hxx:1352
#define UNO_NAME_BOTTOM_BORDER
Definition: unoprnms.hxx:357
tools::Long getWidth() 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:190
virtual bool QueryValue(css::uno::Any &rVal, sal_uInt8 nMemberId=0) const override
Definition: atrfrm.cxx:2146
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
#define UNO_NAME_IS_FOLLOWING_TEXT_FLOW
Definition: unoprnms.hxx:741
constexpr TypedWhichId< SwFormatFrameSize > RES_FRM_SIZE(89)
static void destroy(SwFrameFormat *pShape)
Destroy a TextBox for a shape.
#define UNO_NAME_ALLOW_OVERLAP
Definition: unoprnms.hxx:867
constexpr TypedWhichId< SdrTextVertAdjustItem > RES_TEXT_VERT_ADJUST(130)
sal_uInt16 GetPageNum() const
Definition: fmtanchr.hxx:66
virtual void SetModified()=0
Must be called manually at changes of format.
Reference< XFrame > xFrame
static bool DoTextBoxZOrderCorrection(SwFrameFormat *pShape)
#define MID_VERTORIENT_RELATION
Definition: unomid.h:35
static sal_Int32 getOrdNum(const SdrObject *pObject)
Get the order of the shape, excluding TextBoxes.
#define UNO_NAME_TEXT_LOWERDIST
SdrObject * GetObj(size_t nNum) const
void RecalcObjOrdNums()
Definition: doc.hxx:188
virtual bool IsTextBox() const
size_t GetObjCount() const
OUString GetUniqueFrameName() const
Definition: doclay.cxx:1379
tools::Long getY() const
#define RIGHT_BORDER_DISTANCE
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:691
#define UNO_NAME_ANCHOR_PAGE_NO
Definition: unoprnms.hxx:227
#define UNO_NAME_VERT_ORIENT
Definition: unoprnms.hxx:329
IDocumentUndoRedo & GetIDocumentUndoRedo()
Definition: doc.cxx:144
#define UNO_NAME_TEXT_UPPERDIST
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 SwFrameFormat * getOtherTextBoxFormat(const SwFrameFormat *pFormat, sal_uInt16 nType)
If we have an associated TextFrame, then return that.
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:744
std::map< const SwFrameFormat *, const SwFrameFormat * > SavedLink
Maps a draw format to a fly format.
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(156)
static css::uno::Any queryInterface(const SwFrameFormat *pShape, const css::uno::Type &rType)
Get interface of a shape's TextBox, if there is any.
IDocumentDrawModelAccess const & getIDocumentDrawModelAccess() const
Definition: doc.cxx:155
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:188
constexpr TypedWhichId< SwDrawFrameFormat > RES_DRAWFRMFMT(159)
#define UNO_NAME_CHAIN_NEXT_NAME
Definition: unoprnms.hxx:231
virtual css::uno::Reference< css::uno::XInterface > getUnoShape()
#define MID_FRMSIZE_SIZE
Definition: unomid.h:70
tools::Long Left() const
constexpr TypedWhichId< SwFormatHoriOrient > RES_HORI_ORIENT(103)
SdrPage * getSdrPageFromSdrObject() const
static bool changeAnchor(SwFrameFormat *pShape)
Sets the anchor of the associated textframe of the given shape, and returns true on success...
#define MID_FOLLOW_TEXT_FLOW
Definition: unomid.h:152
static bool setWrapThrough(SwFrameFormat *pShape)
Sets the surround to through for the textframe of the given shape, not to interfere with the layout...
void SetOtherTextBoxFormat(SwFrameFormat *pFormat)
Definition: atrfrm.cxx:2583
const OUString & GetName() const
Definition: format.hxx:115
int nCount
#define UNO_NAME_SIZE
Definition: unoprnms.hxx:303
virtual void DelLayoutFormat(SwFrameFormat *pFormat)=0
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType)
Is the frame format a text box?
Mode eMode
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
static bool doTextBoxPositioning(SwFrameFormat *pShape)
Does the positioning for the associated textframe of the shape, and returns true on success...
#define UNO_NAME_VERT_ORIENT_RELATION
Definition: unoprnms.hxx:332
tools::Long getX() const
#define UNO_NAME_TEXT_WRITINGMODE
#define FN_TEXT_RANGE
Definition: cmdid.h:807
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. ...
static void lcl_queryInterface(const SwFrameFormat *pShape, uno::Any &rAny)
#define UNO_NAME_HORI_ORIENT
Definition: unoprnms.hxx:260
#define MID_CHAIN_NEXTNAME
Definition: unomid.h:57
#define MID_L_MARGIN
static void create(SwFrameFormat *pShape, bool bCopyText=false)
Create a TextBox for a shape.
#define MID_ANCHOR_ANCHORTYPE
Definition: unomid.h:43
Style of a layout element.
Definition: frmfmt.hxx:58
#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:355
T & StaticWhichCast(TypedWhichId< T > nId)
#define MID_FRMSIZE_WIDTH_TYPE
Definition: unomid.h:86
#define UNO_NAME_FILL_TRANSPARENCE
SwFrameFormat * GetOtherTextBoxFormat() const
Definition: frmfmt.hxx:102
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:170
#define MID_VERTORIENT_POSITION
Definition: unomid.h:36
void SetPos(SwTwips nNew)
Definition: fmtornt.hxx:60
FlyAnchors.
Definition: fmtanchr.hxx:34
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 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
#define UNO_NAME_LEFT_BORDER
Definition: unoprnms.hxx:354
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:123
tools::Long Top() const
#define UNO_NAME_LEFT_BORDER_DISTANCE
Definition: unoprnms.hxx:359
#define UNO_NAME_CHAIN_PREV_NAME
Definition: unoprnms.hxx:232
bool SetFlyFrameAttr(SwFrameFormat &rFlyFormat, SfxItemSet &rSet)
Definition: docfly.cxx:558
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:405
constexpr TypedWhichId< SwFormatContent > RES_CNTNT(95)
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:68
constexpr Point TopLeft() const
#define UNO_NAME_TOP_BORDER
Definition: unoprnms.hxx:356
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:450
#define UNO_NAME_TOP_BORDER_DISTANCE
Definition: unoprnms.hxx:361
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:82
#define UNO_NAME_TEXT_VERT_ADJUST
Definition: unoprnms.hxx:856
#define UNO_NAME_SURROUND
Definition: unoprnms.hxx:310
#define MID_HORIORIENT_ORIENT
Definition: unomid.h:38
#define MID_FRMSIZE_REL_HEIGHT_RELATION
Definition: unomid.h:88
virtual bool ResetFormatAttr(sal_uInt16 nWhich1, sal_uInt16 nWhich2=0)
Definition: format.cxx:624
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)
Any makeAny(Color const &value)
sal_Int16 GetRelationOrient() const
Definition: fmtornt.hxx:88
#define UNO_NAME_LEFT_MARGIN
Definition: unoprnms.hxx:67
#define MID_VERTORIENT_ORIENT
Definition: unomid.h:34
unsigned char sal_uInt8
#define UNO_NAME_BOTTOM_BORDER_DISTANCE
Definition: unoprnms.hxx:362
#define UNO_NAME_ANCHOR_TYPE
Definition: unoprnms.hxx:225
SwTwips GetPos() const
Definition: fmtornt.hxx:59
#define UNO_NAME_TEXT_LEFTDIST
#define MID_FRMSIZE_REL_WIDTH_RELATION
Definition: unomid.h:87
#define SAL_INFO(area, stream)
#define UNO_NAME_HORI_ORIENT_RELATION
Definition: unoprnms.hxx:263
static SW_DLLPUBLIC css::uno::Reference< css::text::XTextFrame > CreateXTextFrame(SwDoc &rDoc, SwFrameFormat *pFrameFormat)
Definition: unoframe.cxx:3184
#define TOP_BORDER_DISTANCE
bool HasItem(sal_uInt16 nWhich, const SfxPoolItem **ppItem=nullptr) const
#define UNO_NAME_TEXT_AUTOGROWHEIGHT
void * p
static css::uno::Reference< css::uno::XInterface > MakeInstance(SwServiceType nObjectType, SwDoc &rDoc)
Definition: unocoll.cxx:513
bool GetTextBounds(tools::Rectangle &rTextBound) const
constexpr TypedWhichId< SvxLRSpaceItem > RES_LR_SPACE(91)
static tools::Rectangle getTextRectangle(SwFrameFormat *pShape, bool bAbsolute=true)
Return the textbox rectangle of a draw shape (in twips).
constexpr TypedWhichId< SvxBoxItem > RES_BOX(106)
const SwFormatFrameSize & GetFrameSize(bool=true) const
Definition: fmtfsize.hxx:104
const SwFormatContent & GetContent(bool=true) const
Definition: fmtcntnt.hxx:55
void SetPos(SwTwips nNew)
Definition: fmtornt.hxx:93
#define UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT
Definition: unoprnms.hxx:591
#define MID_HORIORIENT_RELATION
Definition: unomid.h:39
#define UNO_NAME_TEXT_HORZADJUST
static void syncFlyFrameAttr(SwFrameFormat &rShape, SfxItemSet const &rSet)
Similar to syncProperty(), but used by the internal API (e.g. for UI purposes).
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
#define SAL_WARN(area, stream)
static void syncProperty(SwFrameFormat *pShape, sal_uInt16 nWID, sal_uInt8 nMemberID, const css::uno::Any &rValue)
Sync property of TextBox with the one of the shape.
RndStdIds
#define UNO_NAME_SIZE_TYPE
Definition: unoprnms.hxx:258
#define UNO_NAME_RIGHT_BORDER_DISTANCE
Definition: unoprnms.hxx:360
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:120
#define UNO_NAME_WIDTH_TYPE
Definition: unoprnms.hxx:742
#define UNO_NAME_VERT_ORIENT_POSITION
Definition: unoprnms.hxx:331
constexpr TypedWhichId< SwFormatFollowTextFlow > RES_FOLLOW_TEXT_FLOW(123)
#define UNO_NAME_OPAQUE
Definition: unoprnms.hxx:282
sal_uInt16 Which() const
SdrObject * FindRealSdrObject()
Definition: atrfrm.cxx:2802
constexpr TypedWhichId< SwFormatAnchor > RES_ANCHOR(104)
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1319
sal_Int16 nValue
#define MID_ALLOW_OVERLAP
Definition: unomid.h:149
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1583
#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.
#define UNO_NAME_TEXT_VERTADJUST