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