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