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