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  class theSwXTextPortionEnumerationUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextPortionEnumerationUnoTunnelId > {};
202  struct SwAnnotationStartPortion_Impl
203  {
204 
205  uno::Reference< text::XTextField > mxAnnotationField;
206  const SwPosition maPosition;
207 
208  SwAnnotationStartPortion_Impl(
209  uno::Reference< text::XTextField > const& xAnnotationField,
210  SwPosition const& rPosition)
211  : mxAnnotationField ( xAnnotationField )
212  , maPosition ( rPosition )
213  {
214  }
215 
216  sal_Int32 getIndex () const
217  {
218  return maPosition.nContent.GetIndex();
219  }
220  };
221  typedef std::shared_ptr < SwAnnotationStartPortion_Impl > SwAnnotationStartPortion_ImplSharedPtr;
222  struct AnnotationStartCompareStruct
223  {
224  bool operator () ( const SwAnnotationStartPortion_ImplSharedPtr &r1,
225  const SwAnnotationStartPortion_ImplSharedPtr &r2 )
226  const
227  {
228  return r1->maPosition < r2->maPosition;
229  }
230  };
231  typedef std::multiset < SwAnnotationStartPortion_ImplSharedPtr, AnnotationStartCompareStruct > SwAnnotationStartPortion_ImplList;
232 
233  void lcl_FillAnnotationStartArray(
234  SwDoc& rDoc,
235  SwUnoCursor& rUnoCursor,
236  SwAnnotationStartPortion_ImplList& rAnnotationStartArr )
237  {
238  IDocumentMarkAccess* const pMarkAccess = rDoc.getIDocumentMarkAccess();
239  if ( pMarkAccess->getAnnotationMarksCount() == 0 )
240  {
241  return;
242  }
243 
244  // no need to consider annotation marks starting after aEndOfPara
245  SwPosition aEndOfPara(*rUnoCursor.GetPoint());
246  aEndOfPara.nContent = aEndOfPara.nNode.GetNode().GetTextNode()->Len();
247  const IDocumentMarkAccess::const_iterator_t pCandidatesEnd =
248  pMarkAccess->findFirstAnnotationStartsAfter(aEndOfPara);
249 
250  // search for all annotation marks that have its start position in this paragraph
251  const SwNodeIndex nOwnNode = rUnoCursor.GetPoint()->nNode;
253  ppMark != pCandidatesEnd;
254  ++ppMark )
255  {
256  ::sw::mark::AnnotationMark* const pAnnotationMark =
257  dynamic_cast< ::sw::mark::AnnotationMark* >(*ppMark);
258 
259  if (!pAnnotationMark)
260  continue;
261 
262  const SwPosition& rStartPos = pAnnotationMark->GetMarkStart();
263  if (rStartPos.nNode != nOwnNode)
264  continue;
265 
266  const SwFormatField* pAnnotationFormatField = pAnnotationMark->GetAnnotationFormatField();
267  if (!pAnnotationFormatField)
268  {
269  SAL_WARN("sw.core", "missing annotation format field");
270  continue;
271  }
272 
273  rAnnotationStartArr.insert(
274  std::make_shared<SwAnnotationStartPortion_Impl>(
276  pAnnotationFormatField),
277  rStartPos));
278  }
279  }
280 }
281 
282 const uno::Sequence< sal_Int8 > & SwXTextPortionEnumeration::getUnoTunnelId()
283 {
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* pDoc = 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  if (pDoc)
409  {
410  pFieldmark = pDoc->getIDocumentMarkAccess()->
411  getFieldmarkAt(*pUnoCursor->GetMark());
412  }
413  SwXTextPortion* pPortion = new SwXTextPortion(
414  pUnoCursor, i_xParentText, PORTION_FIELD_START);
415  xRef = pPortion;
416  if (pFieldmark && pDoc)
417  {
418  pPortion->SetBookmark(
419  SwXFieldmark::CreateXFieldmark(*pDoc, pFieldmark));
420  }
421  }
422  else if (CH_TXT_ATR_FIELDSEP == Char)
423  {
424  // TODO how to get the field?
425  SwXTextPortion* pPortion = new SwXTextPortion(
426  pUnoCursor, i_xParentText, PORTION_FIELD_SEP);
427  xRef = pPortion;
428  }
429  else if (CH_TXT_ATR_FIELDEND == Char)
430  {
431  ::sw::mark::IFieldmark* pFieldmark = nullptr;
432  if (pDoc)
433  {
434  pFieldmark = pDoc->getIDocumentMarkAccess()->
435  getFieldmarkAt(*pUnoCursor->GetMark());
436  }
437  SwXTextPortion* pPortion = new SwXTextPortion(
438  pUnoCursor, i_xParentText, PORTION_FIELD_END);
439  xRef = pPortion;
440  if (pFieldmark && pDoc)
441  {
442  pPortion->SetBookmark(
443  SwXFieldmark::CreateXFieldmark(*pDoc, pFieldmark));
444  }
445  }
446  else if (CH_TXT_ATR_FORMELEMENT == Char)
447  {
448  ::sw::mark::IFieldmark* pFieldmark = nullptr;
449  if (pDoc)
450  {
451  pFieldmark = pDoc->getIDocumentMarkAccess()->getFieldmarkAt(*pUnoCursor->GetMark());
452  }
453  SwXTextPortion* pPortion = new SwXTextPortion(
454  pUnoCursor, i_xParentText, PORTION_FIELD_START_END);
455  xRef = pPortion;
456  if (pFieldmark && pDoc)
457  {
458  pPortion->SetBookmark(
459  SwXFieldmark::CreateXFieldmark(*pDoc, pFieldmark));
460  }
461  }
462  else
463  {
464  OSL_FAIL("no fieldmark found?");
465  }
466  return xRef;
467 }
468 
469 static Reference<XTextRange>
471  Reference<XText> const& xParent,
472  const SwUnoCursor * const pUnoCursor,
473  const SwTextAttr & rAttr, const bool bEnd)
474 {
475  SwDoc* pDoc = pUnoCursor->GetDoc();
476  SwFormatRefMark& rRefMark = const_cast<SwFormatRefMark&>(
477  static_cast<const SwFormatRefMark&>(rAttr.GetAttr()));
478  Reference<XTextContent> xContent;
479  if (!xContent.is())
480  {
481  xContent = SwXReferenceMark::CreateXReferenceMark(*pDoc, &rRefMark);
482  }
483 
484  SwXTextPortion* pPortion = nullptr;
485  if (!bEnd)
486  {
487  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_START);
488  pPortion->SetRefMark(xContent);
489  pPortion->SetCollapsed(rAttr.End() == nullptr);
490  }
491  else
492  {
493  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_REFMARK_END);
494  pPortion->SetRefMark(xContent);
495  }
496  return pPortion;
497 }
498 
499 static void
501  TextRangeList_t & rPortions,
502  Reference<XText> const& xParent,
503  const SwUnoCursor * const pUnoCursor,
504  const SwTextAttr & rAttr, const bool bEnd)
505 {
506  SwXTextPortion* pPortion = new SwXTextPortion(pUnoCursor,
507  static_txtattr_cast<const SwTextRuby&>(rAttr), xParent, bEnd);
508  rPortions.emplace_back(pPortion);
509  pPortion->SetCollapsed(rAttr.End() == nullptr);
510 }
511 
512 static Reference<XTextRange>
514  Reference<XText> const& xParent,
515  const SwUnoCursor * const pUnoCursor,
516  SwTextAttr & rAttr, const bool bEnd)
517 {
518  SwDoc* pDoc = pUnoCursor->GetDoc();
519  SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr());
520 
521  const Reference<XTextContent> xContent =
523 
524  SwXTextPortion* pPortion = nullptr;
525  if (!bEnd)
526  {
527  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_START);
528  pPortion->SetTOXMark(xContent);
529  pPortion->SetCollapsed(rAttr.GetEnd() == nullptr);
530  }
531  else
532  {
533  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_TOXMARK_END);
534  pPortion->SetTOXMark(xContent);
535  }
536  return pPortion;
537 }
538 
539 static uno::Reference<text::XTextRange>
541  uno::Reference<text::XText> const& xParent,
542  const SwUnoCursor * const pUnoCursor,
543  SwTextAttr & rAttr, std::unique_ptr<TextRangeList_t const> && pPortions)
544 {
545  const uno::Reference<rdf::XMetadatable> xMeta( SwXMeta::CreateXMeta(
546  *static_cast<SwFormatMeta &>(rAttr.GetAttr()).GetMeta(),
547  xParent, std::move(pPortions)));
548  SwXTextPortion * pPortion(nullptr);
549  if (RES_TXTATR_META == rAttr.Which())
550  {
551  const uno::Reference<text::XTextContent> xContent(xMeta,
552  uno::UNO_QUERY);
553  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_META);
554  pPortion->SetMeta(xContent);
555  }
556  else
557  {
558  const uno::Reference<text::XTextField> xField(xMeta, uno::UNO_QUERY);
559  pPortion = new SwXTextPortion(pUnoCursor, xParent, PORTION_FIELD);
560  pPortion->SetTextField(xField);
561  }
562  return pPortion;
563 }
564 
579 static void lcl_ExportBookmark(
580  TextRangeList_t & rPortions,
581  Reference<XText> const& xParent,
582  const SwUnoCursor * const pUnoCursor,
583  SwXBookmarkPortion_ImplList& rBkmArr,
584  const sal_Int32 nIndex,
585  const std::set<sal_Int32>& rFramePositions,
586  bool bOnlyFrameStarts)
587 {
588  for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; )
589  {
590  const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter;
591  if ( nIndex > pPtr->getIndex() )
592  {
593  if (bOnlyFrameStarts)
594  ++aIter;
595  else
596  aIter = rBkmArr.erase(aIter);
597  continue;
598  }
599  if ( nIndex < pPtr->getIndex() )
600  break;
601 
602  if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) ||
603  (BkmType::StartEnd == pPtr->nBkmType))
604  {
605  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
606  bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts;
607  if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts)
608  {
609  // At this we create a text portion, due to one of these
610  // reasons:
611  // - this is the real start of a non-collapsed bookmark
612  // - this is the real position of a collapsed bookmark
613  // - this is the start or end (depending on bOnlyFrameStarts)
614  // of a collapsed bookmark at the same position as an at-char
615  // anchored frame
616  SwXTextPortion* pPortion =
617  new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START);
618  rPortions.emplace_back(pPortion);
619  pPortion->SetBookmark(pPtr->xBookmark);
620  pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart );
621  }
622  }
623  else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts)
624  {
625  SwXTextPortion* pPortion =
626  new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END);
627  rPortions.emplace_back(pPortion);
628  pPortion->SetBookmark(pPtr->xBookmark);
629  }
630 
631  // next bookmark
632  if (bOnlyFrameStarts)
633  ++aIter;
634  else
635  aIter = rBkmArr.erase(aIter);
636  }
637 }
638 
640  TextRangeList_t & rPortions,
641  Reference<XText> const& xParent,
642  const SwUnoCursor * const pUnoCursor,
643  SwSoftPageBreakList& rBreakArr,
644  const sal_Int32 nIndex)
645 {
646  for ( SwSoftPageBreakList::iterator aIter = rBreakArr.begin(),
647  aEnd = rBreakArr.end();
648  aIter != aEnd; )
649  {
650  if ( nIndex > *aIter )
651  {
652  aIter = rBreakArr.erase(aIter);
653  continue;
654  }
655  if ( nIndex < *aIter )
656  break;
657 
658  rPortions.push_back(
659  new SwXTextPortion(pUnoCursor, xParent, PORTION_SOFT_PAGEBREAK) );
660  aIter = rBreakArr.erase(aIter);
661  }
662 }
663 
664 namespace {
665 
666 struct SwXRedlinePortion_Impl
667 {
668  const SwRangeRedline* m_pRedline;
669  const bool m_bStart;
670 
671  SwXRedlinePortion_Impl ( const SwRangeRedline* pRed, const bool bIsStart )
672  : m_pRedline(pRed)
673  , m_bStart(bIsStart)
674  {
675  }
676 
677  sal_Int32 getRealIndex () const
678  {
679  return m_bStart ? m_pRedline->Start()->nContent.GetIndex()
680  : m_pRedline->End() ->nContent.GetIndex();
681  }
682 };
683 
684 }
685 
686 typedef std::shared_ptr < SwXRedlinePortion_Impl >
688 
689 namespace {
690 
691 struct RedlineCompareStruct
692 {
693  static const SwPosition& getPosition ( const SwXRedlinePortion_ImplSharedPtr &r )
694  {
695  return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End());
696  }
697 
698  bool operator () ( const SwXRedlinePortion_ImplSharedPtr &r1,
699  const SwXRedlinePortion_ImplSharedPtr &r2 ) const
700  {
701  return getPosition ( r1 ) < getPosition ( r2 );
702  }
703 };
704 
705 }
706 
707 typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct >
709 
710 static Reference<XTextRange>
712  PortionStack_t & rPortionStack,
713  const Reference<XText> & xParent,
714  SwUnoCursor * const pUnoCursor,
715  SwpHints const * const pHints,
716  const sal_Int32 i_nStartPos,
717  const sal_Int32 i_nEndPos,
718  const sal_Int32 nCurrentIndex,
719  const bool bRightMoveForbidden,
720  bool & o_rbCursorMoved,
721  sal_Int32 & o_rNextAttrPosition)
722 {
723  // if the attribute has a dummy character, then xRef is set (except META)
724  // otherwise, the portion for the attribute is inserted into rPortions!
725  Reference<XTextRange> xRef;
726  SwDoc* pDoc = pUnoCursor->GetDoc();
727  //search for special text attributes - first some ends
728  size_t nEndIndex = 0;
729  sal_Int32 nNextEnd = 0;
730  while(nEndIndex < pHints->Count() &&
731  (!pHints->GetSortedByEnd(nEndIndex)->GetEnd() ||
732  nCurrentIndex >= (nNextEnd = (*pHints->GetSortedByEnd(nEndIndex)->GetEnd()))))
733  {
734  if(pHints->GetSortedByEnd(nEndIndex)->GetEnd())
735  {
736  SwTextAttr * const pAttr = pHints->GetSortedByEnd(nEndIndex);
737  if (nNextEnd == nCurrentIndex)
738  {
739  const sal_uInt16 nWhich( pAttr->Which() );
740  switch (nWhich)
741  {
742  case RES_TXTATR_TOXMARK:
743  {
744  Reference<XTextRange> xTmp = lcl_CreateTOXMarkPortion(
745  xParent, pUnoCursor, *pAttr, true);
746  rPortionStack.top().first->push_back(xTmp);
747  }
748  break;
749  case RES_TXTATR_REFMARK:
750  {
751  Reference<XTextRange> xTmp = lcl_CreateRefMarkPortion(
752  xParent, pUnoCursor, *pAttr, true);
753  rPortionStack.top().first->push_back(xTmp);
754  }
755  break;
756  case RES_TXTATR_CJK_RUBY:
757  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
758  if( *pAttr->GetEnd() == pAttr->GetStart())
759  {
760  lcl_InsertRubyPortion( *rPortionStack.top().first,
761  xParent, pUnoCursor, *pAttr, false);
762  }
763  lcl_InsertRubyPortion( *rPortionStack.top().first,
764  xParent, pUnoCursor, *pAttr, true);
765  break;
766  case RES_TXTATR_META:
768  {
769  OSL_ENSURE(pAttr->GetStart() != *pAttr->GetEnd(),
770  "empty meta?");
771  if ((i_nStartPos > 0) &&
772  (pAttr->GetStart() < i_nStartPos))
773  {
774  // force skip pAttr and rest of attribute ends
775  // at nCurrentIndex
776  // because they are not contained in the meta pAttr
777  // and the meta pAttr itself is outside selection!
778  // (necessary for SwXMeta::createEnumeration)
779  if (pAttr->GetStart() + 1 == i_nStartPos)
780  {
781  nEndIndex = pHints->Count() - 1;
782  }
783  break;
784  }
785  PortionList_t Top = rPortionStack.top();
786  if (Top.second != pAttr)
787  {
788  OSL_FAIL("ExportHints: stack error" );
789  }
790  else
791  {
792  std::unique_ptr<const TextRangeList_t>
793  pCurrentPortions(Top.first);
794  rPortionStack.pop();
795  const uno::Reference<text::XTextRange> xPortion(
796  lcl_CreateMetaPortion(xParent, pUnoCursor,
797  *pAttr, std::move(pCurrentPortions)));
798  rPortionStack.top().first->push_back(xPortion);
799  }
800  }
801  break;
802  }
803  }
804  }
805  nEndIndex++;
806  }
807 
808  // then some starts
809  size_t nStartIndex = 0;
810  sal_Int32 nNextStart = 0;
811  while(nStartIndex < pHints->Count() &&
812  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
813  {
814  SwTextAttr * const pAttr = pHints->Get(nStartIndex);
815  sal_uInt16 nAttrWhich = pAttr->Which();
816  if (nNextStart == nCurrentIndex)
817  {
818  switch( nAttrWhich )
819  {
820  case RES_TXTATR_FIELD:
821  if(!bRightMoveForbidden)
822  {
823  pUnoCursor->Right(1);
824  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
825  break;
826  SwXTextPortion* pPortion;
827  xRef = pPortion =
828  new SwXTextPortion(
829  pUnoCursor, xParent, PORTION_FIELD);
830  Reference<XTextField> const xField =
832  &pAttr->GetFormatField());
833  pPortion->SetTextField(xField);
834  }
835  break;
836 
838  if(!bRightMoveForbidden)
839  {
840  pUnoCursor->Right(1);
841  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
842  break;
843 
844  const SwTextAnnotationField* pTextAnnotationField = dynamic_cast<const SwTextAnnotationField*>( pAttr );
845  ::sw::mark::IMark* pAnnotationMark = pTextAnnotationField ? pTextAnnotationField->GetAnnotationMark() : nullptr;
846  if ( pAnnotationMark != nullptr )
847  {
848  SwXTextPortion* pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION_END );
850  *pDoc, pAnnotationMark));
851  xRef = pPortion;
852  }
853  else
854  {
855  SwXTextPortion* pPortion = new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
856  Reference<XTextField> xField =
858  &pAttr->GetFormatField());
859  pPortion->SetTextField(xField);
860  xRef = pPortion;
861  }
862  }
863  break;
864 
866  if(!bRightMoveForbidden)
867  {
868 
869  pUnoCursor->Right(
870  pAttr->GetFormatField().GetField()->ExpandField(true, nullptr).getLength() + 2 );
871  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
872  break;
873  SwXTextPortion* pPortion =
874  new SwXTextPortion( pUnoCursor, xParent, PORTION_FIELD);
875  xRef = pPortion;
876  Reference<XTextField> xField =
878  &pAttr->GetFormatField());
879  pPortion->SetTextField(xField);
880  }
881  break;
882 
883  case RES_TXTATR_FLYCNT:
884  if(!bRightMoveForbidden)
885  {
886  pUnoCursor->Right(1);
887  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
888  break; // Robust #i81708# content in covered cells
889 
890  // Do not expose inline anchored textboxes.
892  break;
893 
894  pUnoCursor->Exchange();
895  xRef = new SwXTextPortion( pUnoCursor, xParent, PORTION_FRAME);
896  }
897  break;
898 
899  case RES_TXTATR_FTN:
900  {
901  if(!bRightMoveForbidden)
902  {
903  pUnoCursor->Right(1);
904  if( *pUnoCursor->GetMark() == *pUnoCursor->GetPoint() )
905  break;
906  SwXTextPortion* pPortion;
907  xRef = pPortion = new SwXTextPortion(
908  pUnoCursor, xParent, PORTION_FOOTNOTE);
909  Reference<XFootnote> xContent =
910  SwXFootnotes::GetObject(*pDoc, pAttr->GetFootnote());
911  pPortion->SetFootnote(xContent);
912  }
913  }
914  break;
915 
916  case RES_TXTATR_TOXMARK:
917  case RES_TXTATR_REFMARK:
918  {
919  bool bIsPoint = !(pAttr->GetEnd());
920  if (!bRightMoveForbidden || !bIsPoint)
921  {
922  if (bIsPoint)
923  {
924  pUnoCursor->Right(1);
925  }
926  Reference<XTextRange> xTmp =
927  (RES_TXTATR_REFMARK == nAttrWhich)
929  xParent, pUnoCursor, *pAttr, false)
931  xParent, pUnoCursor, *pAttr, false);
932  if (bIsPoint) // consume CH_TXTATR!
933  {
934  pUnoCursor->Normalize(false);
935  pUnoCursor->DeleteMark();
936  xRef = xTmp;
937  }
938  else // just insert it
939  {
940  rPortionStack.top().first->push_back(xTmp);
941  }
942  }
943  }
944  break;
945  case RES_TXTATR_CJK_RUBY:
946  //#i91534# GetEnd() == 0 mixes the order of ruby start/end
947  if(pAttr->GetEnd() && (*pAttr->GetEnd() != pAttr->GetStart()))
948  {
949  lcl_InsertRubyPortion( *rPortionStack.top().first,
950  xParent, pUnoCursor, *pAttr, false);
951  }
952  break;
953  case RES_TXTATR_META:
955  if (pAttr->GetStart() != *pAttr->GetEnd())
956  {
957  if (!bRightMoveForbidden)
958  {
959  pUnoCursor->Right(1);
960  o_rbCursorMoved = true;
961  // only if the end is included in selection!
962  if ((i_nEndPos < 0) ||
963  (*pAttr->GetEnd() <= i_nEndPos))
964  {
965  rPortionStack.push( std::make_pair(
966  new TextRangeList_t, pAttr ));
967  }
968  }
969  }
970  break;
971  case RES_TXTATR_AUTOFMT:
972  case RES_TXTATR_INETFMT:
973  case RES_TXTATR_CHARFMT:
974  break; // these are handled as properties of a "Text" portion
975  default:
976  OSL_FAIL("unknown attribute");
977  break;
978  }
979  }
980  nStartIndex++;
981  }
982 
983  if (xRef.is()) // implies that we have moved the cursor
984  {
985  o_rbCursorMoved = true;
986  }
987  if (!o_rbCursorMoved)
988  {
989  // search for attribute changes behind the current cursor position
990  // break up at frames, bookmarks, redlines
991 
992  nStartIndex = 0;
993  nNextStart = 0;
994  while(nStartIndex < pHints->Count() &&
995  nCurrentIndex >= (nNextStart = pHints->Get(nStartIndex)->GetStart()))
996  nStartIndex++;
997 
998  nEndIndex = 0;
999  nNextEnd = 0;
1000  while(nEndIndex < pHints->Count() &&
1001  nCurrentIndex >= (nNextEnd = pHints->GetSortedByEnd(nEndIndex)->GetAnyEnd()))
1002  nEndIndex++;
1003 
1004  sal_Int32 nNextPos =
1005  ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd))
1006  ? nNextStart : nNextEnd;
1007  if (nNextPos > nCurrentIndex)
1008  {
1009  o_rNextAttrPosition = nNextPos;
1010  }
1011  }
1012  return xRef;
1013 }
1014 
1015 static void lcl_MoveCursor( SwUnoCursor * const pUnoCursor,
1016  const sal_Int32 nCurrentIndex,
1017  const sal_Int32 nNextFrameIndex,
1018  const sal_Int32 nNextPortionIndex,
1019  const sal_Int32 nNextAttrIndex,
1020  const sal_Int32 nNextMarkIndex,
1021  const sal_Int32 nEndPos )
1022 {
1023  sal_Int32 nMovePos = pUnoCursor->GetContentNode()->Len();
1024 
1025  if ((nEndPos >= 0) && (nEndPos < nMovePos))
1026  {
1027  nMovePos = nEndPos;
1028  }
1029 
1030  if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos))
1031  {
1032  nMovePos = nNextFrameIndex;
1033  }
1034 
1035  if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos))
1036  {
1037  nMovePos = nNextPortionIndex;
1038  }
1039 
1040  if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos))
1041  {
1042  nMovePos = nNextAttrIndex;
1043  }
1044 
1045  if ((nNextMarkIndex >= 0) && (nNextMarkIndex < nMovePos))
1046  {
1047  nMovePos = nNextMarkIndex;
1048  }
1049 
1050  if (nMovePos > nCurrentIndex)
1051  {
1052  pUnoCursor->GetPoint()->nContent = nMovePos;
1053  }
1054 }
1055 
1057  SwDoc const & rDoc,
1058  SwUnoCursor const & rUnoCursor,
1059  SwXRedlinePortion_ImplList& rRedArr )
1060 {
1061  const SwRedlineTable& rRedTable = rDoc.getIDocumentRedlineAccess().GetRedlineTable();
1062  const size_t nRedTableCount = rRedTable.size();
1063 
1064  if ( nRedTableCount <= 0 )
1065  return;
1066 
1067  const SwPosition* pStart = rUnoCursor.GetPoint();
1068  const SwNodeIndex nOwnNode = pStart->nNode;
1069 
1070  for(size_t nRed = 0; nRed < nRedTableCount; ++nRed)
1071  {
1072  const SwRangeRedline* pRedline = rRedTable[nRed];
1073  const SwPosition* pRedStart = pRedline->Start();
1074  const SwNodeIndex nRedNode = pRedStart->nNode;
1075  if ( nOwnNode == nRedNode )
1076  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1077  pRedline, true ) );
1078  if( pRedline->HasMark() && pRedline->End()->nNode == nOwnNode )
1079  rRedArr.insert( std::make_shared<SwXRedlinePortion_Impl>(
1080  pRedline, false ) );
1081  }
1082 }
1083 
1085  SwUnoCursor const & rUnoCursor,
1086  SwSoftPageBreakList& rBreakArr )
1087 {
1088  const SwTextNode *pTextNode =
1089  rUnoCursor.GetPoint()->nNode.GetNode().GetTextNode();
1090  if( pTextNode )
1091  pTextNode->fillSoftPageBreakList( rBreakArr );
1092 }
1093 
1094 static void lcl_ExportRedline(
1095  TextRangeList_t & rPortions,
1096  Reference<XText> const& xParent,
1097  const SwUnoCursor * const pUnoCursor,
1098  SwXRedlinePortion_ImplList& rRedlineArr,
1099  const sal_Int32 nIndex)
1100 {
1101 
1102  // We want this loop to iterate over all red lines in this
1103  // array. We will only insert the ones with index matches
1104  for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end();
1105  aIter != aEnd; )
1106  {
1107  SwXRedlinePortion_ImplSharedPtr pPtr = *aIter;
1108  sal_Int32 nRealIndex = pPtr->getRealIndex();
1109  // If there are elements before nIndex, remove them
1110  if ( nIndex > nRealIndex )
1111  aIter = rRedlineArr.erase(aIter);
1112  // If the elements match, and them to the list
1113  else if ( nIndex == nRealIndex )
1114  {
1115  rPortions.push_back( new SwXRedlinePortion(
1116  *pPtr->m_pRedline, pUnoCursor, xParent, pPtr->m_bStart));
1117  aIter = rRedlineArr.erase(aIter);
1118  }
1119  // If we've iterated past nIndex, exit the loop
1120  else
1121  break;
1122  }
1123 }
1124 
1126  TextRangeList_t & rPortions,
1127  Reference<XText> const & xParent,
1128  const SwUnoCursor * const pUnoCursor,
1129  SwXBookmarkPortion_ImplList& rBkmArr,
1130  SwXRedlinePortion_ImplList& rRedlineArr,
1131  SwSoftPageBreakList& rBreakArr,
1132  const sal_Int32 nIndex,
1133  const std::set<sal_Int32>& rFramePositions,
1134  bool bOnlyFrameBookmarkStarts)
1135 {
1136  if (!rBkmArr.empty())
1137  lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions,
1138  bOnlyFrameBookmarkStarts);
1139 
1140  if (bOnlyFrameBookmarkStarts)
1141  // Only exporting the start of some collapsed bookmarks: no export of
1142  // other arrays.
1143  return;
1144 
1145  if (!rRedlineArr.empty())
1146  lcl_ExportRedline(rPortions, xParent, pUnoCursor, rRedlineArr, nIndex);
1147 
1148  if (!rBreakArr.empty())
1149  lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCursor, rBreakArr, nIndex);
1150 }
1151 
1164  TextRangeList_t & rPortions,
1165  Reference<XText> const & xParent,
1166  const SwUnoCursor * const pUnoCursor,
1167  SwAnnotationStartPortion_ImplList& rAnnotationStartArr,
1168  const sal_Int32 nIndex,
1169  const std::set<sal_Int32>& rFramePositions,
1170  bool bOnlyFrame)
1171 {
1172  for ( SwAnnotationStartPortion_ImplList::iterator aIter = rAnnotationStartArr.begin(), aEnd = rAnnotationStartArr.end();
1173  aIter != aEnd; )
1174  {
1175  SwAnnotationStartPortion_ImplSharedPtr pPtr = *aIter;
1176  if ( nIndex > pPtr->getIndex() )
1177  {
1178  aIter = rAnnotationStartArr.erase(aIter);
1179  continue;
1180  }
1181  if ( pPtr->getIndex() > nIndex )
1182  {
1183  break;
1184  }
1185 
1186  bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end();
1187  if (bFrameStart || !bOnlyFrame)
1188  {
1189  SwXTextPortion* pPortion =
1190  new SwXTextPortion( pUnoCursor, xParent, PORTION_ANNOTATION );
1191  pPortion->SetTextField( pPtr->mxAnnotationField );
1192  rPortions.emplace_back(pPortion);
1193 
1194  aIter = rAnnotationStartArr.erase(aIter);
1195  }
1196  else
1197  ++aIter;
1198  }
1199 }
1200 
1202 static void lcl_ExtractFramePositions(FrameClientSortList_t& rFrames, sal_Int32 nCurrentIndex,
1203  std::set<sal_Int32>& rFramePositions)
1204 {
1205  for (const auto& rFrame : rFrames)
1206  {
1207  if (rFrame.nIndex < nCurrentIndex)
1208  continue;
1209 
1210  if (rFrame.nIndex > nCurrentIndex)
1211  break;
1212 
1213  const SwModify* pFrame = rFrame.pFrameClient->GetRegisteredIn();
1214  if (!pFrame)
1215  continue;
1216 
1217  auto& rFormat = *static_cast<SwFrameFormat*>(const_cast<SwModify*>(pFrame));
1218  const SwFormatAnchor& rAnchor = rFormat.GetAnchor();
1219  const SwPosition* pPosition = rAnchor.GetContentAnchor();
1220  if (!pPosition)
1221  continue;
1222 
1223  rFramePositions.insert(pPosition->nContent.GetIndex());
1224  }
1225 }
1226 
1233 static sal_Int32 lcl_ExportFrames(
1234  TextRangeList_t & rPortions,
1235  Reference<XText> const & i_xParent,
1236  SwUnoCursor const * const i_pUnoCursor,
1237  FrameClientSortList_t & i_rFrames,
1238  sal_Int32 const i_nCurrentIndex)
1239 {
1240  // Ignore frames which are not exported, as we are exporting a selection
1241  // and they are anchored before the start of the selection.
1242  while (!i_rFrames.empty() && i_rFrames.front().nIndex < i_nCurrentIndex)
1243  i_rFrames.pop_front();
1244 
1245  // find first Frame in (sorted) i_rFrames at current position
1246  while (!i_rFrames.empty() && (i_rFrames.front().nIndex == i_nCurrentIndex))
1247  // do not check for i_nEnd here; this is done implicitly by lcl_MoveCursor
1248  {
1249  const SwModify * const pFrame =
1250  i_rFrames.front().pFrameClient->GetRegisteredIn();
1251  if (pFrame) // Frame could be disposed
1252  {
1253  SwXTextPortion* pPortion = new SwXTextPortion(i_pUnoCursor, i_xParent,
1254  *static_cast<SwFrameFormat*>( const_cast<SwModify*>( pFrame ) ) );
1255  rPortions.emplace_back(pPortion);
1256  }
1257  i_rFrames.pop_front();
1258  }
1259 
1260  return !i_rFrames.empty() ? i_rFrames.front().nIndex : -1;
1261 }
1262 
1263 static sal_Int32 lcl_GetNextIndex(
1264  SwXBookmarkPortion_ImplList const & rBkmArr,
1265  SwXRedlinePortion_ImplList const & rRedlineArr,
1266  SwSoftPageBreakList const & rBreakArr )
1267 {
1268  sal_Int32 nRet = -1;
1269  if(!rBkmArr.empty())
1270  {
1271  SwXBookmarkPortion_ImplSharedPtr pPtr = *rBkmArr.begin();
1272  nRet = pPtr->getIndex();
1273  }
1274  if(!rRedlineArr.empty())
1275  {
1276  SwXRedlinePortion_ImplSharedPtr pPtr = *rRedlineArr.begin();
1277  sal_Int32 nTmp = pPtr->getRealIndex();
1278  if(nRet < 0 || nTmp < nRet)
1279  nRet = nTmp;
1280  }
1281  if(!rBreakArr.empty())
1282  {
1283  if(nRet < 0 || *rBreakArr.begin() < nRet)
1284  nRet = *rBreakArr.begin();
1285  }
1286  return nRet;
1287 };
1288 
1290  TextRangeList_t & i_rPortions,
1291  uno::Reference< text::XText > const & i_xParentText,
1292  SwUnoCursor * const pUnoCursor,
1293  FrameClientSortList_t & i_rFrames,
1294  const sal_Int32 i_nStartPos,
1295  const sal_Int32 i_nEndPos )
1296 {
1297  if (!pUnoCursor)
1298  return;
1299 
1300  // set the start if a selection should be exported
1301  if ((i_nStartPos > 0) &&
1302  (pUnoCursor->Start()->nContent.GetIndex() != i_nStartPos))
1303  {
1304  pUnoCursor->DeleteMark();
1305  OSL_ENSURE(pUnoCursor->Start()->nNode.GetNode().GetTextNode() &&
1306  (i_nStartPos <= pUnoCursor->Start()->nNode.GetNode().GetTextNode()->
1307  GetText().getLength()), "Incorrect start position" );
1308  // ??? should this be i_nStartPos - current position ?
1309  pUnoCursor->Right(i_nStartPos);
1310  }
1311 
1312  SwDoc * const pDoc = pUnoCursor->GetDoc();
1313 
1314  std::deque<sal_Int32> FieldMarks;
1315  lcl_FillFieldMarkArray(FieldMarks, *pUnoCursor, i_nStartPos);
1316 
1317  SwXBookmarkPortion_ImplList Bookmarks;
1318  lcl_FillBookmarkArray(*pDoc, *pUnoCursor, Bookmarks);
1319 
1320  SwXRedlinePortion_ImplList Redlines;
1321  lcl_FillRedlineArray(*pDoc, *pUnoCursor, Redlines);
1322 
1323  SwSoftPageBreakList SoftPageBreaks;
1324  lcl_FillSoftPageBreakArray(*pUnoCursor, SoftPageBreaks);
1325 
1326  SwAnnotationStartPortion_ImplList AnnotationStarts;
1327  lcl_FillAnnotationStartArray( *pDoc, *pUnoCursor, AnnotationStarts );
1328 
1329  PortionStack_t PortionStack;
1330  PortionStack.push( PortionList_t(&i_rPortions, nullptr) );
1331 
1332  bool bAtEnd( false );
1333  while (!bAtEnd) // every iteration consumes at least current character!
1334  {
1335  if (pUnoCursor->HasMark())
1336  {
1337  pUnoCursor->Normalize(false);
1338  pUnoCursor->DeleteMark();
1339  }
1340 
1341  SwTextNode * const pTextNode = pUnoCursor->GetNode().GetTextNode();
1342  if (!pTextNode)
1343  {
1344  OSL_FAIL("lcl_CreatePortions: no TextNode - what now ?");
1345  return;
1346  }
1347 
1348  SwpHints * const pHints = pTextNode->GetpSwpHints();
1349  const sal_Int32 nCurrentIndex =
1350  pUnoCursor->GetPoint()->nContent.GetIndex();
1351  // this contains the portion which consumes the character in the
1352  // text at nCurrentIndex; i.e. it must be set _once_ per iteration
1353  uno::Reference< XTextRange > xRef;
1354 
1355  SwUnoCursorHelper::SelectPam(*pUnoCursor, true); // set mark
1356 
1357  // First remember the frame positions.
1358  std::set<sal_Int32> aFramePositions;
1359  lcl_ExtractFramePositions(i_rFrames, nCurrentIndex, aFramePositions);
1360 
1361  // Then export start of collapsed bookmarks which "cover" at-char
1362  // anchored frames.
1363  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1364  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true );
1365 
1367  *PortionStack.top().first,
1368  i_xParentText,
1369  pUnoCursor,
1370  AnnotationStarts,
1371  nCurrentIndex,
1372  aFramePositions,
1373  /*bOnlyFrame=*/true );
1374 
1375  const sal_Int32 nFirstFrameIndex =
1376  lcl_ExportFrames( *PortionStack.top().first,
1377  i_xParentText, pUnoCursor, i_rFrames, nCurrentIndex);
1378 
1379  // Export ends of the previously started collapsed bookmarks + all
1380  // other bookmarks, redlines, etc.
1381  lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1382  pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false );
1383 
1385  *PortionStack.top().first,
1386  i_xParentText,
1387  pUnoCursor,
1388  AnnotationStarts,
1389  nCurrentIndex,
1390  aFramePositions,
1391  /*bOnlyFrame=*/false );
1392 
1393  bool bCursorMoved( false );
1394  sal_Int32 nNextAttrIndex = -1;
1395  // #111716# the cursor must not move right at the
1396  // end position of a selection!
1397  bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos))
1398  || (nCurrentIndex >= pTextNode->Len());
1399  if (pHints)
1400  {
1401  // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor
1402  xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCursor,
1403  pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd,
1404  bCursorMoved, nNextAttrIndex);
1405  if (PortionStack.empty())
1406  {
1407  OSL_FAIL("CreatePortions: stack underflow");
1408  return;
1409  }
1410  }
1411 
1412  if (!xRef.is() && !bCursorMoved)
1413  {
1414  if (!bAtEnd &&
1415  !FieldMarks.empty() && (FieldMarks.front() == nCurrentIndex))
1416  {
1417  // moves cursor
1418  xRef = lcl_ExportFieldMark(i_xParentText, pUnoCursor, pTextNode);
1419  FieldMarks.pop_front();
1420  }
1421  }
1422  else
1423  {
1424  OSL_ENSURE(FieldMarks.empty() ||
1425  (FieldMarks.front() != nCurrentIndex),
1426  "fieldmark and hint with CH_TXTATR at same pos?");
1427  }
1428 
1429  if (!bAtEnd && !xRef.is() && !bCursorMoved)
1430  {
1431  const sal_Int32 nNextPortionIndex =
1432  lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks);
1433 
1434  sal_Int32 nNextMarkIndex = ( !FieldMarks.empty() ? FieldMarks.front() : -1 );
1435  if ( !AnnotationStarts.empty()
1436  && ( nNextMarkIndex == -1
1437  || (*AnnotationStarts.begin())->getIndex() < nNextMarkIndex ) )
1438  {
1439  nNextMarkIndex = (*AnnotationStarts.begin())->getIndex();
1440  }
1441 
1443  pUnoCursor,
1444  nCurrentIndex,
1445  nFirstFrameIndex,
1446  nNextPortionIndex,
1447  nNextAttrIndex,
1448  nNextMarkIndex,
1449  i_nEndPos );
1450 
1451  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1452  }
1453  else if (bAtEnd && !xRef.is() && !pTextNode->Len())
1454  {
1455  // special case: for an empty paragraph, we better put out a
1456  // text portion because there may be a hyperlink attribute
1457  xRef = new SwXTextPortion(pUnoCursor, i_xParentText, PORTION_TEXT);
1458  }
1459 
1460  if (xRef.is())
1461  {
1462  PortionStack.top().first->push_back(xRef);
1463  }
1464  }
1465 
1466  OSL_ENSURE((PortionStack.size() == 1) && !PortionStack.top().second,
1467  "CreatePortions: stack error" );
1468 }
1469 
1470 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
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:1223
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:111
constexpr TypedWhichId< SwFormatMeta > RES_TXTATR_METAFIELD(49)
const OUString & GetText() const
Definition: ndtxt.hxx:211
SwpHints * GetpSwpHints()
Definition: ndtxt.hxx:219
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
static void lcl_ExportAnnotationStarts(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwAnnotationStartPortion_ImplList &rAnnotationStartArr, const sal_Int32 nIndex, const std::set< sal_Int32 > &rFramePositions, bool bOnlyFrame)
Exports all start annotation marks from rAnnotationStartArr into rPortions that have the same start p...
virtual const sal_Int32 * GetEnd() const
end position
Definition: txatbase.cxx:48
virtual sal_Int32 Len() const override
Definition: ndtxt.cxx:275
static SW_DLLPUBLIC MarkType GetType(const ::sw::mark::IMark &rMark)
Returns the MarkType used to create the mark.
Definition: docbm.cxx:474
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:184
virtual SwPosition & GetMarkStart() const override
Definition: bookmrk.hxx:56
constexpr TypedWhichId< SwFormatFlyCnt > RES_TXTATR_FLYCNT(57)
virtual ~SwXTextPortionEnumeration() override
std::shared_ptr< SwXRedlinePortion_Impl > SwXRedlinePortion_ImplSharedPtr
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:1682
sal_uInt16 Which() const
Definition: txatbase.hxx:110
static css::uno::Reference< css::text::XTextField > CreateXTextField(SwDoc *pDoc, SwFormatField const *pFormat, SwServiceType nServiceId=SwServiceType::Invalid)
Definition: unofield.cxx:1227
virtual sal_Int32 getAnnotationMarksCount() const =0
sal_Int32 GetAnyEnd() const
end (if available), else start
Definition: txatbase.hxx:153
constexpr TypedWhichId< SwFormatField > RES_TXTATR_ANNOTATION(59)
#define CH_TXT_ATR_FORMELEMENT
Definition: hintids.hxx:177
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
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:82
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:649
void SetTOXMark(css::uno::Reference< css::text::XTextContent > const &xMark)
Definition: unoport.hxx:210
constexpr TypedWhichId< SwFormatRuby > RES_TXTATR_CJK_RUBY(53)
constexpr TypedWhichId< SwFormatCharFormat > RES_TXTATR_CHARFMT(52)
const SwFormatField & GetFormatField() const
Definition: txatbase.hxx:191
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:538
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
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
void SetFootnote(css::uno::Reference< css::text::XFootnote > const &xNote)
Definition: unoport.hxx:216
static css::uno::Reference< css::text::XTextContent > CreateXBookmark(SwDoc &rDoc,::sw::mark::IMark *pBookmark)
Definition: unobkm.cxx:155
constexpr TypedWhichId< SwFormatField > RES_TXTATR_FIELD(RES_TXTATR_NOEND_BEGIN)
Style of a layout element.
Definition: frmfmt.hxx:57
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:718
const SwPosition * GetPoint() const
Definition: pam.hxx:207
const SwPosition * GetContentAnchor() const
Definition: fmtanchr.hxx:67
void SetBookmark(css::uno::Reference< css::text::XTextContent > const &xMark)
Definition: unoport.hxx:213
Count
void Exchange()
Definition: pam.cxx:489
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:138
bool HasMark() const
A PaM marks a selection if Point and Mark are distinct positions.
Definition: pam.hxx:205
const Any & any
SwDoc * GetDoc() const
Definition: pam.hxx:243
sal_Int32 indexOfAny(OUString const &rIn, sal_Unicode const *const pChars, sal_Int32 const nPos)
Marks a character position inside a document model node.
Definition: index.hxx:33
static void lcl_ExtractFramePositions(FrameClientSortList_t &rFrames, sal_Int32 nCurrentIndex, std::set< sal_Int32 > &rFramePositions)
Fills character positions from rFrames into rFramePositions.
#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:1628
void SetTextField(css::uno::Reference< css::text::XTextField > const &xField)
Definition: unoport.hxx:219
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
void SetCollapsed(bool bSet)
Definition: unoport.hxx:225
static void lcl_ExportBookmark(TextRangeList_t &rPortions, Reference< XText > const &xParent, const SwUnoCursor *const pUnoCursor, SwXBookmarkPortion_ImplList &rBkmArr, const sal_Int32 nIndex, const std::set< sal_Int32 > &rFramePositions, bool bOnlyFrameStarts)
Exports all bookmarks from rBkmArr into rPortions that have the same start or end position as nIndex...
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:200
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
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:80
OUString ExpandField(bool bCached, SwRootFrame const *pLayout) const
expand the field.
Definition: fldbas.cxx:443
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
sw::UnoCursorPointer m_pUnoCursor
Definition: unoport.hxx:241
std::multiset< SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct > SwXRedlinePortion_ImplList
std::set< sal_Int32 > SwSoftPageBreakList
Definition: wrtww8.hxx:129
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 SwModify * GetRegisteredIn() const
Definition: calbck.hxx:157
const sal_Int32 * End() const
Definition: txatbase.hxx:148
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)
void SetRefMark(css::uno::Reference< css::text::XTextContent > const &xMark)
Definition: unoport.hxx:207
virtual const SwPosition & GetMarkEnd() const =0
constexpr TypedWhichId< SwFormatField > RES_TXTATR_INPUTFIELD(55)
#define CH_TXT_ATR_FIELDEND
Definition: hintids.hxx:181
constexpr TypedWhichId< SwFlyFrameFormat > RES_FLYFRMFMT(154)
const SfxPoolItem & GetAttr() const
Definition: txatbase.hxx:159
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)
void SetMeta(css::uno::Reference< css::text::XTextContent > const &xMeta)
Definition: unoport.hxx:222
const SwIndex * GetFirstIndex() const
Definition: index.hxx:125
virtual const SwPosition & GetMarkStart() const =0
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)
#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:844
static css::uno::Reference< css::text::XFootnote > GetObject(SwDoc &rDoc, const SwFormatFootnote &rFormat)
Definition: unocoll.cxx:1819
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:206
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 std::set< sal_Int32 > &rFramePositions, bool bOnlyFrameBookmarkStarts)