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