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_VERT_ORIENT:
454  switch (nMemberID)
455  {
457  aPropertyName = UNO_NAME_VERT_ORIENT;
458  break;
460  aPropertyName = UNO_NAME_VERT_ORIENT_RELATION;
461  break;
463  aPropertyName = UNO_NAME_VERT_ORIENT_POSITION;
464  bAdjustY = true;
465  break;
466  }
467  break;
468  case RES_FRM_SIZE:
469  switch (nMemberID)
470  {
472  aPropertyName = UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT;
473  break;
475  aPropertyName = UNO_NAME_RELATIVE_HEIGHT_RELATION;
476  break;
478  aPropertyName = UNO_NAME_RELATIVE_WIDTH_RELATION;
479  break;
480  default:
481  aPropertyName = UNO_NAME_SIZE;
482  bAdjustSize = true;
483  break;
484  }
485  break;
486  case RES_ANCHOR:
487  switch (nMemberID)
488  {
490  if (aValue.get<text::TextContentAnchorType>()
491  == text::TextContentAnchorType_AS_CHARACTER)
492  {
493  uno::Reference<beans::XPropertySet> const xPropertySet(
494  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat),
495  uno::UNO_QUERY);
496  xPropertySet->setPropertyValue(
497  UNO_NAME_SURROUND, uno::makeAny(text::WrapTextMode_THROUGH));
498  return;
499  }
500  break;
501  }
502  break;
503  case FN_TEXT_RANGE:
504  {
505  uno::Reference<text::XTextRange> xRange;
506  rValue >>= xRange;
507  SwUnoInternalPaM aInternalPaM(*pFormat->GetDoc());
508  if (sw::XTextRangeToSwPaM(aInternalPaM, xRange))
509  {
510  SwFormatAnchor aAnchor(pFormat->GetAnchor());
511  aAnchor.SetAnchor(aInternalPaM.Start());
512  pFormat->SetFormatAttr(aAnchor);
513  }
514  }
515  break;
516  case RES_CHAIN:
517  switch (nMemberID)
518  {
519  case MID_CHAIN_PREVNAME:
520  aPropertyName = UNO_NAME_CHAIN_PREV_NAME;
521  break;
522  case MID_CHAIN_NEXTNAME:
523  aPropertyName = UNO_NAME_CHAIN_NEXT_NAME;
524  break;
525  }
526  break;
528  aPropertyName = UNO_NAME_TEXT_VERT_ADJUST;
529  break;
530  case RES_BOX:
531  switch (nMemberID)
532  {
534  aPropertyName = UNO_NAME_LEFT_BORDER_DISTANCE;
535  break;
537  aPropertyName = UNO_NAME_RIGHT_BORDER_DISTANCE;
538  break;
539  case TOP_BORDER_DISTANCE:
540  aPropertyName = UNO_NAME_TOP_BORDER_DISTANCE;
541  break;
543  aPropertyName = UNO_NAME_BOTTOM_BORDER_DISTANCE;
544  break;
545  }
546  break;
547  case RES_OPAQUE:
548  aPropertyName = UNO_NAME_OPAQUE;
549  break;
550  case RES_FRAMEDIR:
551  aPropertyName = UNO_NAME_WRITING_MODE;
552  break;
553  }
554 
555  if (!aPropertyName.isEmpty())
556  {
557  // Position/size should be the text position/size, not the shape one as-is.
558  if (bAdjustX || bAdjustY || bAdjustSize)
559  {
560  tools::Rectangle aRect = getTextRectangle(pShape, /*bAbsolute=*/false);
561  if (!aRect.IsEmpty())
562  {
563  if (bAdjustX || bAdjustY)
564  {
565  sal_Int32 nValue;
566  if (aValue >>= nValue)
567  {
568  if (bAdjustX)
569  nValue += TWIPS_TO_MM(aRect.getX());
570  else if (bAdjustY)
571  nValue += TWIPS_TO_MM(aRect.getY());
572  aValue <<= nValue;
573  }
574  }
575  else if (bAdjustSize)
576  {
577  awt::Size aSize(TWIPS_TO_MM(aRect.getWidth()),
578  TWIPS_TO_MM(aRect.getHeight()));
579  aValue <<= aSize;
580  }
581  }
582  }
583 
584  uno::Reference<beans::XPropertySet> const xPropertySet(
585  SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat), uno::UNO_QUERY);
586  xPropertySet->setPropertyValue(aPropertyName, aValue);
587  }
588  }
589 }
590 
592  std::map<const SwFrameFormat*, const SwFrameFormat*>& rLinks)
593 {
594  for (const auto pFormat : rFormats)
595  {
596  if (SwFrameFormat* pTextBox = getOtherTextBoxFormat(pFormat, RES_DRAWFRMFMT))
597  rLinks[pFormat] = pTextBox;
598  }
599 }
600 
602  std::map<const SwFrameFormat*, SwFormatContent>& rOldContent)
603 {
604  if (pShape->Which() == RES_DRAWFRMFMT)
605  {
606  if (pShape->GetContent().GetContentIdx())
607  rOldContent.insert(std::make_pair(pShape, pShape->GetContent()));
608  pShape->ResetFormatAttr(RES_CNTNT);
609  }
610 }
611 
612 void SwTextBoxHelper::restoreLinks(std::set<ZSortFly>& rOld, std::vector<SwFrameFormat*>& rNew,
613  SavedLink& rSavedLinks, SavedContent& rResetContent)
614 {
615  std::size_t i = 0;
616  for (const auto& rIt : rOld)
617  {
618  auto aTextBoxIt = rSavedLinks.find(rIt.GetFormat());
619  if (aTextBoxIt != rSavedLinks.end())
620  {
621  std::size_t j = 0;
622  for (const auto& rJt : rOld)
623  {
624  if (rJt.GetFormat() == aTextBoxIt->second)
625  rNew[i]->SetFormatAttr(rNew[j]->GetContent());
626  ++j;
627  }
628  }
629  if (rResetContent.find(rIt.GetFormat()) != rResetContent.end())
630  const_cast<SwFrameFormat*>(rIt.GetFormat())
631  ->SetFormatAttr(rResetContent[rIt.GetFormat()]);
632  ++i;
633  }
634 }
635 
637 {
638  if (SwFrameFormat* pFormat = getOtherTextBoxFormat(&rShape, RES_DRAWFRMFMT))
639  {
640  SfxItemSet aTextBoxSet(pFormat->GetDoc()->GetAttrPool(), aFrameFormatSetRange);
641 
642  SfxItemIter aIter(rSet);
643  sal_uInt16 nWhich = aIter.GetCurItem()->Which();
644  do
645  {
646  switch (nWhich)
647  {
648  case RES_VERT_ORIENT:
649  {
650  auto& rOrient = static_cast<const SwFormatVertOrient&>(*aIter.GetCurItem());
651  SwFormatVertOrient aOrient(rOrient);
652 
653  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
654  if (!aRect.IsEmpty())
655  aOrient.SetPos(aOrient.GetPos() + aRect.getY());
656 
657  aTextBoxSet.Put(aOrient);
658 
659  // restore height (shrunk for extending beyond the page bottom - tdf#91260)
660  SwFormatFrameSize aSize(pFormat->GetFrameSize());
661  if (!aRect.IsEmpty())
662  {
663  aSize.SetHeight(aRect.getHeight());
664  aTextBoxSet.Put(aSize);
665  }
666  }
667  break;
668  case RES_HORI_ORIENT:
669  {
670  auto& rOrient = static_cast<const SwFormatHoriOrient&>(*aIter.GetCurItem());
671  SwFormatHoriOrient aOrient(rOrient);
672 
673  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
674  if (!aRect.IsEmpty())
675  aOrient.SetPos(aOrient.GetPos() + aRect.getX());
676 
677  aTextBoxSet.Put(aOrient);
678  }
679  break;
680  case RES_FRM_SIZE:
681  {
682  // In case the shape got resized, then we need to adjust both
683  // the position and the size of the textbox (e.g. larger
684  // rounded edges of a rectangle -> need to push right/down the
685  // textbox).
686  SwFormatVertOrient aVertOrient(rShape.GetVertOrient());
687  SwFormatHoriOrient aHoriOrient(rShape.GetHoriOrient());
688  SwFormatFrameSize aSize(pFormat->GetFrameSize());
689 
690  tools::Rectangle aRect = getTextRectangle(&rShape, /*bAbsolute=*/false);
691  if (!aRect.IsEmpty())
692  {
693  aVertOrient.SetPos(aVertOrient.GetPos() + aRect.getY());
694  aTextBoxSet.Put(aVertOrient);
695 
696  aHoriOrient.SetPos(aHoriOrient.GetPos() + aRect.getX());
697  aTextBoxSet.Put(aHoriOrient);
698 
699  aSize.SetWidth(aRect.getWidth());
700  aSize.SetHeight(aRect.getHeight());
701  aTextBoxSet.Put(aSize);
702  }
703  }
704  break;
705  default:
706  SAL_WARN("sw.core",
707  "SwTextBoxHelper::syncFlyFrameAttr: unhandled which-id: " << nWhich);
708  break;
709  }
710 
711  if (aIter.IsAtEnd())
712  break;
713  } while (0 != (nWhich = aIter.NextItem()->Which()));
714 
715  if (aTextBoxSet.Count())
716  pFormat->GetDoc()->SetFlyFrameAttr(*pFormat, aTextBoxSet);
717  }
718 }
719 
720 /* 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:194
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:1340
#define RES_HORI_ORIENT
Definition: hintids.hxx:208
#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:2049
const SwFormatVertOrient & GetVertOrient(bool=true) const
Definition: fmtornt.hxx:106
static void destroy(SwFrameFormat *pShape)
Destroy a TextBox for a shape.
long getWidth() const
SwTwips GetPos() const
Definition: fmtornt.hxx:92
#define RES_FRAMEDIR
Definition: hintids.hxx:225
#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:1387
#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 UNO_NAME_TEXT_UPPERDIST
long getY() const
#define RES_CNTNT
Definition: hintids.hxx:200
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:738
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:219
#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:2487
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:780
bool XTextRangeToSwPaM(SwUnoInternalPaM &rToFill, const uno::Reference< text::XTextRange > &xTextRange)
Definition: unoobj2.cxx:1009
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:274
#define MID_CHAIN_NEXTNAME
Definition: unomid.h:57
#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:209
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:207
#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_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:548
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:437
const SwNodeIndex * GetContentIdx() const
Definition: fmtcntnt.hxx:46
#define UNO_NAME_TOP_BORDER
Definition: unoprnms.hxx:360
sal_uInt16 const aFrameFormatSetRange[]
Definition: init.cxx:240
virtual bool SetFormatAttr(const SfxPoolItem &rAttr)
Definition: format.cxx:460
#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:652
#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 RES_DRAWFRMFMT
Definition: hintids.hxx:277
#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:204
#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:3152
#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:211
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
SdrObject * FindRealSdrObject()
Definition: atrfrm.cxx:2686
const SwAttrPool & GetAttrPool() const
Definition: doc.hxx:1307
#define RES_TEXT_VERT_ADJUST
Definition: hintids.hxx:235
void SetAnchor(const SwPosition *pPos)
Definition: atrfrm.cxx:1486
#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.