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