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 <docsh.hxx>
19 #include <unocoll.hxx>
20 #include <unoframe.hxx>
21 #include <unodraw.hxx>
22 #include <unotextrange.hxx>
23 #include <cmdid.h>
24 #include <unomid.h>
25 #include <unoprnms.hxx>
26 #include <mvsave.hxx>
27 #include <fmtsrnd.hxx>
28 #include <frmfmt.hxx>
29 
30 #include <editeng/unoprnms.hxx>
31 #include <editeng/memberids.h>
32 #include <svx/svdoashp.hxx>
33 #include <svx/svdpage.hxx>
34 #include <svl/itemiter.hxx>
36 #include <sal/log.hxx>
37 
38 #include <com/sun/star/document/XActionLockable.hpp>
39 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
40 #include <com/sun/star/text/SizeType.hpp>
41 #include <com/sun/star/text/TextContentAnchorType.hpp>
42 #include <com/sun/star/text/WrapTextMode.hpp>
43 #include <com/sun/star/text/XTextDocument.hpp>
44 #include <com/sun/star/table/BorderLine2.hpp>
45 #include <com/sun/star/text/WritingMode2.hpp>
46 
47 using namespace com::sun::star;
48 
50 {
51  // If TextBox wasn't enabled previously
52  if (pShape->GetAttrSet().HasItem(RES_CNTNT))
53  return;
54 
55  // Create the associated TextFrame and insert it into the document.
56  uno::Reference<text::XTextContent> xTextFrame(
58  uno::UNO_QUERY);
59  uno::Reference<text::XTextDocument> xTextDocument(
60  pShape->GetDoc()->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
61  uno::Reference<text::XTextContentAppend> xTextContentAppend(xTextDocument->getText(),
62  uno::UNO_QUERY);
63  xTextContentAppend->appendTextContent(xTextFrame, uno::Sequence<beans::PropertyValue>());
64 
65  // Link FLY and DRAW formats, so it becomes a text box (needed for syncProperty calls).
66  uno::Reference<text::XTextFrame> xRealTextFrame(xTextFrame, uno::UNO_QUERY);
67  auto pTextFrame = dynamic_cast<SwXTextFrame*>(xRealTextFrame.get());
68  assert(nullptr != pTextFrame);
69  SwFrameFormat* pFormat = pTextFrame->GetFrameFormat();
70 
71  assert(nullptr != dynamic_cast<SwDrawFrameFormat*>(pShape));
72  assert(nullptr != dynamic_cast<SwFlyFrameFormat*>(pFormat));
73 
74  pShape->SetOtherTextBoxFormat(pFormat);
75  pFormat->SetOtherTextBoxFormat(pShape);
76 
77  // Initialize properties.
78  uno::Reference<beans::XPropertySet> xPropertySet(xTextFrame, uno::UNO_QUERY);
79  uno::Any aEmptyBorder = uno::makeAny(table::BorderLine2());
80  xPropertySet->setPropertyValue(UNO_NAME_TOP_BORDER, aEmptyBorder);
81  xPropertySet->setPropertyValue(UNO_NAME_BOTTOM_BORDER, aEmptyBorder);
82  xPropertySet->setPropertyValue(UNO_NAME_LEFT_BORDER, aEmptyBorder);
83  xPropertySet->setPropertyValue(UNO_NAME_RIGHT_BORDER, aEmptyBorder);
84 
85  xPropertySet->setPropertyValue(UNO_NAME_FILL_TRANSPARENCE, uno::makeAny(sal_Int32(100)));
86 
87  xPropertySet->setPropertyValue(UNO_NAME_SIZE_TYPE, uno::makeAny(text::SizeType::FIX));
88 
89  xPropertySet->setPropertyValue(UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
90 
91  uno::Reference<container::XNamed> xNamed(xTextFrame, uno::UNO_QUERY);
92  xNamed->setName(pShape->GetDoc()->GetUniqueFrameName());
93 
94  // Link its text range to the original shape.
95  uno::Reference<text::XTextRange> xTextBox(xTextFrame, uno::UNO_QUERY_THROW);
96  SwUnoInternalPaM aInternalPaM(*pShape->GetDoc());
97  if (sw::XTextRangeToSwPaM(aInternalPaM, xTextBox))
98  {
99  SwAttrSet aSet(pShape->GetAttrSet());
100  SwFormatContent aContent(aInternalPaM.GetNode().StartOfSectionNode());
101  aSet.Put(aContent);
102  pShape->SetFormatAttr(aSet);
103  }
104 
105  // Also initialize the properties, which are not constant, but inherited from the shape's ones.
106  uno::Reference<drawing::XShape> xShape(pShape->FindRealSdrObject()->getUnoShape(),
107  uno::UNO_QUERY);
108  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::makeAny(xShape->getSize()));
109 
110  uno::Reference<beans::XPropertySet> xShapePropertySet(xShape, uno::UNO_QUERY);
111  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_ORIENT,
112  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT));
113  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_RELATION,
114  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_RELATION));
115  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_ORIENT,
116  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT));
117  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_RELATION,
118  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_RELATION));
119  syncProperty(pShape, RES_HORI_ORIENT, MID_HORIORIENT_POSITION,
120  xShapePropertySet->getPropertyValue(UNO_NAME_HORI_ORIENT_POSITION));
121  syncProperty(pShape, RES_VERT_ORIENT, MID_VERTORIENT_POSITION,
122  xShapePropertySet->getPropertyValue(UNO_NAME_VERT_ORIENT_POSITION));
123  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT,
124  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT));
125  syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0,
126  xShapePropertySet->getPropertyValue(UNO_NAME_TEXT_VERT_ADJUST));
127 }
128 
130 {
131  // If a TextBox was enabled previously
132  if (pShape->GetAttrSet().HasItem(RES_CNTNT))
133  {
134  SwFrameFormat* pFormat = pShape->GetOtherTextBoxFormat();
135 
136  // Unlink the TextBox's text range from the original shape.
137  pShape->ResetFormatAttr(RES_CNTNT);
138 
139  // Delete the associated TextFrame.
140  if (pFormat)
141  pShape->GetDoc()->getIDocumentLayoutAccess().DelLayoutFormat(pFormat);
142  }
143 }
144 
145 bool SwTextBoxHelper::isTextBox(const SwFrameFormat* pFormat, sal_uInt16 nType)
146 {
147  assert(nType == RES_FLYFRMFMT || nType == RES_DRAWFRMFMT);
148  if (!pFormat || pFormat->Which() != nType || !pFormat->GetAttrSet().HasItem(RES_CNTNT))
149  return false;
150 
151  sal_uInt16 nOtherType = (pFormat->Which() == RES_FLYFRMFMT) ? sal_uInt16(RES_DRAWFRMFMT)
152  : sal_uInt16(RES_FLYFRMFMT);
153  SwFrameFormat* pOtherFormat = pFormat->GetOtherTextBoxFormat();
154  if (!pOtherFormat)
155  return false;
156 
157  assert(pOtherFormat->Which() == nOtherType);
158  if (pOtherFormat->Which() != nOtherType)
159  return false;
160 
161  const SwFormatContent& rContent = pFormat->GetContent();
162  return pOtherFormat->GetAttrSet().HasItem(RES_CNTNT) && pOtherFormat->GetContent() == rContent;
163 }
164 
165 sal_Int32 SwTextBoxHelper::getCount(SdrPage const* pPage)
166 {
167  sal_Int32 nRet = 0;
168  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
169  {
170  SdrObject* p = pPage->GetObj(i);
171  if (p && p->IsTextBox())
172  continue;
173  ++nRet;
174  }
175  return nRet;
176 }
177 
178 sal_Int32 SwTextBoxHelper::getCount(const SwDoc* pDoc)
179 {
180  sal_Int32 nRet = 0;
181  const SwFrameFormats& rSpzFrameFormats = *pDoc->GetSpzFrameFormats();
182  for (const auto pFormat : rSpzFrameFormats)
183  {
184  if (isTextBox(pFormat, RES_FLYFRMFMT))
185  ++nRet;
186  }
187  return nRet;
188 }
189 
190 uno::Any SwTextBoxHelper::getByIndex(SdrPage const* pPage, sal_Int32 nIndex)
191 {
192  if (nIndex < 0)
193  throw lang::IndexOutOfBoundsException();
194 
195  SdrObject* pRet = nullptr;
196  sal_Int32 nCount = 0; // Current logical index.
197  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
198  {
199  SdrObject* p = pPage->GetObj(i);
200  if (p && p->IsTextBox())
201  continue;
202  if (nCount == nIndex)
203  {
204  pRet = p;
205  break;
206  }
207  ++nCount;
208  }
209 
210  if (!pRet)
211  throw lang::IndexOutOfBoundsException();
212 
213  return uno::makeAny(uno::Reference<drawing::XShape>(pRet->getUnoShape(), uno::UNO_QUERY));
214 }
215 
216 sal_Int32 SwTextBoxHelper::getOrdNum(const SdrObject* pObject)
217 {
218  if (const SdrPage* pPage = pObject->getSdrPageFromSdrObject())
219  {
220  sal_Int32 nOrder = 0; // Current logical order.
221  for (std::size_t i = 0; i < pPage->GetObjCount(); ++i)
222  {
223  SdrObject* p = pPage->GetObj(i);
224  if (p && p->IsTextBox())
225  continue;
226  if (p == pObject)
227  return nOrder;
228  ++nOrder;
229  }
230  }
231 
232  SAL_WARN("sw.core", "SwTextBoxHelper::getOrdNum: no page or page doesn't contain the object");
233  return pObject->GetOrdNum();
234 }
235 
236 void SwTextBoxHelper::getShapeWrapThrough(const SwFrameFormat* pTextBox, bool& rWrapThrough)
237 {
239  if (pShape)
240  rWrapThrough = pShape->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
241 }
242 
244  sal_uInt16 nType)
245 {
246  if (!isTextBox(pFormat, nType))
247  return nullptr;
248  return pFormat->GetOtherTextBoxFormat();
249 }
250 
251 SwFrameFormat* SwTextBoxHelper::getOtherTextBoxFormat(uno::Reference<drawing::XShape> const& xShape)
252 {
253  auto pShape = dynamic_cast<SwXShape*>(xShape.get());
254  if (!pShape)
255  return nullptr;
256 
257  SwFrameFormat* pFormat = pShape->GetFrameFormat();
258  return getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT);
259 }
260 
261 template <typename T> static void lcl_queryInterface(const SwFrameFormat* pShape, uno::Any& rAny)
262 {
264  {
265  uno::Reference<T> const xInterface(
266  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
267  rAny <<= xInterface;
268  }
269 }
270 
272 {
273  uno::Any aRet;
274 
276  {
277  lcl_queryInterface<text::XTextAppend>(pShape, aRet);
278  }
279  else if (rType == cppu::UnoType<css::text::XText>::get())
280  {
281  lcl_queryInterface<text::XText>(pShape, aRet);
282  }
283  else if (rType == cppu::UnoType<css::text::XTextRange>::get())
284  {
285  lcl_queryInterface<text::XTextRange>(pShape, aRet);
286  }
287 
288  return aRet;
289 }
290 
292 {
293  tools::Rectangle aRet;
294  aRet.SetEmpty();
295  auto pSdrShape = pShape->FindRealSdrObject();
296  auto pCustomShape = dynamic_cast<SdrObjCustomShape*>(pSdrShape);
297  if (pCustomShape)
298  {
299  // Need to temporarily release the lock acquired in
300  // SdXMLShapeContext::AddShape(), otherwise we get an empty rectangle,
301  // see EnhancedCustomShapeEngine::getTextBounds().
302  uno::Reference<document::XActionLockable> xLockable(pCustomShape->getUnoShape(),
303  uno::UNO_QUERY);
304  sal_Int16 nLocks = 0;
305  if (xLockable.is())
306  nLocks = xLockable->resetActionLocks();
307  pCustomShape->GetTextBounds(aRet);
308  if (nLocks)
309  xLockable->setActionLocks(nLocks);
310  }
311  else if (pSdrShape)
312  {
313  // fallback - get *any* bound rect we can possibly get hold of
314  aRet = pSdrShape->GetCurrentBoundRect();
315  }
316 
317  if (!bAbsolute && pSdrShape)
318  {
319  // Relative, so count the logic (reference) rectangle, see the EnhancedCustomShape2d ctor.
320  Point aPoint(pSdrShape->GetSnapRect().Center());
321  Size aSize(pSdrShape->GetLogicRect().GetSize());
322  aPoint.AdjustX(-(aSize.Width() / 2));
323  aPoint.AdjustY(-(aSize.Height() / 2));
324  tools::Rectangle aLogicRect(aPoint, aSize);
325  aRet.Move(-1 * aLogicRect.Left(), -1 * aLogicRect.Top());
326  }
327 
328  return aRet;
329 }
330 
331 void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, const OUString& rPropertyName,
332  const css::uno::Any& rValue)
333 {
334  if (rPropertyName == "CustomShapeGeometry")
335  {
336  // CustomShapeGeometry changes the textbox position offset and size, so adjust both.
337  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_SIZE, uno::Any());
338 
339  SdrObject* pObject = pShape->FindRealSdrObject();
340  if (pObject)
341  {
342  tools::Rectangle aRectangle(pObject->GetSnapRect());
343  syncProperty(
345  uno::makeAny(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Left()))));
346  syncProperty(
348  uno::makeAny(static_cast<sal_Int32>(convertTwipToMm100(aRectangle.Top()))));
349  }
350 
351  SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT);
352  if (!pFormat)
353  return;
354 
355  comphelper::SequenceAsHashMap aCustomShapeGeometry(rValue);
356  auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
357  if (it != aCustomShapeGeometry.end())
358  {
359  auto nTextPreRotateAngle = it->second.get<sal_Int32>();
360  sal_Int16 nDirection = 0;
361  switch (nTextPreRotateAngle)
362  {
363  case -90:
364  nDirection = text::WritingMode2::TB_RL;
365  break;
366  case -270:
367  nDirection = text::WritingMode2::BT_LR;
368  break;
369  }
370 
371  if (nDirection)
372  {
373  syncProperty(pShape, RES_FRAMEDIR, 0, uno::makeAny(nDirection));
374  }
375  }
376  }
377  else if (rPropertyName == UNO_NAME_TEXT_VERT_ADJUST)
378  syncProperty(pShape, RES_TEXT_VERT_ADJUST, 0, rValue);
379  else if (rPropertyName == UNO_NAME_TEXT_AUTOGROWHEIGHT)
380  syncProperty(pShape, RES_FRM_SIZE, MID_FRMSIZE_IS_AUTO_HEIGHT, rValue);
381  else if (rPropertyName == UNO_NAME_TEXT_LEFTDIST)
382  syncProperty(pShape, RES_BOX, LEFT_BORDER_DISTANCE, rValue);
383  else if (rPropertyName == UNO_NAME_TEXT_RIGHTDIST)
384  syncProperty(pShape, RES_BOX, RIGHT_BORDER_DISTANCE, rValue);
385  else if (rPropertyName == UNO_NAME_TEXT_UPPERDIST)
386  syncProperty(pShape, RES_BOX, TOP_BORDER_DISTANCE, rValue);
387  else if (rPropertyName == UNO_NAME_TEXT_LOWERDIST)
388  syncProperty(pShape, RES_BOX, BOTTOM_BORDER_DISTANCE, rValue);
389 }
390 
391 void SwTextBoxHelper::getProperty(SwFrameFormat const* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
392  css::uno::Any& rValue)
393 {
394  if (!pShape)
395  return;
396 
397  nMemberID &= ~CONVERT_TWIPS;
398 
399  if (SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
400  {
401  if (nWID == RES_CHAIN)
402  {
403  switch (nMemberID)
404  {
405  case MID_CHAIN_PREVNAME:
406  case MID_CHAIN_NEXTNAME:
407  {
408  const SwFormatChain& rChain = pFormat->GetChain();
409  rChain.QueryValue(rValue, nMemberID);
410  }
411  break;
412  case MID_CHAIN_NAME:
413  rValue <<= pFormat->GetName();
414  break;
415  }
416  }
417  }
418 }
419 
420 void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, sal_uInt16 nWID, sal_uInt8 nMemberID,
421  const css::uno::Any& rValue)
422 {
423  // No shape yet? Then nothing to do, initial properties are set by create().
424  if (!pShape)
425  return;
426 
427  uno::Any aValue(rValue);
428  nMemberID &= ~CONVERT_TWIPS;
429 
430  if (SwFrameFormat* pFormat = getOtherTextBoxFormat(pShape, RES_DRAWFRMFMT))
431  {
432  OUString aPropertyName;
433  bool bAdjustX = false;
434  bool bAdjustY = false;
435  bool bAdjustSize = false;
436  switch (nWID)
437  {
438  case RES_HORI_ORIENT:
439  switch (nMemberID)
440  {
442  aPropertyName = UNO_NAME_HORI_ORIENT;
443  break;
445  aPropertyName = UNO_NAME_HORI_ORIENT_RELATION;
446  break;
448  aPropertyName = UNO_NAME_HORI_ORIENT_POSITION;
449  bAdjustX = true;
450  break;
451  }
452  break;
453  case RES_LR_SPACE:
454  {
455  switch (nMemberID)
456  {
457  case MID_L_MARGIN:
458  aPropertyName = UNO_NAME_LEFT_MARGIN;
459  break;
460  case MID_R_MARGIN:
461  aPropertyName = UNO_NAME_RIGHT_MARGIN;
462  break;
463  }
464  break;
465  }
466  case RES_VERT_ORIENT:
467  switch (nMemberID)
468  {
470  aPropertyName = UNO_NAME_VERT_ORIENT;
471  break;
473  aPropertyName = UNO_NAME_VERT_ORIENT_RELATION;
474  break;
476  aPropertyName = UNO_NAME_VERT_ORIENT_POSITION;
477  bAdjustY = true;
478  break;
479  }
480  break;
481  case RES_FRM_SIZE:
482  switch (nMemberID)
483  {
485  aPropertyName = UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT;
486  break;
488  aPropertyName = UNO_NAME_RELATIVE_HEIGHT_RELATION;
489  break;
491  aPropertyName = UNO_NAME_RELATIVE_WIDTH_RELATION;
492  break;
493  default:
494  aPropertyName = UNO_NAME_SIZE;
495  bAdjustSize = true;
496  break;
497  }
498  break;
499  case RES_ANCHOR:
500  switch (nMemberID)
501  {
503  if (aValue.get<text::TextContentAnchorType>()
504  == text::TextContentAnchorType_AS_CHARACTER)
505  {
506  uno::Reference<beans::XPropertySet> const xPropertySet(
507  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
508  uno::UNO_QUERY);
509  xPropertySet->setPropertyValue(
510  UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
511  return;
512  }
513  break;
514  }
515  break;
516  case FN_TEXT_RANGE:
517  {
518  uno::Reference<text::XTextRange> xRange;
519  rValue >>= xRange;
520  SwUnoInternalPaM aInternalPaM(*pFormat->GetDoc());
521  if (sw::XTextRangeToSwPaM(aInternalPaM, xRange))
522  {
523  SwFormatAnchor aAnchor(pFormat->GetAnchor());
524  aAnchor.SetAnchor(aInternalPaM.Start());
525  pFormat->SetFormatAttr(aAnchor);
526  }
527  }
528  break;
529  case RES_CHAIN:
530  switch (nMemberID)
531  {
532  case MID_CHAIN_PREVNAME:
533  aPropertyName = UNO_NAME_CHAIN_PREV_NAME;
534  break;
535  case MID_CHAIN_NEXTNAME:
536  aPropertyName = UNO_NAME_CHAIN_NEXT_NAME;
537  break;
538  }
539  break;
541  aPropertyName = UNO_NAME_TEXT_VERT_ADJUST;
542  break;
543  case RES_BOX:
544  switch (nMemberID)
545  {
547  aPropertyName = UNO_NAME_LEFT_BORDER_DISTANCE;
548  break;
550  aPropertyName = UNO_NAME_RIGHT_BORDER_DISTANCE;
551  break;
552  case TOP_BORDER_DISTANCE:
553  aPropertyName = UNO_NAME_TOP_BORDER_DISTANCE;
554  break;
556  aPropertyName = UNO_NAME_BOTTOM_BORDER_DISTANCE;
557  break;
558  }
559  break;
560  case RES_OPAQUE:
561  aPropertyName = UNO_NAME_OPAQUE;
562  break;
563  case RES_FRAMEDIR:
564  aPropertyName = UNO_NAME_WRITING_MODE;
565  break;
567  switch (nMemberID)
568  {
569  case MID_ALLOW_OVERLAP:
570  aPropertyName = UNO_NAME_ALLOW_OVERLAP;
571  break;
572  }
573  break;
574  }
575 
576  if (!aPropertyName.isEmpty())
577  {
578  // Position/size should be the text position/size, not the shape one as-is.
579  if (bAdjustX || bAdjustY || bAdjustSize)
580  {
581  tools::Rectangle aRect = getTextRectangle(pShape, /*bAbsolute=*/false);
582  if (!aRect.IsEmpty())
583  {
584  if (bAdjustX || bAdjustY)
585  {
586  sal_Int32 nValue;
587  if (aValue >>= nValue)
588  {
589  if (bAdjustX)
590  nValue += TWIPS_TO_MM(aRect.getX());
591  else if (bAdjustY)
592  nValue += TWIPS_TO_MM(aRect.getY());
593  aValue <<= nValue;
594  }
595  }
596  else if (bAdjustSize)
597  {
598  awt::Size aSize(TWIPS_TO_MM(aRect.getWidth()),
599  TWIPS_TO_MM(aRect.getHeight()));
600  aValue <<= aSize;
601  }
602  }
603  }
604 
605  uno::Reference<beans::XPropertySet> const xPropertySet(
606  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
607  xPropertySet->setPropertyValue(aPropertyName, aValue);
608  }
609  }
610 }
611 
613  std::map<const SwFrameFormat*, const SwFrameFormat*>& rLinks)
614 {
615  for (const auto pFormat : rFormats)
616  {
617  if (SwFrameFormat* pTextBox = getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
618  rLinks[pFormat] = pTextBox;
619  }
620 }
621 
623  std::map<const SwFrameFormat*, SwFormatContent>& rOldContent)
624 {
625  if (pShape->Which() == RES_DRAWFRMFMT)
626  {
627  if (pShape->GetContent().GetContentIdx())
628  rOldContent.insert(std::make_pair(pShape, pShape->GetContent()));
629  pShape->ResetFormatAttr(RES_CNTNT);
630  }
631 }
632 
633 void SwTextBoxHelper::restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrameFormat*>& rNew,
634  SavedLink& rSavedLinks, SavedContent& rResetContent)
635 {
636  std::size_t i = 0;
637  for (const auto& rIt : rOld)
638  {
639  auto aTextBoxIt = rSavedLinks.find(rIt.GetFormat());
640  if (aTextBoxIt != rSavedLinks.end())
641  {
642  std::size_t j = 0;
643  for (const auto& rJt : rOld)
644  {
645  if (rJt.GetFormat() == aTextBoxIt->second)
646  rNew[i]->SetFormatAttr(rNew[j]->GetContent());
647  ++j;
648  }
649  }
650  if (rResetContent.find(rIt.GetFormat()) != rResetContent.end())
651  const_cast<SwFrameFormat*>(rIt.GetFormat())
652  ->SetFormatAttr(rResetContent[rIt.GetFormat()]);
653  ++i;
654  }
655 }
656 
658 {
659  if (SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT))
660  {
661  SfxItemSet aTextBoxSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange);
662 
663  SfxItemIter aIter(rSet);
664  const SfxPoolItem* pItem = aIter.GetCurItem();
665  do
666  {
667  switch (pItem->Which())
668  {
669  case RES_VERT_ORIENT:
670  {
671  auto& rOrient = static_cast<const SwFormatVertOrient&>(*pItem);
672  SwFormatVertOrient aOrient(rOrient);
673 
674  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
675  if (!aRect.IsEmpty())
676  aOrient.SetPos(aOrient.GetPos() + aRect.getY());
677 
678  aTextBoxSet.Put(aOrient);
679 
680  // restore height (shrunk for extending beyond the page bottom - tdf#91260)
681  SwFormatFrameSize aSize(pFormat->GetFrameSize());
682  if (!aRect.IsEmpty())
683  {
684  aSize.SetHeight(aRect.getHeight());
685  aTextBoxSet.Put(aSize);
686  }
687  }
688  break;
689  case RES_HORI_ORIENT:
690  {
691  auto& rOrient = static_cast<const SwFormatHoriOrient&>(*pItem);
692  SwFormatHoriOrient aOrient(rOrient);
693 
694  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
695  if (!aRect.IsEmpty())
696  aOrient.SetPos(aOrient.GetPos() + aRect.getX());
697 
698  aTextBoxSet.Put(aOrient);
699  }
700  break;
701  case RES_FRM_SIZE:
702  {
703  // In case the shape got resized, then we need to adjust both
704  // the position and the size of the textbox (e.g. larger
705  // rounded edges of a rectangle -> need to push right/down the
706  // textbox).
707  SwFormatVertOrient aVertOrient(rShape.GetVertOrient());
708  SwFormatHoriOrient aHoriOrient(rShape.GetHoriOrient());
709  SwFormatFrameSize aSize(pFormat->GetFrameSize());
710 
711  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
712  if (!aRect.IsEmpty())
713  {
714  aVertOrient.SetPos(aVertOrient.GetPos() + aRect.getY());
715  aTextBoxSet.Put(aVertOrient);
716 
717  aHoriOrient.SetPos(aHoriOrient.GetPos() + aRect.getX());
718  aTextBoxSet.Put(aHoriOrient);
719 
720  aSize.SetWidth(aRect.getWidth());
721  aSize.SetHeight(aRect.getHeight());
722  aTextBoxSet.Put(aSize);
723  }
724  }
725  break;
726  default:
727  SAL_WARN("sw.core", "SwTextBoxHelper::syncFlyFrameAttr: unhandled which-id: "
728  << pItem->Which());
729  break;
730  }
731 
732  pItem = aIter.NextItem();
733  } while (pItem && (0 != pItem->Which()));
734 
735  if (aTextBoxSet.Count())
736  pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
737  }
738 }
739 
740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long getHeight() const
#define MID_CHAIN_NAME
Definition: unomid.h:58
#define RES_FRM_SIZE
Definition: hintids.hxx:196
static css::uno::Any getByIndex(SdrPage const *pPage, sal_Int32 nIndex)
Get a shape by index, excluding TextBoxes.
#define UNO_NAME_HORI_ORIENT_POSITION
Definition: unoprnms.hxx:267
#define UNO_NAME_TEXT_RIGHTDIST
SwDocShell * GetDocShell()
Definition: doc.hxx:1342
#define RES_HORI_ORIENT
Definition: hintids.hxx:210
#define UNO_NAME_BOTTOM_BORDER
Definition: unoprnms.hxx:361
#define UNO_NAME_RELATIVE_HEIGHT_RELATION
Definition: unoprnms.hxx:193
virtual bool QueryValue(css::uno::Any &rVal, sal_uInt8 nMemberId=0) const override
Definition: atrfrm.cxx:2039
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
static void destroy(SwFrameFormat *pShape)
Destroy a TextBox for a shape.
long getWidth() const
#define UNO_NAME_ALLOW_OVERLAP
Definition: unoprnms.hxx:871
SwTwips GetPos() const
Definition: fmtornt.hxx:92
#define RES_FRAMEDIR
Definition: hintids.hxx:227
#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:185
virtual bool IsTextBox() const
size_t GetObjCount() const
OUString GetUniqueFrameName() const
Definition: doclay.cxx:1374
#define RIGHT_BORDER_DISTANCE
Content, content of frame (header, footer, fly).
Definition: fmtcntnt.hxx:31
#define UNO_NAME_WRITING_MODE
Definition: unoprnms.hxx:698
#define UNO_NAME_VERT_ORIENT
Definition: unoprnms.hxx:333
#define RES_WRAP_INFLUENCE_ON_OBJPOS
Definition: hintids.hxx:232
#define UNO_NAME_TEXT_UPPERDIST
long getY() const
#define RES_CNTNT
Definition: hintids.hxx:202
static SwFrameFormat * getOtherTextBoxFormat(const SwFrameFormat *pFormat, sal_uInt16 nType)
If we have an associated TextFrame, then return that.
static void resetLink(SwFrameFormat *pShape, std::map< const SwFrameFormat *, SwFormatContent > &rOldContent)
Reset the shape -> textbox link on the shape, and save it to the map, so it can be restored later...
const SwFrameFormats * GetSpzFrameFormats() const
Definition: doc.hxx:737
std::map< const SwFrameFormat *, const SwFrameFormat * > SavedLink
Maps a draw format to a fly format.
static css::uno::Any queryInterface(const SwFrameFormat *pShape, const css::uno::Type &rType)
Get interface of a shape's TextBox, if there is any.
void Move(long nHorzMoveDelta, long nVertMoveDelta)
virtual const tools::Rectangle & GetSnapRect() const
bool IsEmpty() const
#define UNO_NAME_RELATIVE_WIDTH_RELATION
Definition: unoprnms.hxx:191
#define RES_CHAIN
Definition: hintids.hxx:221
#define UNO_NAME_CHAIN_NEXT_NAME
Definition: unoprnms.hxx:234
virtual css::uno::Reference< css::uno::XInterface > getUnoShape()
#define MID_FRMSIZE_SIZE
Definition: unomid.h:70
SdrPage * getSdrPageFromSdrObject() const
void SetOtherTextBoxFormat(SwFrameFormat *pFormat)
Definition: atrfrm.cxx:2477
static void restoreLinks(std::set< ZSortFly > &rOld, std::vector< SwFrameFormat * > &rNew, SavedLink &rSavedLinks, SavedContent &rResetContent)
Undo the effect of saveLinks() + individual resetLink() calls.
const OUString & GetName() const
Definition: format.hxx:111
#define UNO_NAME_SIZE
Definition: unoprnms.hxx:307
virtual void DelLayoutFormat(SwFrameFormat *pFormat)=0
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType)
Is the frame format a text box?
const SwFormatSurround & GetSurround(bool=true) const
Definition: fmtsrnd.hxx:66
#define UNO_NAME_VERT_ORIENT_RELATION
Definition: unoprnms.hxx:336
long Top() const
long getX() const
#define FN_TEXT_RANGE
Definition: cmdid.h:784
bool XTextRangeToSwPaM(SwUnoInternalPaM &rToFill, const uno::Reference< text::XTextRange > &xTextRange)
Definition: unoobj2.cxx:989
css::uno::Reference< css::frame::XModel > GetBaseModel() const
Specific frame formats (frames, DrawObjects).
Definition: docary.hxx:201
#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:263
#define RES_FLYFRMFMT
Definition: hintids.hxx:276
#define MID_CHAIN_NEXTNAME
Definition: unomid.h:57
#define MID_L_MARGIN
#define MID_ANCHOR_ANCHORTYPE
Definition: unomid.h:43
Style of a layout element.
Definition: frmfmt.hxx:57
#define MID_HORIORIENT_POSITION
Definition: unomid.h:40
#define RES_ANCHOR
Definition: hintids.hxx:211
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
#define UNO_NAME_RIGHT_BORDER
Definition: unoprnms.hxx:359
#define UNO_NAME_FILL_TRANSPARENCE
SwFrameFormat * GetOtherTextBoxFormat() const
Definition: frmfmt.hxx:101
const SwFormatHoriOrient & GetHoriOrient(bool=true) const
Definition: fmtornt.hxx:108
#define RES_VERT_ORIENT
Definition: hintids.hxx:209
#define MID_VERTORIENT_POSITION
Definition: unomid.h:36
int i
void SetPos(SwTwips nNew)
Definition: fmtornt.hxx:60
FlyAnchors.
Definition: fmtanchr.hxx:34
#define BOTTOM_BORDER_DISTANCE
static void getProperty(SwFrameFormat const *pShape, sal_uInt16 nWID, sal_uInt8 nMemberID, css::uno::Any &rValue)
Get a property of the underlying TextFrame.
sal_uInt32 GetOrdNum() const
css::text::WrapTextMode GetSurround() const
Definition: fmtsrnd.hxx:51
#define UNO_NAME_LEFT_BORDER
Definition: unoprnms.hxx:358
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:119
#define UNO_NAME_LEFT_BORDER_DISTANCE
Definition: unoprnms.hxx:363
#define UNO_NAME_CHAIN_PREV_NAME
Definition: unoprnms.hxx:235
bool SetFlyFrameAttr(SwFrameFormat &rFlyFormat, SfxItemSet &rSet)
Definition: docfly.cxx:540
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:404
#define UNO_NAME_RIGHT_MARGIN
Definition: unoprnms.hxx:67
#define RES_LR_SPACE
Definition: hintids.hxx:198
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
#define UNO_NAME_TOP_BORDER
Definition: unoprnms.hxx:360
sal_uInt16 const aFrameFormatSetRange[]
Definition: init.cxx:234
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:458
#define UNO_NAME_TOP_BORDER_DISTANCE
Definition: unoprnms.hxx:365
sal_uInt16 Which() const
for Querying of Writer-functions.
Definition: format.hxx:78
#define UNO_NAME_TEXT_VERT_ADJUST
Definition: unoprnms.hxx:860
#define UNO_NAME_SURROUND
Definition: unoprnms.hxx:314
#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:650
#define MID_CHAIN_PREVNAME
Definition: unomid.h:56
const SwFormatChain & GetChain(bool=true) const
Definition: fmtcnct.hxx:70
std::map< const SwFrameFormat *, SwFormatContent > SavedContent
Maps a draw format to content.
iterator find(const OUString &rKey)
Any makeAny(Color const &value)
#define UNO_NAME_LEFT_MARGIN
Definition: unoprnms.hxx:66
#define RES_DRAWFRMFMT
Definition: hintids.hxx:279
#define MID_VERTORIENT_ORIENT
Definition: unomid.h:34
unsigned char sal_uInt8
static void create(SwFrameFormat *pShape)
Create a TextBox for a shape.
#define UNO_NAME_BOTTOM_BORDER_DISTANCE
Definition: unoprnms.hxx:366
SwTwips GetPos() const
Definition: fmtornt.hxx:59
#define UNO_NAME_TEXT_LEFTDIST
#define MID_FRMSIZE_REL_WIDTH_RELATION
Definition: unomid.h:87
#define RES_OPAQUE
Definition: hintids.hxx:206
#define TWIPS_TO_MM(val)
#define UNO_NAME_HORI_ORIENT_RELATION
Definition: unoprnms.hxx:266
static SW_DLLPUBLIC css::uno::Reference< css::text::XTextFrame > CreateXTextFrame(SwDoc &rDoc, SwFrameFormat *pFrameFormat)
Definition: unoframe.cxx:3166
#define TOP_BORDER_DISTANCE
bool HasItem(sal_uInt16 nWhich, const SfxPoolItem **ppItem=nullptr) const
#define UNO_NAME_TEXT_AUTOGROWHEIGHT
void SetHeight(long n)
static css::uno::Reference< css::uno::XInterface > MakeInstance(SwServiceType nObjectType, SwDoc &rDoc)
Definition: unocoll.cxx:512
bool GetTextBounds(tools::Rectangle &rTextBound) const
static sal_Int32 getCount(const SwDoc *pDoc)
Count number of shapes in the document, excluding TextBoxes.
static tools::Rectangle getTextRectangle(SwFrameFormat *pShape, bool bAbsolute=true)
Return the textbox rectangle of a draw shape (in twips).
long Left() const
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:598
#define MID_HORIORIENT_RELATION
Definition: unomid.h:39
#define RES_BOX
Definition: hintids.hxx:213
static void syncFlyFrameAttr(SwFrameFormat &rShape, SfxItemSet const &rSet)
Similar to syncProperty(), but used by the internal API (e.g. for UI purposes).
constexpr sal_Int64 convertTwipToMm100(sal_Int64 n)
#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.
#define UNO_NAME_SIZE_TYPE
Definition: unoprnms.hxx:261
#define UNO_NAME_RIGHT_BORDER_DISTANCE
Definition: unoprnms.hxx:364
const SwAttrSet & GetAttrSet() const
For querying the attribute array.
Definition: format.hxx:116
#define UNO_NAME_VERT_ORIENT_POSITION
Definition: unoprnms.hxx:335
#define UNO_NAME_OPAQUE
Definition: unoprnms.hxx:286
sal_uInt16 Which() const
SdrObject * FindRealSdrObject()
Definition: atrfrm.cxx:2700
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1309
#define RES_TEXT_VERT_ADJUST
Definition: hintids.hxx:237
#define MID_ALLOW_OVERLAP
Definition: unomid.h:149
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1476
#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.