LibreOffice Module sw (master)  1
unoportenum.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  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22 
23 #include <utility>
24 
25 #include <unoport.hxx>
26 #include <IMark.hxx>
27 #include <crossrefbookmark.hxx>
28 #include <annotationmark.hxx>
29 #include <doc.hxx>
31 #include <txatbase.hxx>
32 #include <txtatr.hxx>
33 #include <ndhints.hxx>
34 #include <ndtxt.hxx>
35 #include <unocrsr.hxx>
36 #include <docary.hxx>
37 #include <textboxhelper.hxx>
38 #include <tox.hxx>
39 #include <unoparaframeenum.hxx>
40 #include <unocrsrhelper.hxx>
41 #include <unorefmark.hxx>
42 #include <unobookmark.hxx>
43 #include <unofield.hxx>
44 #include <unometa.hxx>
45 #include <fmtfld.hxx>
46 #include <fldbas.hxx>
47 #include <fmtmeta.hxx>
48 #include <fmtanchr.hxx>
49 #include <fmtrfmrk.hxx>
50 #include <frmfmt.hxx>
51 #include <fmtflcnt.hxx>
52 #include <unoidx.hxx>
53 #include <unocoll.hxx>
54 #include <redline.hxx>
55 #include <txtannotationfld.hxx>
56 #include <vcl/svapp.hxx>
57 #include <comphelper/string.hxx>
60 #include <com/sun/star/container/XEnumeration.hpp>
61 #include <algorithm>
62 #include <memory>
63 #include <set>
64 #include <stack>
65 
66 using namespace ::com::sun::star;
67 using namespace ::com::sun::star::uno;
68 using namespace ::com::sun::star::text;
69 using namespace ::std;
70 
71 typedef std::pair< TextRangeList_t * const, SwTextAttr const * const > PortionList_t;
72 typedef std::stack< PortionList_t > PortionStack_t;
73 
74 static void lcl_CreatePortions(
75  TextRangeList_t & i_rPortions,
76  uno::Reference< text::XText > const& i_xParentText,
77  SwUnoCursor* pUnoCursor,
78  FrameClientSortList_t & i_rFrames,
79  const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos );
80 
81 namespace
82 {
83  enum class BkmType {
84  Start, End, StartEnd
85  };
86 
87  struct SwXBookmarkPortion_Impl
88  {
89  Reference<XTextContent> xBookmark;
90  BkmType nBkmType;
91  const SwPosition aPosition;
92 
93  SwXBookmarkPortion_Impl(uno::Reference<text::XTextContent> const& xMark,
94  const BkmType nType, SwPosition const& rPosition)
95  : xBookmark ( xMark )
96  , nBkmType ( nType )
97  , aPosition ( rPosition )
98  {
99  }
100  sal_Int32 getIndex () const
101  {
102  return aPosition.nContent.GetIndex();
103  }
104  };
105  typedef std::shared_ptr < SwXBookmarkPortion_Impl > SwXBookmarkPortion_ImplSharedPtr;
106  struct BookmarkCompareStruct
107  {
108  bool operator () ( const SwXBookmarkPortion_ImplSharedPtr &r1,
109  const SwXBookmarkPortion_ImplSharedPtr &r2 ) const
110  {
111  // #i16896# for bookmark portions at the same position, the start should
112  // always precede the end. Hence compare positions, and use bookmark type
113  // as tie-breaker for same position.
114  // return ( r1->nIndex == r2->nIndex )
115  // ? ( r1->nBkmType < r2->nBkmType )
116  // : ( r1->nIndex < r2->nIndex );
117 
118  // Note that the above code does not correctly handle
119  // the case when one bookmark ends, and another begins in the same
120  // position. When this occurs, the above code will return the
121  // start of the 2nd bookmark BEFORE the end of the first bookmark
122  // See bug #i58438# for more details. The below code is correct and
123  // fixes both #i58438 and #i16896#
124  return r1->aPosition < r2->aPosition;
125  }
126  };
127  typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList;
128 
130  void lcl_FillBookmark(sw::mark::IMark* const pBkmk, const SwNodeIndex& nOwnNode, SwDoc& rDoc, SwXBookmarkPortion_ImplList& rBkmArr)
131  {
132  bool const hasOther = pBkmk->IsExpanded();
133 
134  const SwPosition& rStartPos = pBkmk->GetMarkStart();
135  if(rStartPos.nNode == nOwnNode)
136  {
137  // #i109272#: cross reference marks: need special handling!
138  ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
139  BkmType const nType = (hasOther || pCrossRefMark)
140  ? BkmType::Start : BkmType::StartEnd;
141  rBkmArr.insert(std::make_shared<SwXBookmarkPortion_Impl>(
142  SwXBookmark::CreateXBookmark(rDoc, pBkmk),
143  nType, rStartPos));
144  }
145 
146  const SwPosition& rEndPos = pBkmk->GetMarkEnd();
147  if(rEndPos.nNode != nOwnNode)
148  return;
149 
150  unique_ptr<SwPosition> pCrossRefEndPos;
151  const SwPosition* pEndPos = nullptr;
152  ::sw::mark::CrossRefBookmark *const pCrossRefMark(dynamic_cast< ::sw::mark::CrossRefBookmark*>(pBkmk));
153  if(hasOther)
154  {
155  pEndPos = &rEndPos;
156  }
157  else if (pCrossRefMark)
158  {
159  // Crossrefbookmarks only remember the start position but have to span the whole paragraph
160  pCrossRefEndPos = std::make_unique<SwPosition>(rEndPos);
161  pCrossRefEndPos->nContent = pCrossRefEndPos->nNode.GetNode().GetTextNode()->Len();
162  pEndPos = pCrossRefEndPos.get();
163  }
164  if(pEndPos)
165  {
166  rBkmArr.insert(std::make_shared<SwXBookmarkPortion_Impl>(
167  SwXBookmark::CreateXBookmark(rDoc, pBkmk),
168  BkmType::End, *pEndPos));
169  }
170  }
171 
172  void lcl_FillBookmarkArray(SwDoc& rDoc, SwUnoCursor& rUnoCursor, SwXBookmarkPortion_ImplList& rBkmArr)
173  {
174  IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
175  if(!pMarkAccess->getBookmarksCount())
176  return;
177 
178  const SwNodeIndex nOwnNode = rUnoCursor.GetPoint()->nNode;
179  SwTextNode* pTextNode = nOwnNode.GetNode().GetTextNode();
180  assert(pTextNode);
181  // A text node already knows its marks via its SwIndexes.
183  for (const SwIndex* pIndex = pTextNode->GetFirstIndex(); pIndex; pIndex = pIndex->GetNext())
184  {
185  // Need a non-cost mark here, as we'll create a UNO wrapper around it.
186  sw::mark::IMark* pBkmk = const_cast<sw::mark::IMark*>(pIndex->GetMark());
187  if (!pBkmk)
188  continue;
190  // These are the types stored in the container otherwise accessible via getBookmarks*()
193  continue;
194  // Only handle bookmarks once, if they start and end at this node as well.
195  if (!aSeenMarks.insert(pBkmk).second)
196  continue;
197  lcl_FillBookmark(pBkmk, nOwnNode, rDoc, rBkmArr);
198  }
199  }
200 
201  struct SwAnnotationStartPortion_Impl
202  {
203 
204  uno::Reference< text::XTextField > mxAnnotationField;
205  const SwPosition maPosition;
206 
207  SwAnnotationStartPortion_Impl(
208  uno::Reference< text::XTextField > const& xAnnotationField,
209  SwPosition const& rPosition)
210  : mxAnnotationField ( xAnnotationField )
211  , maPosition ( rPosition )
212  {
213  }
214 
215  sal_Int32 getIndex () const
216  {
217  return maPosition.nContent.GetIndex();
218  }
219  };
220  typedef std::shared_ptr < SwAnnotationStartPortion_Impl > SwAnnotationStartPortion_ImplSharedPtr;
221  struct AnnotationStartCompareStruct
222  {
223  bool operator () ( const SwAnnotationStartPortion_ImplSharedPtr &r1,
224  const SwAnnotationStartPortion_ImplSharedPtr &r2 )
225  const
226  {
227  return r1->maPosition < r2->maPosition;
228  }
229  };
230  typedef std::multiset < SwAnnotationStartPortion_ImplSharedPtr, AnnotationStartCompareStruct > SwAnnotationStartPortion_ImplList;
231 
232  void lcl_FillAnnotationStartArray(
233  SwDoc& rDoc,
234  SwUnoCursor& rUnoCursor,
235  SwAnnotationStartPortion_ImplList& rAnnotationStartArr )
236  {
237  IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
238  if ( pMarkAccess->getAnnotationMarksCount() == 0 )
239  {
240  return;
241  }
242 
243  // no need to consider annotation marks starting after aEndOfPara
244  SwPosition aEndOfPara(*rUnoCursor.GetPoint());
245  aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTextNode()->Len();
246  const IDocumentMarkAccess::const_iterator_t pCandidatesEnd =
247  pMarkAccess->findFirstAnnotationStartsAfter(aEndOfPara);
248 
249  // search for all annotation marks that have its start position in this paragraph
250  const SwNodeIndex nOwnNode = rUnoCursor.GetPoint()->nNode;
252  ppMark != pCandidatesEnd;
253  ++ppMark )
254  {
255  ::sw::mark::AnnotationMark* const pAnnotationMark =
256  dynamic_cast< ::sw::mark::AnnotationMark* >(*ppMark);
257 
258  if (!pAnnotationMark)
259  continue;
260 
261  const SwPosition& rStartPos = pAnnotationMark->GetMarkStart();
262  if (rStartPos.nNode != nOwnNode)
263  continue;
264 
265  const SwFormatField* pAnnotationFormatField = pAnnotationMark->GetAnnotationFormatField();
266  if (!pAnnotationFormatField)
267  {
268  SAL_WARN("sw.core", "missing annotation format field");
269  continue;
270  }
271 
272  rAnnotationStartArr.insert(
273  std::make_shared<SwAnnotationStartPortion_Impl>(
275  pAnnotationFormatField),
276  rStartPos));
277  }
278  }
279 }
280 
281 const uno::Sequence< sal_Int8 > & SwXTextPortionEnumeration::getUnoTunnelId()
282 {
283  static const UnoTunnelIdInit theSwXTextPortionEnumerationUnoTunnelId;
284  return theSwXTextPortionEnumerationUnoTunnelId.getSeq();
285 }
286 
288  const uno::Sequence< sal_Int8 >& rId )
289 {
290  if( isUnoTunnelId<SwXTextPortionEnumeration>(rId) )
291  {
292  return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ) );
293  }
294  return 0;
295 }
296 
298 {
299  return "SwXTextPortionEnumeration";
300 }
301 
302 sal_Bool
303 SwXTextPortionEnumeration::supportsService(const OUString& rServiceName)
304 {
305  return cppu::supportsService(this, rServiceName);
306 }
307 
309 {
310  return { "com.sun.star.text.TextPortionEnumeration" };
311 }
312 
314  SwPaM& rParaCursor,
315  uno::Reference< XText > const & xParentText,
316  const sal_Int32 nStart,
317  const sal_Int32 nEnd )
318  : m_Portions()
319 {
320  m_pUnoCursor = rParaCursor.GetDoc().CreateUnoCursor(*rParaCursor.GetPoint());
321 
322  OSL_ENSURE(nEnd == -1 || (nStart <= nEnd &&
323  nEnd <= m_pUnoCursor->Start()->nNode.GetNode().GetTextNode()->GetText().getLength()),
324  "start or end value invalid!");
325 
326  // find all frames, graphics and OLEs that are bound AT character in para
327  FrameClientSortList_t frames;
328  ::CollectFrameAtNode(m_pUnoCursor->GetPoint()->nNode, frames, true);
329  lcl_CreatePortions(m_Portions, xParentText, &*m_pUnoCursor, frames, nStart, nEnd);
330 }
331 
333  SwPaM& rParaCursor,
334  TextRangeList_t const & rPortions )
335  : m_Portions( rPortions )
336 {
337  m_pUnoCursor = rParaCursor.GetDoc().CreateUnoCursor(*rParaCursor.GetPoint());
338 }
339 
341 {
342  SolarMutexGuard aGuard;
343  m_pUnoCursor.reset(nullptr);
344 }
345 
347 {
348  SolarMutexGuard aGuard;
349 
350  return !m_Portions.empty();
351 }
352 
354 {
355  SolarMutexGuard aGuard;
356 
357  if (m_Portions.empty())
358  throw container::NoSuchElementException();
359 
360  Any any;
361  any <<= m_Portions.front();
362  m_Portions.pop_front();
363  return any;
364 }
365 
366 static void
367 lcl_FillFieldMarkArray(std::deque<sal_Int32> & rFieldMarks, SwUnoCursor const & rUnoCursor,
368  const sal_Int32 i_nStartPos)
369 {
370  const SwTextNode * const pTextNode =
371  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
372  if (!pTextNode) return;
373 
374  const sal_Unicode fld[] = {
376  sal_Int32 pos = std::max(static_cast<sal_Int32>(0), i_nStartPos);
377  while ((pos = ::comphelper::string::indexOfAny(pTextNode->GetText(), fld, pos)) != -1)
378  {
379  rFieldMarks.push_back(pos);
380  ++pos;
381  }
382 }
383 
384 static uno::Reference<text::XTextRange>
386  uno::Reference< text::XText > const & i_xParentText,
387  SwUnoCursor * const pUnoCursor,
388  const SwTextNode * const pTextNode )
389 {
390  uno::Reference<text::XTextRange> xRef;
391  SwDoc& rDoc = pUnoCursor->GetDoc();
392  // maybe it's a good idea to add a special hint to the hints array and rely on the hint segmentation...
393  const sal_Int32 start = pUnoCursor->Start()->nContent.GetIndex();
394  OSL_ENSURE(pUnoCursor->End()->nContent.GetIndex() == start,
395  "hmm --- why is this different");
396 
397  pUnoCursor->Right(1);
398  if ( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
399  {
400  OSL_FAIL("cannot move cursor?");
401  return nullptr;
402  }
403 
404  const sal_Unicode Char = pTextNode->GetText()[start];
405  if (CH_TXT_ATR_FIELDSTART == Char)
406  {
407  ::sw::mark::IFieldmark* pFieldmark = nullptr;
408  pFieldmark = rDoc.getIDocumentMarkAccess()->
409  getFieldmarkAt(*pUnoCursor->GetMark());
411  pUnoCursor, i_xParentText, PORTION_FIELD_START);
412  xRef = pPortion;
413  if (pFieldmark)
414  {
415  pPortion->SetBookmark(
416  SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark));
417  }
418  }
419  else if (CH_TXT_ATR_FIELDSEP == Char)
420  {
421  // TODO how to get the field?
422  xRef = new SwXTextPortion(
423  pUnoCursor, i_xParentText, PORTION_FIELD_SEP);
424  }
425  else if (CH_TXT_ATR_FIELDEND == Char)
426  {
427  ::sw::mark::IFieldmark* pFieldmark = nullptr;
428  pFieldmark = rDoc.getIDocumentMarkAccess()->
429  getFieldmarkAt(*pUnoCursor->GetMark());
431  pUnoCursor, i_xParentText, PORTION_FIELD_END);
432  xRef = pPortion;
433  if (pFieldmark)
434  {
435  pPortion->SetBookmark(
436  SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark));
437  }
438  }
439  else if (CH_TXT_ATR_FORMELEMENT == Char)
440  {
441  ::sw::mark::IFieldmark* pFieldmark =
442  rDoc.getIDocumentMarkAccess()->getFieldmarkAt(*pUnoCursor->GetMark());
444  pUnoCursor, i_xParentText, PORTION_FIELD_START_END);
445  xRef = pPortion;
446  if (pFieldmark)
447  {
448  pPortion->SetBookmark(
449  SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark));
450  }
451  }
452  else
453  {
454  OSL_FAIL("no fieldmark found?");
455  }
456  return xRef;
457 }
458 
459 static Reference<XTextRange>
461  Reference<XText> const& xParent,
462  const SwUnoCursor * const pUnoCursor,
463  const SwTextAttr & rAttr, const bool bEnd)
464 {
465  SwDoc& rDoc = pUnoCursor->GetDoc();
466  SwFormatRefMark& rRefMark = const_cast<SwFormatRefMark&>(
467  static_cast<const SwFormatRefMark&>(rAttr.GetAttr()));
468  Reference<XTextContent> xContent;
469  if (!xContent.is())
470  {
471  xContent = SwXReferenceMark::CreateXReferenceMark(rDoc, &rRefMark);
472  }
473 
475  if (!bEnd)
476  {
477  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_START);
478  pPortion->SetRefMark(xContent);
479  pPortion->SetCollapsed(rAttr.End() == nullptr);
480  }
481  else
482  {
483  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_END);
484  pPortion->SetRefMark(xContent);
485  }
486  return pPortion;
487 }
488 
489 static void
491  TextRangeList_t & rPortions,
492  Reference<XText> const& xParent,
493  const SwUnoCursor * const pUnoCursor,
494  const SwTextAttr & rAttr, const bool bEnd)
495 {
496  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(pUnoCursor,
497  static_txtattr_cast<const SwTextRuby&>(rAttr), xParent, bEnd);
498  rPortions.emplace_back(pPortion);
499  pPortion->SetCollapsed(rAttr.End() == nullptr);
500 }
501 
502 static Reference<XTextRange>
504  Reference<XText> const& xParent,
505  const SwUnoCursor * const pUnoCursor,
506  SwTextAttr & rAttr, const bool bEnd)
507 {
508  SwDoc& rDoc = pUnoCursor->GetDoc();
509  SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr());
510 
511  const Reference<XTextContent> xContent =
513 
515  if (!bEnd)
516  {
517  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_START);
518  pPortion->SetTOXMark(xContent);
519  pPortion->SetCollapsed(rAttr.GetEnd() == nullptr);
520  }
521  else
522  {
523  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_END);
524  pPortion->SetTOXMark(xContent);
525  }
526  return pPortion;
527 }
528 
529 static uno::Reference<text::XTextRange>
531  uno::Reference<text::XText> const& xParent,
532  const SwUnoCursor * const pUnoCursor,
533  SwTextAttr & rAttr, std::unique_ptr<TextRangeList_t const> && pPortions)
534 {
535  const uno::Reference<rdf::XMetadatable> xMeta( SwXMeta::CreateXMeta(
536  *static_cast<SwFormatMeta &>(rAttr.GetAttr()).GetMeta(),
537  xParent, std::move(pPortions)));
539  if (RES_TXTATR_META == rAttr.Which())
540  {
541  const uno::Reference<text::XTextContent> xContent(xMeta,
542  uno::UNO_QUERY);
543  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_META);
544  pPortion->SetMeta(xContent);
545  }
546  else
547  {
548  const uno::Reference<text::XTextField> xField(xMeta, uno::UNO_QUERY);
549  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_FIELD);
550  pPortion->SetTextField(xField);
551  }
552  return pPortion;
553 }
554 
569 static void lcl_ExportBookmark(
570  TextRangeList_t & rPortions,
571  Reference<XText> const& xParent,
572  const SwUnoCursor * const pUnoCursor,
573  SwXBookmarkPortion_ImplList& rBkmArr,
574  const sal_Int32 nIndex,
575  const o3tl::sorted_vector<sal_Int32>& rFramePositions,
576  bool bOnlyFrameStarts)
577 {
578  for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; )
579  {
580  const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter;
581  if ( nIndex > pPtr->getIndex() )
582  {
583  if (bOnlyFrameStarts)
584  ++aIter;
585  else
586  aIter = rBkmArr.erase(aIter);
587  continue;
588  }
589  if ( nIndex < pPtr->getIndex() )
590  break;
591 
592  if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) ||
593  (BkmType::StartEnd == pPtr->nBkmType))
594  {
595  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
596  bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts;
597  if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts)
598  {
599  // At this we create a text portion, due to one of these
600  // reasons:
601  // - this is the real start of a non-collapsed bookmark
602  // - this is the real position of a collapsed bookmark
603  // - this is the start or end (depending on bOnlyFrameStarts)
604  // of a collapsed bookmark at the same position as an at-char
605  // anchored frame
607  new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START);
608  rPortions.emplace_back(pPortion);
609  pPortion->SetBookmark(pPtr->xBookmark);
610  pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart );
611  }
612  }
613  else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts)
614  {
616  new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END);
617  rPortions.emplace_back(pPortion);
618  pPortion->SetBookmark(pPtr->xBookmark);
619  }
620 
621  // next bookmark
622  if (bOnlyFrameStarts)
623  ++aIter;
624  else
625  aIter = rBkmArr.erase(aIter);
626  }
627 }
628 
630  TextRangeList_t & rPortions,
631  Reference<XText> const& xParent,
632  const SwUnoCursor * const pUnoCursor,
633  SwSoftPageBreakList& rBreakArr,
634  const sal_Int32 nIndex)
635 {
636  for ( auto aIter = rBreakArr.begin(); aIter != rBreakArr.end(); )
637  {
638  if ( nIndex > *aIter )
639  {
640  aIter = rBreakArr.erase(aIter);
641  continue;
642  }
643  if ( nIndex < *aIter )
644  break;
645 
646  rPortions.push_back(
647  new SwXTextPortion(pUnoCursor, xParent, PORTION_SOFT_PAGEBREAK) );
648  aIter = rBreakArr.erase(aIter);
649  }
650 }
651 
652 namespace {
653 
654 struct SwXRedlinePortion_Impl
655 {
656  const SwRangeRedline* m_pRedline;
657  const bool m_bStart;
658 
659  SwXRedlinePortion_Impl ( const SwRangeRedline* pRed, const bool bIsStart )
660  : m_pRedline(pRed)
661  , m_bStart(bIsStart)
662  {
663  }
664 
665  sal_Int32 getRealIndex () const
666  {
667  return m_bStart ? m_pRedline->Start()->nContent.GetIndex()
668  : m_pRedline->End() ->nContent.GetIndex();
669  }
670 };
671 
672 }
673 
674 typedef std::shared_ptr < SwXRedlinePortion_Impl >
676 
677 namespace {
678 
679 struct RedlineCompareStruct
680 {
681  static const SwPosition& getPosition ( const SwXRedlinePortion_ImplSharedPtr &r )
682  {
683  return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End());
684  }
685 
686  bool operator () ( const SwXRedlinePortion_ImplSharedPtr &r1,
687  const SwXRedlinePortion_ImplSharedPtr &r2 ) const
688  {
689  return getPosition ( r1 ) < getPosition ( r2 );
690  }
691 };
692 
693 }
694 
695 typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct >
697 
698 static Reference<XTextRange>
700  PortionStack_t & rPortionStack,
701  const Reference<XText> & xParent,
702  SwUnoCursor * const pUnoCursor,
703  SwpHints const * const pHints,
704  const sal_Int32 i_nStartPos,
705  const sal_Int32 i_nEndPos,
706  const sal_Int32 nCurrentIndex,
707  const bool bRightMoveForbidden,
708  bool & o_rbCursorMoved,
709  sal_Int32 & o_rNextAttrPosition)
710 {
711  // if the attribute has a dummy character, then xRef is set (except META)
712  // otherwise, the portion for the attribute is inserted into rPortions!
713  Reference<XTextRange> xRef;
714  SwDoc& rDoc = pUnoCursor->GetDoc();
715  //search for special text attributes - first some ends
716  size_t nEndIndex = 0;
717  sal_Int32 nNextEnd = 0;
718  while(nEndIndex < pHints->Count() &&
719  (!pHints->GetSortedByEnd(nEndIndex)->GetEnd() ||
720  nCurrentIndex >= (nNextEnd = (*pHints->GetSortedByEnd(nEndIndex)->GetEnd()))))
721  {
722  if(pHints->GetSortedByEnd(nEndIndex)->GetEnd())
723  {
724  SwTextAttr * const pAttr = pHints->GetSortedByEnd(nEndIndex);
725  if (nNextEnd == nCurrentIndex)
726  {
727  const sal_uInt16 nWhich( pAttr->Which() );
728  switch (nWhich)
729  {
730  case RES_TXTATR_TOXMARK:
731  {
732  Reference<XTextRange> xTmp = lcl_CreateTOXMarkPortion(
733  xParent, pUnoCursor, *pAttr, true);
734  rPortionStack.top().first->push_back(xTmp);
735  }
736  break;
737  case RES_TXTATR_REFMARK:
738  {
739  Reference<XTextRange> xTmp = lcl_CreateRefMarkPortion(
740  xParent, pUnoCursor, *pAttr, true);
741  rPortionStack.top().first->push_back(xTmp);
742  }
743  break;
744  case RES_TXTATR_CJK_RUBY:
745  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
746  if( *pAttr->GetEnd() == pAttr->GetStart())
747  {
748  lcl_InsertRubyPortion( *rPortionStack.top().first,
749  xParent, pUnoCursor, *pAttr, false);
750  }
751  lcl_InsertRubyPortion( *rPortionStack.top().first,
752  xParent, pUnoCursor, *pAttr, true);
753  break;
754  case RES_TXTATR_META:
756  {
757  OSL_ENSURE(pAttr->GetStart() != *pAttr->GetEnd(),
758  "empty meta?");
759  if ((i_nStartPos > 0) &&
760  (pAttr->GetStart() < i_nStartPos))
761  {
762  // force skip pAttr and rest of attribute ends
763  // at nCurrentIndex
764  // because they are not contained in the meta pAttr
765  // and the meta pAttr itself is outside selection!
766  // (necessary for SwXMeta::createEnumeration)
767  if (pAttr->GetStart() + 1 == i_nStartPos)
768  {
769  nEndIndex = pHints->Count() - 1;
770  }
771  break;
772  }
773  PortionList_t Top = rPortionStack.top();
774  if (Top.second != pAttr)
775  {
776  OSL_FAIL("ExportHints: stack error" );
777  }
778  else
779  {
780  std::unique_ptr<const TextRangeList_t>
781  pCurrentPortions(Top.first);
782  rPortionStack.pop();
783  const uno::Reference<text::XTextRange> xPortion(
784  lcl_CreateMetaPortion(xParent, pUnoCursor,
785  *pAttr, std::move(pCurrentPortions)));
786  rPortionStack.top().first->push_back(xPortion);
787  }
788  }
789  break;
790  }
791  }
792  }
793  nEndIndex++;
794  }
795 
796  // then some starts
797  size_t nStartIndex = 0;
798  sal_Int32 nNextStart = 0;
799  while(nStartIndex < pHints->Count() &&
800  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
801  {
802  SwTextAttr * const pAttr = pHints->Get(nStartIndex);
803  sal_uInt16 nAttrWhich = pAttr->Which();
804  if (nNextStart == nCurrentIndex)
805  {
806  switch( nAttrWhich )
807  {
808  case RES_TXTATR_FIELD:
809  if(!bRightMoveForbidden)
810  {
811  pUnoCursor->Right(1);
812  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
813  break;
815  new SwXTextPortion(
816  pUnoCursor, xParent, PORTION_FIELD);
817  xRef = pPortion;
818  Reference<XTextField> const xField =
820  &pAttr->GetFormatField());
821  pPortion->SetTextField(xField);
822  }
823  break;
824 
826  if(!bRightMoveForbidden)
827  {
828  pUnoCursor->Right(1);
829  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
830  break;
831 
832  const SwTextAnnotationField* pTextAnnotationField = dynamic_cast<const SwTextAnnotationField*>( pAttr );
833  ::sw::mark::IMark* pAnnotationMark = pTextAnnotationField ? pTextAnnotationField->GetAnnotationMark() : nullptr;
834  if ( pAnnotationMark != nullptr )
835  {
836  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION_END );
837  pPortion->SetBookmark(SwXBookmark::CreateXBookmark(
838  rDoc, pAnnotationMark));
839  xRef = pPortion;
840  }
841  else
842  {
843  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
844  Reference<XTextField> xField =
846  &pAttr->GetFormatField());
847  pPortion->SetTextField(xField);
848  xRef = pPortion;
849  }
850  }
851  break;
852 
854  if(!bRightMoveForbidden)
855  {
856 
857  pUnoCursor->Right(
858  pAttr->GetFormatField().GetField()->ExpandField(true, nullptr).getLength() + 2 );
859  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
860  break;
862  new SwXTextPortion( pUnoCursor, xParent, PORTION_FIELD);
863  xRef = pPortion;
864  Reference<XTextField> xField =
866  &pAttr->GetFormatField());
867  pPortion->SetTextField(xField);
868  }
869  break;
870 
871  case RES_TXTATR_FLYCNT:
872  if(!bRightMoveForbidden)
873  {
874  pUnoCursor->Right(1);
875  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
876  break; // Robust #i81708# content in covered cells
877 
878  // Do not expose inline anchored textboxes.
880  break;
881 
882  pUnoCursor->Exchange();
883  xRef = new SwXTextPortion( pUnoCursor, xParent, PORTION_FRAME);
884  }
885  break;
886 
887  case RES_TXTATR_FTN:
888  {
889  if(!bRightMoveForbidden)
890  {
891  pUnoCursor->Right(1);
892  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
893  break;
895  pUnoCursor, xParent, PORTION_FOOTNOTE);
896  xRef = pPortion;
897  Reference<XFootnote> xContent =
898  SwXFootnotes::GetObject(rDoc, pAttr->GetFootnote());
899  pPortion->SetFootnote(xContent);
900  }
901  }
902  break;
903 
904  case RES_TXTATR_TOXMARK:
905  case RES_TXTATR_REFMARK:
906  {
907  bool bIsPoint = !(pAttr->GetEnd());
908  if (!bRightMoveForbidden || !bIsPoint)
909  {
910  if (bIsPoint)
911  {
912  pUnoCursor->Right(1);
913  }
914  Reference<XTextRange> xTmp =
915  (RES_TXTATR_REFMARK == nAttrWhich)
917  xParent, pUnoCursor, *pAttr, false)
919  xParent, pUnoCursor, *pAttr, false);
920  if (bIsPoint) // consume CH_TXTATR!
921  {
922  pUnoCursor->Normalize(false);
923  pUnoCursor->DeleteMark();
924  xRef = xTmp;
925  }
926  else // just insert it
927  {
928  rPortionStack.top().first->push_back(xTmp);
929  }
930  }
931  }
932  break;
933  case RES_TXTATR_CJK_RUBY:
934  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
935  if(pAttr->GetEnd() && (*pAttr->GetEnd() != pAttr->GetStart()))
936  {
937  lcl_InsertRubyPortion( *rPortionStack.top().first,
938  xParent, pUnoCursor, *pAttr, false);
939  }
940  break;
941  case RES_TXTATR_META:
943  if (pAttr->GetStart() != *pAttr->GetEnd())
944  {
945  if (!bRightMoveForbidden)
946  {
947  pUnoCursor->Right(1);
948  o_rbCursorMoved = true;
949  // only if the end is included in selection!
950  if ((i_nEndPos < 0) ||
951  (*pAttr->GetEnd() <= i_nEndPos))
952  {
953  rPortionStack.push( std::make_pair(
954  new TextRangeList_t, pAttr ));
955  }
956  }
957  }
958  break;
959  case RES_TXTATR_AUTOFMT:
960  case RES_TXTATR_INETFMT:
961  case RES_TXTATR_CHARFMT:
962  break; // these are handled as properties of a "Text" portion
963  default:
964  OSL_FAIL("unknown attribute");
965  break;
966  }
967  }
968  nStartIndex++;
969  }
970 
971  if (xRef.is()) // implies that we have moved the cursor
972  {
973  o_rbCursorMoved = true;
974  }
975  if (!o_rbCursorMoved)
976  {
977  // search for attribute changes behind the current cursor position
978  // break up at frames, bookmarks, redlines
979 
980  nStartIndex = 0;
981  nNextStart = 0;
982  while(nStartIndex < pHints->Count() &&
983  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
984  nStartIndex++;
985 
986  nEndIndex = 0;
987  nNextEnd = 0;
988  while(nEndIndex < pHints->Count() &&
989  nCurrentIndex >= (nNextEnd = pHints->GetSortedByEnd(nEndIndex)->GetAnyEnd()))
990  nEndIndex++;
991 
992  sal_Int32 nNextPos =
993  ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd))
994  ? nNextStart : nNextEnd;
995  if (nNextPos > nCurrentIndex)
996  {
997  o_rNextAttrPosition = nNextPos;
998  }
999  }
1000  return xRef;
1001 }
1002 
1003 static void lcl_MoveCursor( SwUnoCursor * const pUnoCursor,
1004  const sal_Int32 nCurrentIndex,
1005  const sal_Int32 nNextFrameIndex,
1006  const sal_Int32 nNextPortionIndex,
1007  const sal_Int32 nNextAttrIndex,
1008  const sal_Int32 nNextMarkIndex,
1009  const sal_Int32 nEndPos )
1010 {
1011  sal_Int32 nMovePos = pUnoCursor->GetContentNode()->Len();
1012 
1013  if ((nEndPos >= 0) && (nEndPos < nMovePos))
1014  {
1015  nMovePos = nEndPos;
1016  }
1017 
1018  if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos))
1019  {
1020  nMovePos = nNextFrameIndex;
1021  }
1022 
1023  if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos))
1024  {
1025  nMovePos = nNextPortionIndex;
1026  }
1027 
1028  if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos))
1029  {
1030  nMovePos = nNextAttrIndex;
1031  }
1032 
1033  if ((nNextMarkIndex >= 0) && (nNextMarkIndex < nMovePos))
1034  {
1035  nMovePos = nNextMarkIndex;
1036  }
1037 
1038  if (nMovePos > nCurrentIndex)
1039  {
1040  pUnoCursor->GetPoint()->nContent = nMovePos;
1041  }
1042 }
1043 
1045  SwDoc const & rDoc,
1046  SwUnoCursor const & rUnoCursor,
1047  SwXRedlinePortion_ImplList& rRedArr )
1048 {
1049  const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable();
1050  const size_t nRedTableCount = rRedTable.size();
1051 
1052  if ( nRedTableCount <= 0 )
1053  return;
1054 
1055  const SwPosition* pStart = rUnoCursor.GetPoint();
1056  const SwNodeIndex nOwnNode = pStart->nNode;
1057 
1058  for(size_t nRed = 0; nRed < nRedTableCount; ++nRed)
1059  {
1060  const SwRangeRedline* pRedline = rRedTable[nRed];
1061  const SwPosition* pRedStart = pRedline->Start();
1062  const SwNodeIndex nRedNode = pRedStart->nNode;
1063  if ( nOwnNode == nRedNode )
1064  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1065  pRedline, true ) );
1066  if( pRedline->HasMark() && pRedline->End()->nNode == nOwnNode )
1067  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1068  pRedline, false ) );
1069  }
1070 }
1071 
1073  SwUnoCursor const & rUnoCursor,
1074  SwSoftPageBreakList& rBreakArr )
1075 {
1076  const SwTextNode *pTextNode =
1077  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
1078  if( pTextNode )
1079  pTextNode->fillSoftPageBreakList( rBreakArr );
1080 }
1081 
1082 static void lcl_ExportRedline(
1083  TextRangeList_t & rPortions,
1084  Reference<XText> const& xParent,
1085  const SwUnoCursor * const pUnoCursor,
1086  SwXRedlinePortion_ImplList& rRedlineArr,
1087  const sal_Int32 nIndex)
1088 {
1089 
1090  // We want this loop to iterate over all red lines in this
1091  // array. We will only insert the ones with index matches
1092  for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end();
1093  aIter != aEnd; )
1094  {
1095  SwXRedlinePortion_ImplSharedPtr pPtr = *aIter;
1096  sal_Int32 nRealIndex = pPtr->getRealIndex();
1097  // If there are elements before nIndex, remove them
1098  if ( nIndex > nRealIndex )
1099  aIter = rRedlineArr.erase(aIter);
1100  // If the elements match, and them to the list
1101  else if ( nIndex == nRealIndex )
1102  {
1103  rPortions.push_back( new SwXRedlinePortion(
1104  *pPtr->m_pRedline, pUnoCursor, xParent, pPtr->m_bStart));
1105  aIter = rRedlineArr.erase(aIter);
1106  }
1107  // If we've iterated past nIndex, exit the loop
1108  else
1109  break;
1110  }
1111 }
1112 
1114  TextRangeList_t & rPortions,
1115  Reference<XText> const & xParent,
1116  const SwUnoCursor * const pUnoCursor,
1117  SwXBookmarkPortion_ImplList& rBkmArr,
1118  SwXRedlinePortion_ImplList& rRedlineArr,
1119  SwSoftPageBreakList& rBreakArr,
1120  const sal_Int32 nIndex,
1121  const o3tl::sorted_vector<sal_Int32>& rFramePositions,
1122  bool bOnlyFrameBookmarkStarts)
1123 {
1124  if (!rBkmArr.empty())
1125  lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions,
1126  bOnlyFrameBookmarkStarts);
1127 
1128  if (bOnlyFrameBookmarkStarts)
1129  // Only exporting the start of some collapsed bookmarks: no export of
1130  // other arrays.
1131  return;
1132 
1133  if (!rRedlineArr.empty())
1134  lcl_ExportRedline(rPortions, xParent, pUnoCursor, rRedlineArr, nIndex);
1135 
1136  if (!rBreakArr.empty())
1137  lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCursor, rBreakArr, nIndex);
1138 }
1139 
1152  TextRangeList_t & rPortions,
1153  Reference<XText> const & xParent,
1154  const SwUnoCursor * const pUnoCursor,
1155  SwAnnotationStartPortion_ImplList& rAnnotationStartArr,
1156  const sal_Int32 nIndex,
1157  const o3tl::sorted_vector<sal_Int32>& rFramePositions,
1158  bool bOnlyFrame)
1159 {
1160  for ( SwAnnotationStartPortion_ImplList::iterator aIter = rAnnotationStartArr.begin(), aEnd = rAnnotationStartArr.end();
1161  aIter != aEnd; )
1162  {
1163  SwAnnotationStartPortion_ImplSharedPtr pPtr = *aIter;
1164  if ( nIndex > pPtr->getIndex() )
1165  {
1166  aIter = rAnnotationStartArr.erase(aIter);
1167  continue;
1168  }
1169  if ( pPtr->getIndex() > nIndex )
1170  {
1171  break;
1172  }
1173 
1174  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
1175  if (bFrameStart || !bOnlyFrame)
1176  {
1178  new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
1179  pPortion->SetTextField( pPtr->mxAnnotationField );
1180  rPortions.emplace_back(pPortion);
1181 
1182  aIter = rAnnotationStartArr.erase(aIter);
1183  }
1184  else
1185  ++aIter;
1186  }
1187 }
1188 
1190 static void lcl_ExtractFramePositions(FrameClientSortList_t& rFrames, sal_Int32 nCurrentIndex,
1191  o3tl::sorted_vector<sal_Int32>& rFramePositions)
1192 {
1193  for (const auto& rFrame : rFrames)
1194  {
1195  if (rFrame.nIndex < nCurrentIndex)
1196  continue;
1197 
1198  if (rFrame.nIndex > nCurrentIndex)
1199  break;
1200 
1201  const auto pFrame = static_cast<const SwFrameFormat*>(rFrame.pFrameClient->GetRegisteredIn());
1202  if (!pFrame)
1203  continue;
1204 
1205  auto& rFormat = *const_cast<SwFrameFormat*>(pFrame);
1206  const SwFormatAnchor& rAnchor = rFormat.GetAnchor();
1207  const SwPosition* pPosition = rAnchor.GetContentAnchor();
1208  if (!pPosition)
1209  continue;
1210 
1211  rFramePositions.insert(pPosition->nContent.GetIndex());
1212  }
1213 }
1214 
1221 static sal_Int32 lcl_ExportFrames(
1222  TextRangeList_t & rPortions,
1223  Reference<XText> const & i_xParent,
1224  SwUnoCursor const * const i_pUnoCursor,
1225  FrameClientSortList_t & i_rFrames,
1226  sal_Int32 const i_nCurrentIndex)
1227 {
1228  // Ignore frames which are not exported, as we are exporting a selection
1229  // and they are anchored before the start of the selection.
1230  while (!i_rFrames.empty() && i_rFrames.front().nIndex < i_nCurrentIndex)
1231  i_rFrames.pop_front();
1232 
1233  // find first Frame in (sorted) i_rFrames at current position
1234  while (!i_rFrames.empty() && (i_rFrames.front().nIndex == i_nCurrentIndex))
1235  // do not check for i_nEnd here; this is done implicitly by lcl_MoveCursor
1236  {
1237  auto pFrame = static_cast<SwFrameFormat*>(i_rFrames.front().pFrameClient->GetRegisteredIn());
1238  if (pFrame) // Frame could be disposed
1239  {
1240  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(i_pUnoCursor, i_xParent, *pFrame );
1241  rPortions.emplace_back(pPortion);
1242  }
1243  i_rFrames.pop_front();
1244  }
1245 
1246  return !i_rFrames.empty() ? i_rFrames.front().nIndex : -1;
1247 }
1248 
1249 static sal_Int32 lcl_GetNextIndex(
1250  SwXBookmarkPortion_ImplList const & rBkmArr,
1251  SwXRedlinePortion_ImplList const & rRedlineArr,
1252  SwSoftPageBreakList const & rBreakArr )
1253 {
1254  sal_Int32 nRet = -1;
1255  if(!rBkmArr.empty())
1256  {
1257  SwXBookmarkPortion_ImplSharedPtr pPtr = *rBkmArr.begin();
1258  nRet = pPtr->getIndex();
1259  }
1260  if(!rRedlineArr.empty())
1261  {
1262  SwXRedlinePortion_ImplSharedPtr pPtr = *rRedlineArr.begin();
1263  sal_Int32 nTmp = pPtr->getRealIndex();
1264  if(nRet < 0 || nTmp < nRet)
1265  nRet = nTmp;
1266  }
1267  if(!rBreakArr.empty())
1268  {
1269  if(nRet < 0 || *rBreakArr.begin() < nRet)
1270  nRet = *rBreakArr.begin();
1271  }
1272  return nRet;
1273 };
1274 
1276  TextRangeList_t & i_rPortions,
1277  uno::Reference< text::XText > const & i_xParentText,
1278  SwUnoCursor * const pUnoCursor,
1279  FrameClientSortList_t & i_rFrames,
1280  const sal_Int32 i_nStartPos,
1281  const sal_Int32 i_nEndPos )
1282 {
1283  if (!pUnoCursor)
1284  return;
1285 
1286  // set the start if a selection should be exported
1287  if ((i_nStartPos > 0) &&
1288  (pUnoCursor->Start()->nContent.GetIndex() != i_nStartPos))
1289  {
1290  pUnoCursor->DeleteMark();
1291  OSL_ENSURE(pUnoCursor->Start()->nNode.GetNode().GetTextNode() &&
1292  (i_nStartPos <= pUnoCursor->Start()->nNode.GetNode().GetTextNode()->
1293  GetText().getLength()), "Incorrect start position" );
1294  // ??? should this be i_nStartPos - current position ?
1295  pUnoCursor->Right(i_nStartPos);
1296  }
1297 
1298  SwDoc& rDoc = pUnoCursor->GetDoc();
1299 
1300  std::deque<sal_Int32> FieldMarks;
1301  lcl_FillFieldMarkArray(FieldMarks, *pUnoCursor, i_nStartPos);
1302 
1303  SwXBookmarkPortion_ImplList Bookmarks;
1304  lcl_FillBookmarkArray(rDoc, *pUnoCursor, Bookmarks);
1305 
1306  SwXRedlinePortion_ImplList Redlines;
1307  lcl_FillRedlineArray(rDoc, *pUnoCursor, Redlines);
1308 
1309  SwSoftPageBreakList SoftPageBreaks;
1310  lcl_FillSoftPageBreakArray(*pUnoCursor, SoftPageBreaks);
1311 
1312  SwAnnotationStartPortion_ImplList AnnotationStarts;
1313  lcl_FillAnnotationStartArray( rDoc, *pUnoCursor, AnnotationStarts );
1314 
1315  PortionStack_t PortionStack;
1316  PortionStack.push( PortionList_t(&i_rPortions, nullptr) );
1317 
1318  bool bAtEnd( false );
1319  while (!bAtEnd) // every iteration consumes at least current character!
1320  {
1321  if (pUnoCursor->HasMark())
1322  {
1323  pUnoCursor->Normalize(false);
1324  pUnoCursor->DeleteMark();
1325  }
1326 
1327  SwTextNode * const pTextNode = pUnoCursor->GetNode().GetTextNode();
1328  if (!pTextNode)
1329  {
1330  OSL_FAIL("lcl_CreatePortions: no TextNode - what now ?");
1331  return;
1332  }
1333 
1334  SwpHints * const pHints = pTextNode->GetpSwpHints();
1335  const sal_Int32 nCurrentIndex =
1336  pUnoCursor->GetPoint()->nContent.GetIndex();
1337  // this contains the portion which consumes the character in the
1338  // text at nCurrentIndex; i.e. it must be set _once_ per iteration
1339  uno::Reference< XTextRange > xRef;
1340 
1341  SwUnoCursorHelper::SelectPam(*pUnoCursor, true); // set mark
1342 
1343  // First remember the frame positions.
1344  o3tl::sorted_vector<sal_Int32> aFramePositions;
1345  lcl_ExtractFramePositions(i_rFrames, nCurrentIndex, aFramePositions);
1346 
1347  // Then export start of collapsed bookmarks which "cover" at-char
1348  // anchored frames.
1349  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1350  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true );
1351 
1353  *PortionStack.top().first,
1354  i_xParentText,
1355  pUnoCursor,
1356  AnnotationStarts,
1357  nCurrentIndex,
1358  aFramePositions,
1359  /*bOnlyFrame=*/true );
1360 
1361  const sal_Int32 nFirstFrameIndex =
1362  lcl_ExportFrames( *PortionStack.top().first,
1363  i_xParentText, pUnoCursor, i_rFrames, nCurrentIndex);
1364 
1365  // Export ends of the previously started collapsed bookmarks + all
1366  // other bookmarks, redlines, etc.
1367  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1368  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false );
1369 
1371  *PortionStack.top().first,
1372  i_xParentText,
1373  pUnoCursor,
1374  AnnotationStarts,
1375  nCurrentIndex,
1376  aFramePositions,
1377  /*bOnlyFrame=*/false );
1378 
1379  bool bCursorMoved( false );
1380  sal_Int32 nNextAttrIndex = -1;
1381  // #111716# the cursor must not move right at the
1382  // end position of a selection!
1383  bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos))
1384  || (nCurrentIndex >= pTextNode->Len());
1385  if (pHints)
1386  {
1387  // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor
1388  xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCursor,
1389  pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd,
1390  bCursorMoved, nNextAttrIndex);
1391  if (PortionStack.empty())
1392  {
1393  OSL_FAIL("CreatePortions: stack underflow");
1394  return;
1395  }
1396  }
1397 
1398  if (!xRef.is() && !bCursorMoved)
1399  {
1400  if (!bAtEnd &&
1401  !FieldMarks.empty() && (FieldMarks.front() == nCurrentIndex))
1402  {
1403  // moves cursor
1404  xRef = lcl_ExportFieldMark(i_xParentText, pUnoCursor, pTextNode);
1405  FieldMarks.pop_front();
1406  }
1407  }
1408  else
1409  {
1410  OSL_ENSURE(FieldMarks.empty() ||
1411  (FieldMarks.front() != nCurrentIndex),
1412  "fieldmark and hint with CH_TXTATR at same pos?");
1413  }
1414 
1415  if (!bAtEnd && !xRef.is() && !bCursorMoved)
1416  {
1417  const sal_Int32 nNextPortionIndex =
1418  lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks);
1419 
1420  sal_Int32 nNextMarkIndex = ( !FieldMarks.empty() ? FieldMarks.front() : -1 );
1421  if ( !AnnotationStarts.empty()
1422  && ( nNextMarkIndex == -1
1423  || (*AnnotationStarts.begin())->getIndex() < nNextMarkIndex ) )
1424  {
1425  nNextMarkIndex = (*AnnotationStarts.begin())->getIndex();
1426  }
1427 
1429  pUnoCursor,
1430  nCurrentIndex,
1431  nFirstFrameIndex,
1432  nNextPortionIndex,
1433  nNextAttrIndex,
1434  nNextMarkIndex,
1435  i_nEndPos );
1436 
1437  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1438  }
1439  else if (bAtEnd && !xRef.is() && !pTextNode->Len())
1440  {
1441  // special case: for an empty paragraph, we better put out a
1442  // text portion because there may be a hyperlink attribute
1443  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1444  }
1445 
1446  if (xRef.is())
1447  {
1448  PortionStack.top().first->push_back(xRef);
1449  }
1450  }
1451 
1452  OSL_ENSURE((PortionStack.size() == 1) && !PortionStack.top().second,
1453  "CreatePortions: stack error" );
1454 }
1455 
1456 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::deque< css::uno::Reference< css::text::XTextRange > > TextRangeList_t
Definition: unometa.hxx:42
static css::uno::Reference< css::rdf::XMetadatable > CreateXMeta(::sw::Meta &rMeta, css::uno::Reference< css::text::XText > const &xParentText=nullptr, std::unique_ptr< TextRangeList_t const > &&pPortions=std::unique_ptr< TextRangeList_t const >())
std::shared_ptr< SwUnoCursor > CreateUnoCursor(const SwPosition &rPos, bool bTableCursor=false)
Definition: doc.cxx:1779
virtual sal_Int32 Len() const
Definition: node.cxx:1245
void DeleteMark()
Definition: pam.hxx:177
SwNode & GetNode(bool bPoint=true) const
Definition: pam.hxx:223
virtual ::sw::mark::IFieldmark * getFieldmarkAt(const SwPosition &rPos) const =0
get Fieldmark for CH_TXT_ATR_FIELDSTART/CH_TXT_ATR_FIELDEND at rPos
Marks a position in the document model.
Definition: pam.hxx:35
static Reference< XTextRange > lcl_CreateTOXMarkPortion(Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwTextAttr &rAttr, const bool bEnd)
virtual css::uno::Any SAL_CALL nextElement() override
const SwField * GetField() const
Definition: fmtfld.hxx:110
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
const OUString & GetText() const
Definition: ndtxt.hxx:210
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:218
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_META(48)
SwNodeIndex nNode
Definition: pam.hxx:37
virtual sal_Int32 getBookmarksCount() const =0
returns the number of IBookmarks.
wrapper iterator: wraps iterator of implementation while hiding MarkBase class; only IMark instances ...
std::deque< FrameClientSortListEntry > FrameClientSortList_t
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:48
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:276
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:478
virtual sal_Bool SAL_CALL hasMoreElements() override
const SwPosition * GetMark() const
Definition: pam.hxx:209
Provides access to the marks of a document.
Definition: doc.hxx:187
virtual SwPosition & GetMarkStart() const override
Definition: bookmrk.hxx:59
constexpr TypedWhichId< SwFormatFlyCnt > RES_TXTATR_FLYCNT(57)
virtual ~SwXTextPortionEnumeration() override
std::shared_ptr< SwXRedlinePortion_Impl > SwXRedlinePortion_ImplSharedPtr
const_iterator find(const Value &x) const
SwNode & GetNode() const
Definition: ndindex.hxx:119
geometry::RealPoint2D maPosition
SwTextAttr * GetSortedByEnd(size_t nPos) const
Definition: ndhints.hxx:158
IDocumentMarkAccess * getIDocumentMarkAccess()
Definition: docbm.cxx:1794
sal_uInt16 Which() const
Definition: txatbase.hxx:114
static css::uno::Reference< css::text::XTextField > CreateXTextField(SwDoc *pDoc, SwFormatField const *pFormat, SwServiceType nServiceId=SwServiceType::Invalid)
Definition: unofield.cxx:1219
virtual sal_Int32 getAnnotationMarksCount() const =0
sal_Int32 GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:157
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(59)
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:176
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(156)
const SwIndex * GetNext() const
Definition: index.hxx:98
size_type size() const
Definition: docary.hxx:266
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
sal_uInt16 sal_Unicode
SwIndex nContent
Definition: pam.hxx:38
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
size_t pos
A wrapper around SfxPoolItem to store the start position of (usually) a text portion, with an optional end.
Definition: txatbase.hxx:41
static void lcl_FillRedlineArray(SwDoc const &rDoc, SwUnoCursor const &rUnoCursor, SwXRedlinePortion_ImplList &rRedArr)
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType)
Is the frame format a text box?
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
sal_Int32 GetStart() const
Definition: txatbase.hxx:86
virtual const_iterator_t findFirstAnnotationStartsAfter(const SwPosition &rPos) const =0
Finds the first mark that is starting after.
static css::uno::Reference< css::text::XTextContent > CreateXFieldmark(SwDoc &rDoc,::sw::mark::IMark *pMark, bool isReplacementObject=false)
Definition: unobkm.cxx:688
constexpr TypedWhichId< SwFormatRuby > RES_TXTATR_CJK_RUBY(53)
constexpr TypedWhichId< SwFormatCharFormat > RES_TXTATR_CHARFMT(52)
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:195
constexpr TypedWhichId< SwFormatAutoFormat > RES_TXTATR_AUTOFMT(50)
virtual sal_Bool SAL_CALL supportsService(const OUString &ServiceName) override
constexpr TypedWhichId< SwFormatFootnote > RES_TXTATR_FTN(58)
void Normalize(bool bPointFirst=true)
Normalizes PaM, i.e.
Definition: pam.cxx:541
static Reference< XTextRange > lcl_CreateRefMarkPortion(Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, const SwTextAttr &rAttr, const bool bEnd)
constexpr TypedWhichId< SwFormatINetFormat > RES_TXTATR_INETFMT(51)
void SelectPam(SwPaM &rPam, const bool bExpand)
Definition: unoobj.cxx:111
static void lcl_ExtractFramePositions(FrameClientSortList_t &rFrames, sal_Int32 nCurrentIndex, o3tl::sorted_vector< sal_Int32 > &rFramePositions)
Fills character positions from rFrames into rFramePositions.
DocumentType eType
virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override
PaM is Point and Mark: a selection of the document model.
Definition: pam.hxx:136
static css::uno::Reference< css::text::XTextContent > CreateXBookmark(SwDoc &rDoc,::sw::mark::IMark *pBookmark)
Definition: unobkm.cxx:160
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
Style of a layout element.
Definition: frmfmt.hxx:58
static void lcl_ExportBookmark(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXBookmarkPortion_ImplList &rBkmArr, const sal_Int32 nIndex, const o3tl::sorted_vector< sal_Int32 > &rFramePositions, bool bOnlyFrameStarts)
Exports all bookmarks from rBkmArr into rPortions that have the same start or end position as nIndex...
size_t Count() const
Definition: ndhints.hxx:142
SwTextAttr * Get(size_t nPos) const
Definition: ndhints.hxx:144
static void lcl_ExportRedline(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXRedlinePortion_ImplList &rRedlineArr, const sal_Int32 nIndex)
virtual OUString SAL_CALL getImplementationName() override
::sw::mark::IMark * GetAnnotationMark() const
Definition: atrfld.cxx:716
const SwPosition * GetPoint() const
Definition: pam.hxx:207
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
Count
void Exchange()
Definition: pam.cxx:492
static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId()
static uno::Reference< text::XTextRange > lcl_ExportFieldMark(uno::Reference< text::XText > const &i_xParentText, SwUnoCursor *const pUnoCursor, const SwTextNode *const pTextNode)
FlyAnchors.
Definition: fmtanchr.hxx:34
void CollectFrameAtNode(const SwNodeIndex &rIdx, FrameClientSortList_t &rFrames, const bool bAtCharAnchoredObjs)
Definition: unoobj2.cxx:137
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
const Any & any
Marks a character position inside a document model node.
Definition: index.hxx:33
#define CH_TXT_ATR_FIELDSTART
Definition: hintids.hxx:178
unsigned char sal_Bool
std::pair< TextRangeList_t *const, SwTextAttr const *const > PortionList_t
Definition: unoportenum.cxx:71
static css::uno::Reference< css::text::XDocumentIndexMark > CreateXDocumentIndexMark(SwDoc &rDoc, SwTOXMark *pMark, TOXTypes eType=TOX_INDEX)
Definition: unoidx.cxx:1623
static void lcl_InsertRubyPortion(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, const SwTextAttr &rAttr, const bool bEnd)
virtual const_iterator_t getAnnotationMarksBegin() const =0
Marks a node in the document model.
Definition: ndindex.hxx:31
sal_Int32 indexOfAny(std::u16string_view rIn, sal_Unicode const *const pChars, sal_Int32 const nPos)
const_iterator end() const
bool empty() const
std::stack< PortionList_t > PortionStack_t
Definition: unoportenum.cxx:72
static css::uno::Reference< css::text::XTextContent > CreateXReferenceMark(SwDoc &rDoc, SwFormatRefMark *pMarkFormat)
Definition: unorefmk.cxx:129
const SwFormatFootnote & GetFootnote() const
Definition: txatbase.hxx:204
static sal_Int32 lcl_GetNextIndex(SwXBookmarkPortion_ImplList const &rBkmArr, SwXRedlinePortion_ImplList const &rRedlineArr, SwSoftPageBreakList const &rBreakArr)
const SwPosition * Start() const
Definition: pam.hxx:212
BkmType
Definition: unoportenum.cxx:83
const_iterator begin() const
static void lcl_FillFieldMarkArray(std::deque< sal_Int32 > &rFieldMarks, SwUnoCursor const &rUnoCursor, const sal_Int32 i_nStartPos)
void fillSoftPageBreakList(SwSoftPageBreakList &rBreak) const
SwTextNode is a paragraph in the document model.
Definition: ndtxt.hxx:79
OUString ExpandField(bool bCached, SwRootFrame const *pLayout) const
expand the field.
Definition: fldbas.cxx:465
IDocumentRedlineAccess const & getIDocumentRedlineAccess() const
Definition: doc.cxx:335
SwXTextPortionEnumeration(SwPaM &rParaCursor, css::uno::Reference< css::text::XText > const &xParent, const sal_Int32 nStart, const sal_Int32 nEnd)
static void lcl_FillSoftPageBreakArray(SwUnoCursor const &rUnoCursor, SwSoftPageBreakList &rBreakArr)
An SwTextAttr container, stores all directly formatted text portions for a text node.
Definition: ndhints.hxx:67
static void lcl_ExportAnnotationStarts(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwAnnotationStartPortion_ImplList &rAnnotationStartArr, const sal_Int32 nIndex, const o3tl::sorted_vector< sal_Int32 > &rFramePositions, bool bOnlyFrame)
Exports all start annotation marks from rAnnotationStartArr into rPortions that have the same start p...
sw::UnoCursorPointer m_pUnoCursor
Definition: unoport.hxx:241
std::multiset< SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct > SwXRedlinePortion_ImplList
void reset(std::shared_ptr< SwUnoCursor > pNew)
Definition: unocrsr.hxx:157
bool Right(sal_uInt16 nCnt)
Definition: swcrsr.hxx:173
sal_Int32 GetIndex() const
Definition: index.hxx:91
virtual sal_Int64 SAL_CALL getSomething(const css::uno::Sequence< sal_Int8 > &aIdentifier) override
const SwPosition * End() const
Definition: pam.hxx:217
const sal_Int32 * End() const
Definition: txatbase.hxx:152
QPRO_FUNC_TYPE nType
static Reference< XTextRange > lcl_ExportHints(PortionStack_t &rPortionStack, const Reference< XText > &xParent, SwUnoCursor *const pUnoCursor, SwpHints const *const pHints, const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos, const sal_Int32 nCurrentIndex, const bool bRightMoveForbidden, bool &o_rbCursorMoved, sal_Int32 &o_rNextAttrPosition)
constexpr TypedWhichId< SwTOXMark > RES_TXTATR_TOXMARK(47)
virtual const SwPosition & GetMarkEnd() const =0
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:180
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:163
uno::Reference< ucb::XContent > xContent
#define SAL_WARN(area, stream)
SwFrameFormat * GetFrameFormat() const
Definition: fmtflcnt.hxx:45
static void lcl_MoveCursor(SwUnoCursor *const pUnoCursor, const sal_Int32 nCurrentIndex, const sal_Int32 nNextFrameIndex, const sal_Int32 nNextPortionIndex, const sal_Int32 nNextAttrIndex, const sal_Int32 nNextMarkIndex, const sal_Int32 nEndPos)
SwDoc & GetDoc() const
Definition: pam.hxx:243
const SwIndex * GetFirstIndex() const
Definition: index.hxx:125
virtual const SwPosition & GetMarkStart() const =0
static void lcl_ExportBkmAndRedline(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXBookmarkPortion_ImplList &rBkmArr, SwXRedlinePortion_ImplList &rRedlineArr, SwSoftPageBreakList &rBreakArr, const sal_Int32 nIndex, const o3tl::sorted_vector< sal_Int32 > &rFramePositions, bool bOnlyFrameBookmarkStarts)
constexpr TypedWhichId< SwFormatRefMark > RES_TXTATR_REFMARK(RES_TXTATR_WITHEND_BEGIN)
static sal_Int32 lcl_ExportFrames(TextRangeList_t &rPortions, Reference< XText > const &i_xParent, SwUnoCursor const *const i_pUnoCursor, FrameClientSortList_t &i_rFrames, sal_Int32 const i_nCurrentIndex)
Exports at-char anchored frames.
TextRangeList_t m_Portions
Definition: unoport.hxx:240
virtual const SwRedlineTable & GetRedlineTable() const =0
std::pair< const_iterator, bool > insert(Value &&x)
const css::uno::Sequence< sal_Int8 > & getSeq() const
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:179
virtual bool IsExpanded() const =0
static uno::Reference< text::XTextRange > lcl_CreateMetaPortion(uno::Reference< text::XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwTextAttr &rAttr, std::unique_ptr< TextRangeList_t const > &&pPortions)
const SwFormatField * GetAnnotationFormatField() const
static void lcl_ExportSoftPageBreak(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwSoftPageBreakList &rBreakArr, const sal_Int32 nIndex)
SwTextNode * GetTextNode()
Inline methods from Node.hxx.
Definition: ndtxt.hxx:845
size_type erase(const Value &x)
static css::uno::Reference< css::text::XFootnote > GetObject(SwDoc &rDoc, const SwFormatFootnote &rFormat)
Definition: unocoll.cxx:1816
static void lcl_CreatePortions(TextRangeList_t &i_rPortions, uno::Reference< text::XText > const &i_xParentText, SwUnoCursor *pUnoCursor, FrameClientSortList_t &i_rFrames, const sal_Int32 i_nStartPos, const sal_Int32 i_nEndPos)
const SwFormatFlyCnt & GetFlyCnt() const
Definition: txatbase.hxx:210