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