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 comphelper::UnoIdInit theSwXTextPortionEnumerationUnoTunnelId;
284  return theSwXTextPortionEnumerationUnoTunnelId.getSeq();
285 }
286 
288  const uno::Sequence< sal_Int8 >& rId )
289 {
290  return comphelper::getSomethingImpl(rId, this);
291 }
292 
294 {
295  return "SwXTextPortionEnumeration";
296 }
297 
298 sal_Bool
299 SwXTextPortionEnumeration::supportsService(const OUString& rServiceName)
300 {
301  return cppu::supportsService(this, rServiceName);
302 }
303 
305 {
306  return { "com.sun.star.text.TextPortionEnumeration" };
307 }
308 
310  SwPaM& rParaCursor,
311  uno::Reference< XText > const & xParentText,
312  const sal_Int32 nStart,
313  const sal_Int32 nEnd )
314 {
315  m_pUnoCursor = rParaCursor.GetDoc().CreateUnoCursor(*rParaCursor.GetPoint());
316 
317  OSL_ENSURE(nEnd == -1 || (nStart <= nEnd &&
318  nEnd <= m_pUnoCursor->Start()->nNode.GetNode().GetTextNode()->GetText().getLength()),
319  "start or end value invalid!");
320 
321  // find all frames, graphics and OLEs that are bound AT character in para
322  FrameClientSortList_t frames;
323  ::CollectFrameAtNode(m_pUnoCursor->GetPoint()->nNode, frames, true);
324  lcl_CreatePortions(m_Portions, xParentText, &*m_pUnoCursor, frames, nStart, nEnd);
325 }
326 
328  SwPaM& rParaCursor,
329  TextRangeList_t const & rPortions )
330  : m_Portions( rPortions )
331 {
332  m_pUnoCursor = rParaCursor.GetDoc().CreateUnoCursor(*rParaCursor.GetPoint());
333 }
334 
336 {
337  SolarMutexGuard aGuard;
338  m_pUnoCursor.reset(nullptr);
339 }
340 
342 {
343  SolarMutexGuard aGuard;
344 
345  return !m_Portions.empty();
346 }
347 
349 {
350  SolarMutexGuard aGuard;
351 
352  if (m_Portions.empty())
353  throw container::NoSuchElementException();
354 
355  Any any;
356  any <<= m_Portions.front();
357  m_Portions.pop_front();
358  return any;
359 }
360 
361 static void
362 lcl_FillFieldMarkArray(std::deque<sal_Int32> & rFieldMarks, SwUnoCursor const & rUnoCursor,
363  const sal_Int32 i_nStartPos)
364 {
365  const SwTextNode * const pTextNode =
366  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
367  if (!pTextNode) return;
368 
369  const sal_Unicode fld[] = {
371  sal_Int32 pos = std::max(static_cast<sal_Int32>(0), i_nStartPos);
372  while ((pos = ::comphelper::string::indexOfAny(pTextNode->GetText(), fld, pos)) != -1)
373  {
374  rFieldMarks.push_back(pos);
375  ++pos;
376  }
377 }
378 
379 static uno::Reference<text::XTextRange>
381  uno::Reference< text::XText > const & i_xParentText,
382  SwUnoCursor * const pUnoCursor,
383  const SwTextNode * const pTextNode )
384 {
385  uno::Reference<text::XTextRange> xRef;
386  SwDoc& rDoc = pUnoCursor->GetDoc();
387  // maybe it's a good idea to add a special hint to the hints array and rely on the hint segmentation...
388  const sal_Int32 start = pUnoCursor->Start()->nContent.GetIndex();
389  OSL_ENSURE(pUnoCursor->End()->nContent.GetIndex() == start,
390  "hmm --- why is this different");
391 
392  pUnoCursor->Right(1);
393  if ( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
394  {
395  OSL_FAIL("cannot move cursor?");
396  return nullptr;
397  }
398 
399  const sal_Unicode Char = pTextNode->GetText()[start];
400  if (CH_TXT_ATR_FIELDSTART == Char)
401  {
402  ::sw::mark::IFieldmark* pFieldmark = nullptr;
403  pFieldmark = rDoc.getIDocumentMarkAccess()->
404  getFieldmarkAt(*pUnoCursor->GetMark());
406  pUnoCursor, i_xParentText, PORTION_FIELD_START);
407  xRef = pPortion;
408  if (pFieldmark)
409  {
410  pPortion->SetBookmark(
411  SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark));
412  }
413  }
414  else if (CH_TXT_ATR_FIELDSEP == Char)
415  {
416  // TODO how to get the field?
417  xRef = new SwXTextPortion(
418  pUnoCursor, i_xParentText, PORTION_FIELD_SEP);
419  }
420  else if (CH_TXT_ATR_FIELDEND == Char)
421  {
422  ::sw::mark::IFieldmark* pFieldmark = nullptr;
423  pFieldmark = rDoc.getIDocumentMarkAccess()->
424  getFieldmarkAt(*pUnoCursor->GetMark());
426  pUnoCursor, i_xParentText, PORTION_FIELD_END);
427  xRef = pPortion;
428  if (pFieldmark)
429  {
430  pPortion->SetBookmark(
431  SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark));
432  }
433  }
434  else if (CH_TXT_ATR_FORMELEMENT == Char)
435  {
436  ::sw::mark::IFieldmark* pFieldmark =
437  rDoc.getIDocumentMarkAccess()->getFieldmarkAt(*pUnoCursor->GetMark());
439  pUnoCursor, i_xParentText, PORTION_FIELD_START_END);
440  xRef = pPortion;
441  if (pFieldmark)
442  {
443  pPortion->SetBookmark(
444  SwXFieldmark::CreateXFieldmark(rDoc, pFieldmark));
445  }
446  }
447  else
448  {
449  OSL_FAIL("no fieldmark found?");
450  }
451  return xRef;
452 }
453 
454 static Reference<XTextRange>
456  Reference<XText> const& xParent,
457  const SwUnoCursor * const pUnoCursor,
458  const SwTextAttr & rAttr, const bool bEnd)
459 {
460  SwDoc& rDoc = pUnoCursor->GetDoc();
461  SwFormatRefMark& rRefMark = const_cast<SwFormatRefMark&>(
462  static_cast<const SwFormatRefMark&>(rAttr.GetAttr()));
463  Reference<XTextContent> xContent;
464  if (!xContent.is())
465  {
466  xContent = SwXReferenceMark::CreateXReferenceMark(rDoc, &rRefMark);
467  }
468 
470  if (!bEnd)
471  {
472  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_START);
473  pPortion->SetRefMark(xContent);
474  pPortion->SetCollapsed(rAttr.End() == nullptr);
475  }
476  else
477  {
478  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_END);
479  pPortion->SetRefMark(xContent);
480  }
481  return pPortion;
482 }
483 
484 static void
486  TextRangeList_t & rPortions,
487  Reference<XText> const& xParent,
488  const SwUnoCursor * const pUnoCursor,
489  const SwTextAttr & rAttr, const bool bEnd)
490 {
491  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(pUnoCursor,
492  static_txtattr_cast<const SwTextRuby&>(rAttr), xParent, bEnd);
493  rPortions.emplace_back(pPortion);
494  pPortion->SetCollapsed(rAttr.End() == nullptr);
495 }
496 
497 static Reference<XTextRange>
499  Reference<XText> const& xParent,
500  const SwUnoCursor * const pUnoCursor,
501  SwTextAttr & rAttr, const bool bEnd)
502 {
503  SwDoc& rDoc = pUnoCursor->GetDoc();
504  SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr());
505 
506  const Reference<XTextContent> xContent =
508 
510  if (!bEnd)
511  {
512  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_START);
513  pPortion->SetTOXMark(xContent);
514  pPortion->SetCollapsed(rAttr.GetEnd() == nullptr);
515  }
516  else
517  {
518  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_END);
519  pPortion->SetTOXMark(xContent);
520  }
521  return pPortion;
522 }
523 
524 static uno::Reference<text::XTextRange>
526  uno::Reference<text::XText> const& xParent,
527  const SwUnoCursor * const pUnoCursor,
528  SwTextAttr & rAttr, std::unique_ptr<TextRangeList_t const> && pPortions)
529 {
530  const uno::Reference<rdf::XMetadatable> xMeta( SwXMeta::CreateXMeta(
531  *static_cast<SwFormatMeta &>(rAttr.GetAttr()).GetMeta(),
532  xParent, std::move(pPortions)));
534  if (RES_TXTATR_META == rAttr.Which())
535  {
536  const uno::Reference<text::XTextContent> xContent(xMeta,
537  uno::UNO_QUERY);
538  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_META);
539  pPortion->SetMeta(xContent);
540  }
541  else
542  {
543  const uno::Reference<text::XTextField> xField(xMeta, uno::UNO_QUERY);
544  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_FIELD);
545  pPortion->SetTextField(xField);
546  }
547  return pPortion;
548 }
549 
564 static void lcl_ExportBookmark(
565  TextRangeList_t & rPortions,
566  Reference<XText> const& xParent,
567  const SwUnoCursor * const pUnoCursor,
568  SwXBookmarkPortion_ImplList& rBkmArr,
569  const sal_Int32 nIndex,
570  const o3tl::sorted_vector<sal_Int32>& rFramePositions,
571  bool bOnlyFrameStarts)
572 {
573  for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; )
574  {
575  const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter;
576  if ( nIndex > pPtr->getIndex() )
577  {
578  if (bOnlyFrameStarts)
579  ++aIter;
580  else
581  aIter = rBkmArr.erase(aIter);
582  continue;
583  }
584  if ( nIndex < pPtr->getIndex() )
585  break;
586 
587  if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) ||
588  (BkmType::StartEnd == pPtr->nBkmType))
589  {
590  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
591  bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts;
592  if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts)
593  {
594  // At this we create a text portion, due to one of these
595  // reasons:
596  // - this is the real start of a non-collapsed bookmark
597  // - this is the real position of a collapsed bookmark
598  // - this is the start or end (depending on bOnlyFrameStarts)
599  // of a collapsed bookmark at the same position as an at-char
600  // anchored frame
602  new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START);
603  rPortions.emplace_back(pPortion);
604  pPortion->SetBookmark(pPtr->xBookmark);
605  pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart );
606  }
607  }
608  else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts)
609  {
611  new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END);
612  rPortions.emplace_back(pPortion);
613  pPortion->SetBookmark(pPtr->xBookmark);
614  }
615 
616  // next bookmark
617  if (bOnlyFrameStarts)
618  ++aIter;
619  else
620  aIter = rBkmArr.erase(aIter);
621  }
622 }
623 
625  TextRangeList_t & rPortions,
626  Reference<XText> const& xParent,
627  const SwUnoCursor * const pUnoCursor,
628  SwSoftPageBreakList& rBreakArr,
629  const sal_Int32 nIndex)
630 {
631  for ( auto aIter = rBreakArr.begin(); aIter != rBreakArr.end(); )
632  {
633  if ( nIndex > *aIter )
634  {
635  aIter = rBreakArr.erase(aIter);
636  continue;
637  }
638  if ( nIndex < *aIter )
639  break;
640 
641  rPortions.push_back(
642  new SwXTextPortion(pUnoCursor, xParent, PORTION_SOFT_PAGEBREAK) );
643  aIter = rBreakArr.erase(aIter);
644  }
645 }
646 
647 namespace {
648 
649 struct SwXRedlinePortion_Impl
650 {
651  const SwRangeRedline* m_pRedline;
652  const bool m_bStart;
653 
654  SwXRedlinePortion_Impl ( const SwRangeRedline* pRed, const bool bIsStart )
655  : m_pRedline(pRed)
656  , m_bStart(bIsStart)
657  {
658  }
659 
660  sal_Int32 getRealIndex () const
661  {
662  return m_bStart ? m_pRedline->Start()->nContent.GetIndex()
663  : m_pRedline->End() ->nContent.GetIndex();
664  }
665 };
666 
667 }
668 
669 typedef std::shared_ptr < SwXRedlinePortion_Impl >
671 
672 namespace {
673 
674 struct RedlineCompareStruct
675 {
676  static const SwPosition& getPosition ( const SwXRedlinePortion_ImplSharedPtr &r )
677  {
678  return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End());
679  }
680 
681  bool operator () ( const SwXRedlinePortion_ImplSharedPtr &r1,
682  const SwXRedlinePortion_ImplSharedPtr &r2 ) const
683  {
684  return getPosition ( r1 ) < getPosition ( r2 );
685  }
686 };
687 
688 }
689 
690 typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct >
692 
693 static Reference<XTextRange>
695  PortionStack_t & rPortionStack,
696  const Reference<XText> & xParent,
697  SwUnoCursor * const pUnoCursor,
698  SwpHints const * const pHints,
699  const sal_Int32 i_nStartPos,
700  const sal_Int32 i_nEndPos,
701  const sal_Int32 nCurrentIndex,
702  const bool bRightMoveForbidden,
703  bool & o_rbCursorMoved,
704  sal_Int32 & o_rNextAttrPosition)
705 {
706  // if the attribute has a dummy character, then xRef is set (except META)
707  // otherwise, the portion for the attribute is inserted into rPortions!
708  Reference<XTextRange> xRef;
709  SwDoc& rDoc = pUnoCursor->GetDoc();
710  //search for special text attributes - first some ends
711  size_t nEndIndex = 0;
712  sal_Int32 nNextEnd = 0;
713  while(nEndIndex < pHints->Count() &&
714  (!pHints->GetSortedByEnd(nEndIndex)->GetEnd() ||
715  nCurrentIndex >= (nNextEnd = (*pHints->GetSortedByEnd(nEndIndex)->GetEnd()))))
716  {
717  if(pHints->GetSortedByEnd(nEndIndex)->GetEnd())
718  {
719  SwTextAttr * const pAttr = pHints->GetSortedByEnd(nEndIndex);
720  if (nNextEnd == nCurrentIndex)
721  {
722  const sal_uInt16 nWhich( pAttr->Which() );
723  switch (nWhich)
724  {
725  case RES_TXTATR_TOXMARK:
726  {
727  Reference<XTextRange> xTmp = lcl_CreateTOXMarkPortion(
728  xParent, pUnoCursor, *pAttr, true);
729  rPortionStack.top().first->push_back(xTmp);
730  }
731  break;
732  case RES_TXTATR_REFMARK:
733  {
734  Reference<XTextRange> xTmp = lcl_CreateRefMarkPortion(
735  xParent, pUnoCursor, *pAttr, true);
736  rPortionStack.top().first->push_back(xTmp);
737  }
738  break;
739  case RES_TXTATR_CJK_RUBY:
740  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
741  if( *pAttr->GetEnd() == pAttr->GetStart())
742  {
743  lcl_InsertRubyPortion( *rPortionStack.top().first,
744  xParent, pUnoCursor, *pAttr, false);
745  }
746  lcl_InsertRubyPortion( *rPortionStack.top().first,
747  xParent, pUnoCursor, *pAttr, true);
748  break;
749  case RES_TXTATR_META:
751  {
752  OSL_ENSURE(pAttr->GetStart() != *pAttr->GetEnd(),
753  "empty meta?");
754  if ((i_nStartPos > 0) &&
755  (pAttr->GetStart() < i_nStartPos))
756  {
757  // force skip pAttr and rest of attribute ends
758  // at nCurrentIndex
759  // because they are not contained in the meta pAttr
760  // and the meta pAttr itself is outside selection!
761  // (necessary for SwXMeta::createEnumeration)
762  if (pAttr->GetStart() + 1 == i_nStartPos)
763  {
764  nEndIndex = pHints->Count() - 1;
765  }
766  break;
767  }
768  PortionList_t Top = rPortionStack.top();
769  if (Top.second != pAttr)
770  {
771  OSL_FAIL("ExportHints: stack error" );
772  }
773  else
774  {
775  std::unique_ptr<const TextRangeList_t>
776  pCurrentPortions(Top.first);
777  rPortionStack.pop();
778  const uno::Reference<text::XTextRange> xPortion(
779  lcl_CreateMetaPortion(xParent, pUnoCursor,
780  *pAttr, std::move(pCurrentPortions)));
781  rPortionStack.top().first->push_back(xPortion);
782  }
783  }
784  break;
785  }
786  }
787  }
788  nEndIndex++;
789  }
790 
791  // then some starts
792  size_t nStartIndex = 0;
793  sal_Int32 nNextStart = 0;
794  while(nStartIndex < pHints->Count() &&
795  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
796  {
797  SwTextAttr * const pAttr = pHints->Get(nStartIndex);
798  sal_uInt16 nAttrWhich = pAttr->Which();
799  if (nNextStart == nCurrentIndex)
800  {
801  switch( nAttrWhich )
802  {
803  case RES_TXTATR_FIELD:
804  if(!bRightMoveForbidden)
805  {
806  pUnoCursor->Right(1);
807  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
808  break;
810  new SwXTextPortion(
811  pUnoCursor, xParent, PORTION_FIELD);
812  xRef = pPortion;
813  Reference<XTextField> const xField =
815  &pAttr->GetFormatField());
816  pPortion->SetTextField(xField);
817  }
818  break;
819 
821  if(!bRightMoveForbidden)
822  {
823  pUnoCursor->Right(1);
824  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
825  break;
826 
827  const SwTextAnnotationField* pTextAnnotationField = dynamic_cast<const SwTextAnnotationField*>( pAttr );
828  ::sw::mark::IMark* pAnnotationMark = pTextAnnotationField ? pTextAnnotationField->GetAnnotationMark() : nullptr;
829  if ( pAnnotationMark != nullptr )
830  {
831  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION_END );
832  pPortion->SetBookmark(SwXBookmark::CreateXBookmark(
833  rDoc, pAnnotationMark));
834  xRef = pPortion;
835  }
836  else
837  {
838  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
839  Reference<XTextField> xField =
841  &pAttr->GetFormatField());
842  pPortion->SetTextField(xField);
843  xRef = pPortion;
844  }
845  }
846  break;
847 
849  if(!bRightMoveForbidden)
850  {
851 
852  pUnoCursor->Right(
853  pAttr->GetFormatField().GetField()->ExpandField(true, nullptr).getLength() + 2 );
854  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
855  break;
857  new SwXTextPortion( pUnoCursor, xParent, PORTION_FIELD);
858  xRef = pPortion;
859  Reference<XTextField> xField =
861  &pAttr->GetFormatField());
862  pPortion->SetTextField(xField);
863  }
864  break;
865 
866  case RES_TXTATR_FLYCNT:
867  if(!bRightMoveForbidden)
868  {
869  pUnoCursor->Right(1);
870  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
871  break; // Robust #i81708# content in covered cells
872 
873  // Do not expose inline anchored textboxes.
875  break;
876 
877  pUnoCursor->Exchange();
878  xRef = new SwXTextPortion( pUnoCursor, xParent, PORTION_FRAME);
879  }
880  break;
881 
882  case RES_TXTATR_FTN:
883  {
884  if(!bRightMoveForbidden)
885  {
886  pUnoCursor->Right(1);
887  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
888  break;
890  pUnoCursor, xParent, PORTION_FOOTNOTE);
891  xRef = pPortion;
892  Reference<XFootnote> xContent =
893  SwXFootnotes::GetObject(rDoc, pAttr->GetFootnote());
894  pPortion->SetFootnote(xContent);
895  }
896  }
897  break;
898 
899  case RES_TXTATR_TOXMARK:
900  case RES_TXTATR_REFMARK:
901  {
902  bool bIsPoint = !(pAttr->GetEnd());
903  if (!bRightMoveForbidden || !bIsPoint)
904  {
905  if (bIsPoint)
906  {
907  pUnoCursor->Right(1);
908  }
909  Reference<XTextRange> xTmp =
910  (RES_TXTATR_REFMARK == nAttrWhich)
912  xParent, pUnoCursor, *pAttr, false)
914  xParent, pUnoCursor, *pAttr, false);
915  if (bIsPoint) // consume CH_TXTATR!
916  {
917  pUnoCursor->Normalize(false);
918  pUnoCursor->DeleteMark();
919  xRef = xTmp;
920  }
921  else // just insert it
922  {
923  rPortionStack.top().first->push_back(xTmp);
924  }
925  }
926  }
927  break;
928  case RES_TXTATR_CJK_RUBY:
929  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
930  if(pAttr->GetEnd() && (*pAttr->GetEnd() != pAttr->GetStart()))
931  {
932  lcl_InsertRubyPortion( *rPortionStack.top().first,
933  xParent, pUnoCursor, *pAttr, false);
934  }
935  break;
936  case RES_TXTATR_META:
938  if (pAttr->GetStart() != *pAttr->GetEnd())
939  {
940  if (!bRightMoveForbidden)
941  {
942  pUnoCursor->Right(1);
943  o_rbCursorMoved = true;
944  // only if the end is included in selection!
945  if ((i_nEndPos < 0) ||
946  (*pAttr->GetEnd() <= i_nEndPos))
947  {
948  rPortionStack.push( std::make_pair(
949  new TextRangeList_t, pAttr ));
950  }
951  }
952  }
953  break;
954  case RES_TXTATR_AUTOFMT:
955  case RES_TXTATR_INETFMT:
956  case RES_TXTATR_CHARFMT:
957  break; // these are handled as properties of a "Text" portion
958  default:
959  OSL_FAIL("unknown attribute");
960  break;
961  }
962  }
963  nStartIndex++;
964  }
965 
966  if (xRef.is()) // implies that we have moved the cursor
967  {
968  o_rbCursorMoved = true;
969  }
970  if (!o_rbCursorMoved)
971  {
972  // search for attribute changes behind the current cursor position
973  // break up at frames, bookmarks, redlines
974 
975  nStartIndex = 0;
976  nNextStart = 0;
977  while(nStartIndex < pHints->Count() &&
978  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
979  nStartIndex++;
980 
981  nEndIndex = 0;
982  nNextEnd = 0;
983  while(nEndIndex < pHints->Count() &&
984  nCurrentIndex >= (nNextEnd = pHints->GetSortedByEnd(nEndIndex)->GetAnyEnd()))
985  nEndIndex++;
986 
987  sal_Int32 nNextPos =
988  ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd))
989  ? nNextStart : nNextEnd;
990  if (nNextPos > nCurrentIndex)
991  {
992  o_rNextAttrPosition = nNextPos;
993  }
994  }
995  return xRef;
996 }
997 
998 static void lcl_MoveCursor( SwUnoCursor * const pUnoCursor,
999  const sal_Int32 nCurrentIndex,
1000  const sal_Int32 nNextFrameIndex,
1001  const sal_Int32 nNextPortionIndex,
1002  const sal_Int32 nNextAttrIndex,
1003  const sal_Int32 nNextMarkIndex,
1004  const sal_Int32 nEndPos )
1005 {
1006  sal_Int32 nMovePos = pUnoCursor->GetContentNode()->Len();
1007 
1008  if ((nEndPos >= 0) && (nEndPos < nMovePos))
1009  {
1010  nMovePos = nEndPos;
1011  }
1012 
1013  if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos))
1014  {
1015  nMovePos = nNextFrameIndex;
1016  }
1017 
1018  if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos))
1019  {
1020  nMovePos = nNextPortionIndex;
1021  }
1022 
1023  if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos))
1024  {
1025  nMovePos = nNextAttrIndex;
1026  }
1027 
1028  if ((nNextMarkIndex >= 0) && (nNextMarkIndex < nMovePos))
1029  {
1030  nMovePos = nNextMarkIndex;
1031  }
1032 
1033  if (nMovePos > nCurrentIndex)
1034  {
1035  pUnoCursor->GetPoint()->nContent = nMovePos;
1036  }
1037 }
1038 
1040  SwDoc const & rDoc,
1041  SwUnoCursor const & rUnoCursor,
1042  SwXRedlinePortion_ImplList& rRedArr )
1043 {
1044  const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable();
1045  const size_t nRedTableCount = rRedTable.size();
1046 
1047  if ( nRedTableCount <= 0 )
1048  return;
1049 
1050  const SwPosition* pStart = rUnoCursor.GetPoint();
1051  const SwNodeIndex nOwnNode = pStart->nNode;
1052 
1053  for(size_t nRed = 0; nRed < nRedTableCount; ++nRed)
1054  {
1055  const SwRangeRedline* pRedline = rRedTable[nRed];
1056  const SwPosition* pRedStart = pRedline->Start();
1057  const SwNodeIndex nRedNode = pRedStart->nNode;
1058  if ( nOwnNode == nRedNode )
1059  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1060  pRedline, true ) );
1061  if( pRedline->HasMark() && pRedline->End()->nNode == nOwnNode )
1062  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1063  pRedline, false ) );
1064  }
1065 }
1066 
1068  SwUnoCursor const & rUnoCursor,
1069  SwSoftPageBreakList& rBreakArr )
1070 {
1071  const SwTextNode *pTextNode =
1072  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
1073  if( pTextNode )
1074  pTextNode->fillSoftPageBreakList( rBreakArr );
1075 }
1076 
1077 static void lcl_ExportRedline(
1078  TextRangeList_t & rPortions,
1079  Reference<XText> const& xParent,
1080  const SwUnoCursor * const pUnoCursor,
1081  SwXRedlinePortion_ImplList& rRedlineArr,
1082  const sal_Int32 nIndex)
1083 {
1084 
1085  // We want this loop to iterate over all red lines in this
1086  // array. We will only insert the ones with index matches
1087  for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end();
1088  aIter != aEnd; )
1089  {
1090  SwXRedlinePortion_ImplSharedPtr pPtr = *aIter;
1091  sal_Int32 nRealIndex = pPtr->getRealIndex();
1092  // If there are elements before nIndex, remove them
1093  if ( nIndex > nRealIndex )
1094  aIter = rRedlineArr.erase(aIter);
1095  // If the elements match, and them to the list
1096  else if ( nIndex == nRealIndex )
1097  {
1098  rPortions.push_back( new SwXRedlinePortion(
1099  *pPtr->m_pRedline, pUnoCursor, xParent, pPtr->m_bStart));
1100  aIter = rRedlineArr.erase(aIter);
1101  }
1102  // If we've iterated past nIndex, exit the loop
1103  else
1104  break;
1105  }
1106 }
1107 
1109  TextRangeList_t & rPortions,
1110  Reference<XText> const & xParent,
1111  const SwUnoCursor * const pUnoCursor,
1112  SwXBookmarkPortion_ImplList& rBkmArr,
1113  SwXRedlinePortion_ImplList& rRedlineArr,
1114  SwSoftPageBreakList& rBreakArr,
1115  const sal_Int32 nIndex,
1116  const o3tl::sorted_vector<sal_Int32>& rFramePositions,
1117  bool bOnlyFrameBookmarkStarts)
1118 {
1119  if (!rBkmArr.empty())
1120  lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions,
1121  bOnlyFrameBookmarkStarts);
1122 
1123  if (bOnlyFrameBookmarkStarts)
1124  // Only exporting the start of some collapsed bookmarks: no export of
1125  // other arrays.
1126  return;
1127 
1128  if (!rRedlineArr.empty())
1129  lcl_ExportRedline(rPortions, xParent, pUnoCursor, rRedlineArr, nIndex);
1130 
1131  if (!rBreakArr.empty())
1132  lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCursor, rBreakArr, nIndex);
1133 }
1134 
1147  TextRangeList_t & rPortions,
1148  Reference<XText> const & xParent,
1149  const SwUnoCursor * const pUnoCursor,
1150  SwAnnotationStartPortion_ImplList& rAnnotationStartArr,
1151  const sal_Int32 nIndex,
1152  const o3tl::sorted_vector<sal_Int32>& rFramePositions,
1153  bool bOnlyFrame)
1154 {
1155  for ( SwAnnotationStartPortion_ImplList::iterator aIter = rAnnotationStartArr.begin(), aEnd = rAnnotationStartArr.end();
1156  aIter != aEnd; )
1157  {
1158  SwAnnotationStartPortion_ImplSharedPtr pPtr = *aIter;
1159  if ( nIndex > pPtr->getIndex() )
1160  {
1161  aIter = rAnnotationStartArr.erase(aIter);
1162  continue;
1163  }
1164  if ( pPtr->getIndex() > nIndex )
1165  {
1166  break;
1167  }
1168 
1169  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
1170  if (bFrameStart || !bOnlyFrame)
1171  {
1173  new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
1174  pPortion->SetTextField( pPtr->mxAnnotationField );
1175  rPortions.emplace_back(pPortion);
1176 
1177  aIter = rAnnotationStartArr.erase(aIter);
1178  }
1179  else
1180  ++aIter;
1181  }
1182 }
1183 
1185 static void lcl_ExtractFramePositions(FrameClientSortList_t& rFrames, sal_Int32 nCurrentIndex,
1186  o3tl::sorted_vector<sal_Int32>& rFramePositions)
1187 {
1188  for (const auto& rFrame : rFrames)
1189  {
1190  if (rFrame.nIndex < nCurrentIndex)
1191  continue;
1192 
1193  if (rFrame.nIndex > nCurrentIndex)
1194  break;
1195 
1196  const auto pFrame = static_cast<const SwFrameFormat*>(rFrame.pFrameClient->GetRegisteredIn());
1197  if (!pFrame)
1198  continue;
1199 
1200  auto& rFormat = *const_cast<SwFrameFormat*>(pFrame);
1201  const SwFormatAnchor& rAnchor = rFormat.GetAnchor();
1202  const SwPosition* pPosition = rAnchor.GetContentAnchor();
1203  if (!pPosition)
1204  continue;
1205 
1206  rFramePositions.insert(pPosition->nContent.GetIndex());
1207  }
1208 }
1209 
1216 static sal_Int32 lcl_ExportFrames(
1217  TextRangeList_t & rPortions,
1218  Reference<XText> const & i_xParent,
1219  SwUnoCursor const * const i_pUnoCursor,
1220  FrameClientSortList_t & i_rFrames,
1221  sal_Int32 const i_nCurrentIndex)
1222 {
1223  // Ignore frames which are not exported, as we are exporting a selection
1224  // and they are anchored before the start of the selection.
1225  while (!i_rFrames.empty() && i_rFrames.front().nIndex < i_nCurrentIndex)
1226  i_rFrames.pop_front();
1227 
1228  // find first Frame in (sorted) i_rFrames at current position
1229  while (!i_rFrames.empty() && (i_rFrames.front().nIndex == i_nCurrentIndex))
1230  // do not check for i_nEnd here; this is done implicitly by lcl_MoveCursor
1231  {
1232  auto pFrame = static_cast<SwFrameFormat*>(i_rFrames.front().pFrameClient->GetRegisteredIn());
1233  if (pFrame) // Frame could be disposed
1234  {
1235  rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(i_pUnoCursor, i_xParent, *pFrame );
1236  rPortions.emplace_back(pPortion);
1237  }
1238  i_rFrames.pop_front();
1239  }
1240 
1241  return !i_rFrames.empty() ? i_rFrames.front().nIndex : -1;
1242 }
1243 
1244 static sal_Int32 lcl_GetNextIndex(
1245  SwXBookmarkPortion_ImplList const & rBkmArr,
1246  SwXRedlinePortion_ImplList const & rRedlineArr,
1247  SwSoftPageBreakList const & rBreakArr )
1248 {
1249  sal_Int32 nRet = -1;
1250  if(!rBkmArr.empty())
1251  {
1252  SwXBookmarkPortion_ImplSharedPtr pPtr = *rBkmArr.begin();
1253  nRet = pPtr->getIndex();
1254  }
1255  if(!rRedlineArr.empty())
1256  {
1257  SwXRedlinePortion_ImplSharedPtr pPtr = *rRedlineArr.begin();
1258  sal_Int32 nTmp = pPtr->getRealIndex();
1259  if(nRet < 0 || nTmp < nRet)
1260  nRet = nTmp;
1261  }
1262  if(!rBreakArr.empty())
1263  {
1264  if(nRet < 0 || *rBreakArr.begin() < nRet)
1265  nRet = *rBreakArr.begin();
1266  }
1267  return nRet;
1268 };
1269 
1271  TextRangeList_t & i_rPortions,
1272  uno::Reference< text::XText > const & i_xParentText,
1273  SwUnoCursor * const pUnoCursor,
1274  FrameClientSortList_t & i_rFrames,
1275  const sal_Int32 i_nStartPos,
1276  const sal_Int32 i_nEndPos )
1277 {
1278  if (!pUnoCursor)
1279  return;
1280 
1281  // set the start if a selection should be exported
1282  if ((i_nStartPos > 0) &&
1283  (pUnoCursor->Start()->nContent.GetIndex() != i_nStartPos))
1284  {
1285  pUnoCursor->DeleteMark();
1286  OSL_ENSURE(pUnoCursor->Start()->nNode.GetNode().GetTextNode() &&
1287  (i_nStartPos <= pUnoCursor->Start()->nNode.GetNode().GetTextNode()->
1288  GetText().getLength()), "Incorrect start position" );
1289  // ??? should this be i_nStartPos - current position ?
1290  pUnoCursor->Right(i_nStartPos);
1291  }
1292 
1293  SwDoc& rDoc = pUnoCursor->GetDoc();
1294 
1295  std::deque<sal_Int32> FieldMarks;
1296  lcl_FillFieldMarkArray(FieldMarks, *pUnoCursor, i_nStartPos);
1297 
1298  SwXBookmarkPortion_ImplList Bookmarks;
1299  lcl_FillBookmarkArray(rDoc, *pUnoCursor, Bookmarks);
1300 
1301  SwXRedlinePortion_ImplList Redlines;
1302  lcl_FillRedlineArray(rDoc, *pUnoCursor, Redlines);
1303 
1304  SwSoftPageBreakList SoftPageBreaks;
1305  lcl_FillSoftPageBreakArray(*pUnoCursor, SoftPageBreaks);
1306 
1307  SwAnnotationStartPortion_ImplList AnnotationStarts;
1308  lcl_FillAnnotationStartArray( rDoc, *pUnoCursor, AnnotationStarts );
1309 
1310  PortionStack_t PortionStack;
1311  PortionStack.push( PortionList_t(&i_rPortions, nullptr) );
1312 
1313  bool bAtEnd( false );
1314  while (!bAtEnd) // every iteration consumes at least current character!
1315  {
1316  if (pUnoCursor->HasMark())
1317  {
1318  pUnoCursor->Normalize(false);
1319  pUnoCursor->DeleteMark();
1320  }
1321 
1322  SwTextNode * const pTextNode = pUnoCursor->GetNode().GetTextNode();
1323  if (!pTextNode)
1324  {
1325  OSL_FAIL("lcl_CreatePortions: no TextNode - what now ?");
1326  return;
1327  }
1328 
1329  SwpHints * const pHints = pTextNode->GetpSwpHints();
1330  const sal_Int32 nCurrentIndex =
1331  pUnoCursor->GetPoint()->nContent.GetIndex();
1332  // this contains the portion which consumes the character in the
1333  // text at nCurrentIndex; i.e. it must be set _once_ per iteration
1334  uno::Reference< XTextRange > xRef;
1335 
1336  SwUnoCursorHelper::SelectPam(*pUnoCursor, true); // set mark
1337 
1338  // First remember the frame positions.
1339  o3tl::sorted_vector<sal_Int32> aFramePositions;
1340  lcl_ExtractFramePositions(i_rFrames, nCurrentIndex, aFramePositions);
1341 
1342  // Then export start of collapsed bookmarks which "cover" at-char
1343  // anchored frames.
1344  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1345  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true );
1346 
1348  *PortionStack.top().first,
1349  i_xParentText,
1350  pUnoCursor,
1351  AnnotationStarts,
1352  nCurrentIndex,
1353  aFramePositions,
1354  /*bOnlyFrame=*/true );
1355 
1356  const sal_Int32 nFirstFrameIndex =
1357  lcl_ExportFrames( *PortionStack.top().first,
1358  i_xParentText, pUnoCursor, i_rFrames, nCurrentIndex);
1359 
1360  // Export ends of the previously started collapsed bookmarks + all
1361  // other bookmarks, redlines, etc.
1362  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1363  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false );
1364 
1366  *PortionStack.top().first,
1367  i_xParentText,
1368  pUnoCursor,
1369  AnnotationStarts,
1370  nCurrentIndex,
1371  aFramePositions,
1372  /*bOnlyFrame=*/false );
1373 
1374  bool bCursorMoved( false );
1375  sal_Int32 nNextAttrIndex = -1;
1376  // #111716# the cursor must not move right at the
1377  // end position of a selection!
1378  bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos))
1379  || (nCurrentIndex >= pTextNode->Len());
1380  if (pHints)
1381  {
1382  // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor
1383  xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCursor,
1384  pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd,
1385  bCursorMoved, nNextAttrIndex);
1386  if (PortionStack.empty())
1387  {
1388  OSL_FAIL("CreatePortions: stack underflow");
1389  return;
1390  }
1391  }
1392 
1393  if (!xRef.is() && !bCursorMoved)
1394  {
1395  if (!bAtEnd &&
1396  !FieldMarks.empty() && (FieldMarks.front() == nCurrentIndex))
1397  {
1398  // moves cursor
1399  xRef = lcl_ExportFieldMark(i_xParentText, pUnoCursor, pTextNode);
1400  FieldMarks.pop_front();
1401  }
1402  }
1403  else
1404  {
1405  OSL_ENSURE(FieldMarks.empty() ||
1406  (FieldMarks.front() != nCurrentIndex),
1407  "fieldmark and hint with CH_TXTATR at same pos?");
1408  }
1409 
1410  if (!bAtEnd && !xRef.is() && !bCursorMoved)
1411  {
1412  const sal_Int32 nNextPortionIndex =
1413  lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks);
1414 
1415  sal_Int32 nNextMarkIndex = ( !FieldMarks.empty() ? FieldMarks.front() : -1 );
1416  if ( !AnnotationStarts.empty()
1417  && ( nNextMarkIndex == -1
1418  || (*AnnotationStarts.begin())->getIndex() < nNextMarkIndex ) )
1419  {
1420  nNextMarkIndex = (*AnnotationStarts.begin())->getIndex();
1421  }
1422 
1424  pUnoCursor,
1425  nCurrentIndex,
1426  nFirstFrameIndex,
1427  nNextPortionIndex,
1428  nNextAttrIndex,
1429  nNextMarkIndex,
1430  i_nEndPos );
1431 
1432  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1433  }
1434  else if (bAtEnd && !xRef.is() && !pTextNode->Len())
1435  {
1436  // special case: for an empty paragraph, we better put out a
1437  // text portion because there may be a hyperlink attribute
1438  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1439  }
1440 
1441  if (xRef.is())
1442  {
1443  PortionStack.top().first->push_back(xRef);
1444  }
1445  }
1446 
1447  OSL_ENSURE((PortionStack.size() == 1) && !PortionStack.top().second,
1448  "CreatePortions: stack error" );
1449 }
1450 
1451 /* 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:1775
virtual sal_Int32 Len() const
Definition: node.cxx:1246
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:215
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:223
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:277
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:188
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:1790
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:177
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(156)
const SwIndex * GetNext() const
Definition: index.hxx:98
size_type size() const
Definition: docary.hxx:265
SwContentNode * GetContentNode(bool bPoint=true) const
Definition: pam.hxx:229
sal_uInt16 sal_Unicode
SwIndex nContent
Definition: pam.hxx:38
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)
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:683
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
const css::uno::Sequence< sal_Int8 > & getSeq() const
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:59
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:742
const SwPosition * GetPoint() const
Definition: pam.hxx:207
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
static bool isTextBox(const SwFrameFormat *pFormat, sal_uInt16 nType, SdrObject *pObject=nullptr)
Is the frame format a text box?
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:179
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:1625
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_Int64 getSomethingImpl(const css::uno::Sequence< sal_Int8 > &rId, T *pThis, FallbackToGetSomethingOf< Base >={})
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:181
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:163
#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)
uno::Reference< ucb::XContent > xContent
#define CH_TXT_ATR_FIELDSEP
Definition: hintids.hxx:180
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:850
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