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