xref: /trunk/main/sw/source/core/unocore/unoportenum.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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__anonad61abfe0111::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__anonad61abfe0111::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 ()__anonad61abfe0111::BookmarkCompareStruct116         bool operator () ( const SwXBookmarkPortion_ImplSharedPtr &r1,
117                            const SwXBookmarkPortion_ImplSharedPtr &r2 ) const
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__anonad61abfe0111::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__anonad61abfe0111::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 ()__anonad61abfe0111::AnnotationStartCompareStruct225         bool operator () ( const SwAnnotationStartPortion_ImplSharedPtr &r1,
226                            const SwAnnotationStartPortion_ImplSharedPtr &r2 ) const
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 {
302     if( rId.getLength() == 16
303         && 0 == rtl_compareMemory( getUnoTunnelId().getConstArray(),
304                                         rId.getConstArray(), 16 ) )
305     {
306         return sal::static_int_cast< sal_Int64 >( reinterpret_cast< sal_IntPtr >( this ) );
307     }
308     return 0;
309 }
310 /* -----------------------------06.04.00 16:39--------------------------------
311 
312  ---------------------------------------------------------------------------*/
getImplementationName()313 OUString SwXTextPortionEnumeration::getImplementationName()
314 {
315     return C2U("SwXTextPortionEnumeration");
316 }
317 /* -----------------------------06.04.00 16:39--------------------------------
318 
319  ---------------------------------------------------------------------------*/
320 sal_Bool
supportsService(const OUString & rServiceName)321 SwXTextPortionEnumeration::supportsService(const OUString& rServiceName)
322 {
323     return C2U("com.sun.star.text.TextPortionEnumeration") == rServiceName;
324 }
325 /* -----------------------------06.04.00 16:39--------------------------------
326 
327  ---------------------------------------------------------------------------*/
getSupportedServiceNames()328 Sequence< OUString > SwXTextPortionEnumeration::getSupportedServiceNames()
329 {
330     Sequence< OUString > aRet(1);
331     OUString* pArray = aRet.getArray();
332     pArray[0] = C2U("com.sun.star.text.TextPortionEnumeration");
333     return aRet;
334 }
335 
336 /*-- 27.01.99 10:44:43---------------------------------------------------
337 
338   -----------------------------------------------------------------------*/
SwXTextPortionEnumeration(SwPaM & rParaCrsr,uno::Reference<XText> const & xParentText,const sal_Int32 nStart,const sal_Int32 nEnd)339 SwXTextPortionEnumeration::SwXTextPortionEnumeration(
340         SwPaM& rParaCrsr,
341         uno::Reference< XText > const & xParentText,
342         const sal_Int32 nStart,
343         const sal_Int32 nEnd )
344     : m_Portions()
345 {
346     SwUnoCrsr* pUnoCrsr =
347        rParaCrsr.GetDoc()->CreateUnoCrsr(*rParaCrsr.GetPoint(), sal_False);
348     pUnoCrsr->Add(this);
349 
350     DBG_ASSERT(nEnd == -1 || (nStart <= nEnd &&
351         nEnd <= pUnoCrsr->Start()->nNode.GetNode().GetTxtNode()->GetTxt().Len()),
352             "start or end value invalid!");
353 
354     // find all frames, graphics and OLEs that are bound AT character in para
355     FrameDependSortList_t frames;
356     ::CollectFrameAtNode(*this, pUnoCrsr->GetPoint()->nNode, frames, true);
357     lcl_CreatePortions(m_Portions, xParentText, pUnoCrsr, frames, nStart, nEnd);
358 }
359 
SwXTextPortionEnumeration(SwPaM & rParaCrsr,TextRangeList_t const & rPortions)360 SwXTextPortionEnumeration::SwXTextPortionEnumeration(
361         SwPaM& rParaCrsr,
362         TextRangeList_t const & rPortions )
363     : m_Portions( rPortions )
364 {
365     SwUnoCrsr* const pUnoCrsr =
366        rParaCrsr.GetDoc()->CreateUnoCrsr(*rParaCrsr.GetPoint(), sal_False);
367     pUnoCrsr->Add(this);
368 }
369 
370 /*-- 27.01.99 10:44:44---------------------------------------------------
371 
372   -----------------------------------------------------------------------*/
~SwXTextPortionEnumeration()373 SwXTextPortionEnumeration::~SwXTextPortionEnumeration()
374 {
375     vos::OGuard aGuard(Application::GetSolarMutex());
376 
377     SwUnoCrsr* pUnoCrsr = GetCursor();
378     delete pUnoCrsr;
379 }
380 /*-- 27.01.99 10:44:44---------------------------------------------------
381 
382   -----------------------------------------------------------------------*/
hasMoreElements()383 sal_Bool SwXTextPortionEnumeration::hasMoreElements()
384 {
385     vos::OGuard aGuard(Application::GetSolarMutex());
386 
387     return (m_Portions.size() > 0) ? sal_True : sal_False;
388 }
389 /*-- 27.01.99 10:44:45---------------------------------------------------
390 
391   -----------------------------------------------------------------------*/
nextElement()392 uno::Any SwXTextPortionEnumeration::nextElement()
393 {
394     vos::OGuard aGuard(Application::GetSolarMutex());
395 
396     if (!m_Portions.size())
397         throw container::NoSuchElementException();
398 
399     Any any;
400     any <<= m_Portions.front();
401     m_Portions.pop_front();
402     return any;
403 }
404 
405 //======================================================================
406 
407 typedef ::std::deque< xub_StrLen > FieldMarks_t;
408 
lcl_FillFieldMarkArray(FieldMarks_t & rFieldMarks,SwUnoCrsr const & rUnoCrsr,const sal_Int32 i_nStartPos)409 static void lcl_FillFieldMarkArray(
410     FieldMarks_t & rFieldMarks,
411     SwUnoCrsr const & rUnoCrsr,
412     const sal_Int32 i_nStartPos)
413 {
414     const SwTxtNode * const pTxtNode =
415         rUnoCrsr.GetPoint()->nNode.GetNode().GetTxtNode();
416     if (!pTxtNode) return;
417 
418     const sal_Unicode fld[] = {
419         CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDEND, CH_TXT_ATR_FORMELEMENT, 0 };
420     xub_StrLen pos = ::std::max(static_cast<const sal_Int32>(0), i_nStartPos);
421     while ((pos = pTxtNode->GetTxt().SearchChar(fld, pos)) != STRING_NOTFOUND)
422     {
423         rFieldMarks.push_back(pos);
424         ++pos;
425     }
426 }
427 
428 static uno::Reference<text::XTextRange>
lcl_ExportFieldMark(uno::Reference<text::XText> const & i_xParentText,SwUnoCrsr * const pUnoCrsr,const SwTxtNode * const pTxtNode)429 lcl_ExportFieldMark(
430         uno::Reference< text::XText > const & i_xParentText,
431         SwUnoCrsr * const pUnoCrsr,
432         const SwTxtNode * const pTxtNode )
433 {
434     uno::Reference<text::XTextRange> xRef;
435     SwDoc* pDoc = pUnoCrsr->GetDoc();
436     //flr: maybe its a good idea to add a special hint to the hints array and rely on the hint segmentation....
437     const xub_StrLen start = pUnoCrsr->Start()->nContent.GetIndex();
438     ASSERT(pUnoCrsr->End()->nContent.GetIndex() == start,
439                "hmm --- why is this different");
440 
441     pUnoCrsr->Right(1, CRSR_SKIP_CHARS, sal_False, sal_False);
442     if ( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() )
443     {
444         ASSERT(false, "cannot move cursor?");
445         return 0;
446     }
447 
448     const sal_Unicode Char = pTxtNode->GetTxt().GetChar(start);
449     if (CH_TXT_ATR_FIELDSTART == Char)
450     {
451         ::sw::mark::IFieldmark* pFieldmark = NULL;
452         if ( pDoc != NULL )
453         {
454             pFieldmark =
455                 pDoc->getIDocumentMarkAccess()->getFieldmarkFor(*pUnoCrsr->GetMark());
456         }
457         SwXTextPortion* pPortion =
458             new SwXTextPortion( pUnoCrsr, i_xParentText, PORTION_FIELD_START );
459         xRef = pPortion;
460         if ( pPortion != NULL
461              && pFieldmark != NULL
462              && pDoc != NULL )
463         {
464             pPortion->SetBookmark( SwXFieldmark::CreateXFieldmark( *pDoc, *pFieldmark ) );
465         }
466     }
467     else if (CH_TXT_ATR_FIELDEND == Char)
468     {
469         ::sw::mark::IFieldmark* pFieldmark = NULL;
470         if ( pDoc != NULL )
471         {
472             pFieldmark =
473                 pDoc->getIDocumentMarkAccess()->getFieldmarkFor(*pUnoCrsr->GetMark());
474         }
475         SwXTextPortion* pPortion =
476             new SwXTextPortion( pUnoCrsr, i_xParentText, PORTION_FIELD_END );
477         xRef = pPortion;
478         if ( pPortion != NULL
479              && pFieldmark != NULL
480              && pDoc != NULL )
481         {
482             pPortion->SetBookmark( SwXFieldmark::CreateXFieldmark( *pDoc, *pFieldmark ) );
483         }
484     }
485     else if (CH_TXT_ATR_FORMELEMENT == Char)
486     {
487         ::sw::mark::IFieldmark* pFieldmark = NULL;
488         if ( pDoc != NULL )
489         {
490             pFieldmark = pDoc->getIDocumentMarkAccess()->getFieldmarkFor(*pUnoCrsr->GetMark());
491         }
492         SwXTextPortion* pPortion =
493             new SwXTextPortion( pUnoCrsr, i_xParentText, PORTION_FIELD_START_END );
494         xRef = pPortion;
495         if ( pPortion != NULL
496              && pFieldmark != NULL
497              && pDoc != NULL )
498         {
499             pPortion->SetBookmark( SwXFieldmark::CreateXFieldmark( *pDoc, *pFieldmark ) );
500         }
501     }
502     else
503     {
504         ASSERT(false, "no fieldmark found?");
505     }
506     return xRef;
507 }
508 
509 /* -----------------------------31.08.00 14:28--------------------------------
510 
511  ---------------------------------------------------------------------------*/
512 static Reference<XTextRange>
lcl_CreateRefMarkPortion(Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,const SwTxtAttr & rAttr,const bool bEnd)513 lcl_CreateRefMarkPortion(
514     Reference<XText> const& xParent,
515     const SwUnoCrsr * const pUnoCrsr,
516     const SwTxtAttr & rAttr, const bool bEnd)
517 {
518     SwDoc* pDoc = pUnoCrsr->GetDoc();
519     const SwFmtRefMark& rRefMark =
520         static_cast<const SwFmtRefMark&>(rAttr.GetAttr());
521     Reference<XTextContent> xContent;
522     if (!xContent.is())
523     {
524         xContent = new SwXReferenceMark(pDoc, &rRefMark);
525     }
526 
527     SwXTextPortion* pPortion = 0;
528     if (!bEnd)
529     {
530         pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_REFMARK_START);
531         pPortion->SetRefMark(xContent);
532         pPortion->SetCollapsed(rAttr.End() ? false : true);
533     }
534     else
535     {
536         pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_REFMARK_END);
537         pPortion->SetRefMark(xContent);
538     }
539     return pPortion;
540 }
541 
542 //-----------------------------------------------------------------------------
543 static void
lcl_InsertRubyPortion(TextRangeList_t & rPortions,Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,const SwTxtAttr & rAttr,const sal_Bool bEnd)544 lcl_InsertRubyPortion(
545     TextRangeList_t & rPortions,
546     Reference<XText> const& xParent,
547     const SwUnoCrsr * const pUnoCrsr,
548     const SwTxtAttr & rAttr, const sal_Bool bEnd)
549 {
550     SwXTextPortion* pPortion = new SwXTextPortion(pUnoCrsr,
551             static_cast<const SwTxtRuby&>(rAttr), xParent, bEnd);
552     rPortions.push_back(pPortion);
553     pPortion->SetCollapsed(rAttr.End() ? false : true);
554 }
555 
556 //-----------------------------------------------------------------------------
557 static Reference<XTextRange>
lcl_CreateTOXMarkPortion(Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,SwTxtAttr & rAttr,const bool bEnd)558 lcl_CreateTOXMarkPortion(
559     Reference<XText> const& xParent,
560     const SwUnoCrsr * const pUnoCrsr,
561     SwTxtAttr & rAttr, const bool bEnd)
562 {
563     SwDoc* pDoc = pUnoCrsr->GetDoc();
564     SwTOXMark & rTOXMark = static_cast<SwTOXMark&>(rAttr.GetAttr());
565 
566     const Reference<XTextContent> xContent(
567         SwXDocumentIndexMark::CreateXDocumentIndexMark(*pDoc,
568                     *const_cast<SwTOXType*>(rTOXMark.GetTOXType()), rTOXMark),
569         uno::UNO_QUERY);
570 
571     SwXTextPortion* pPortion = 0;
572     if (!bEnd)
573     {
574         pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_TOXMARK_START);
575         pPortion->SetTOXMark(xContent);
576         pPortion->SetCollapsed(rAttr.GetEnd() ? false : true);
577     }
578     else
579     {
580         pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_TOXMARK_END);
581         pPortion->SetTOXMark(xContent);
582     }
583     return pPortion;
584 }
585 
586 //-----------------------------------------------------------------------------
587 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)588 lcl_CreateMetaPortion(
589     uno::Reference<text::XText> const& xParent,
590     const SwUnoCrsr * const pUnoCrsr,
591     SwTxtAttr & rAttr, ::std::auto_ptr<TextRangeList_t const> & pPortions)
592 {
593     const uno::Reference<rdf::XMetadatable> xMeta( SwXMeta::CreateXMeta(
594             *static_cast<SwFmtMeta &>(rAttr.GetAttr()).GetMeta(),
595             xParent, pPortions));
596     SwXTextPortion * pPortion(0);
597     if (RES_TXTATR_META == rAttr.Which())
598     {
599         const uno::Reference<text::XTextContent> xContent(xMeta,
600                 uno::UNO_QUERY);
601         pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_META);
602         pPortion->SetMeta(xContent);
603     }
604     else
605     {
606         const uno::Reference<text::XTextField> xField(xMeta, uno::UNO_QUERY);
607         pPortion = new SwXTextPortion(pUnoCrsr, xParent, PORTION_FIELD);
608         pPortion->SetTextField(xField);
609     }
610     return pPortion;
611 }
612 
613 //-----------------------------------------------------------------------------
lcl_ExportBookmark(TextRangeList_t & rPortions,Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,SwXBookmarkPortion_ImplList & rBkmArr,const xub_StrLen nIndex)614 static void lcl_ExportBookmark(
615     TextRangeList_t & rPortions,
616     Reference<XText> const& xParent,
617     const SwUnoCrsr * const pUnoCrsr,
618     SwXBookmarkPortion_ImplList& rBkmArr,
619     const xub_StrLen nIndex)
620 {
621     for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; )
622     {
623         SwXBookmarkPortion_ImplSharedPtr pPtr = (*aIter);
624         if ( nIndex > pPtr->getIndex() )
625         {
626             rBkmArr.erase( aIter++ );
627             continue;
628         }
629         if ( nIndex < pPtr->getIndex() )
630             break;
631 
632         SwXTextPortion* pPortion = 0;
633         if ((BKM_TYPE_START     == pPtr->nBkmType) ||
634             (BKM_TYPE_START_END == pPtr->nBkmType))
635         {
636             pPortion =
637                 new SwXTextPortion(pUnoCrsr, xParent, PORTION_BOOKMARK_START);
638             rPortions.push_back(pPortion);
639             pPortion->SetBookmark(pPtr->xBookmark);
640             pPortion->SetCollapsed( (BKM_TYPE_START_END == pPtr->nBkmType)
641                     ? true : false);
642 
643         }
644         if (BKM_TYPE_END == pPtr->nBkmType)
645         {
646             pPortion =
647                 new SwXTextPortion(pUnoCrsr, xParent, PORTION_BOOKMARK_END);
648             rPortions.push_back(pPortion);
649             pPortion->SetBookmark(pPtr->xBookmark);
650         }
651         rBkmArr.erase( aIter++ );
652     }
653 }
654 
655 static void
lcl_ExportSoftPageBreak(TextRangeList_t & rPortions,Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,SwSoftPageBreakList & rBreakArr,const xub_StrLen nIndex)656 lcl_ExportSoftPageBreak(
657     TextRangeList_t & rPortions,
658     Reference<XText> const& xParent,
659     const SwUnoCrsr * const pUnoCrsr,
660     SwSoftPageBreakList& rBreakArr,
661     const xub_StrLen nIndex)
662 {
663     for ( SwSoftPageBreakList::iterator aIter = rBreakArr.begin(),
664           aEnd = rBreakArr.end();
665           aIter != aEnd; )
666     {
667         if ( nIndex > *aIter )
668         {
669             rBreakArr.erase( aIter++ );
670             continue;
671         }
672         if ( nIndex < *aIter )
673             break;
674 
675         rPortions.push_back(
676             new SwXTextPortion(pUnoCrsr, xParent, PORTION_SOFT_PAGEBREAK) );
677         rBreakArr.erase( aIter++ );
678     }
679 }
680 
681 
682 /* -----------------------------18.12.00 14:51--------------------------------
683 
684  ---------------------------------------------------------------------------*/
685 //-----------------------------------------------------------------------------
686 #define REDLINE_PORTION_START_REMOVE 0//removed redlines are visible
687 #define REDLINE_PORTION_END_REMOVE   1//removed redlines are visible
688 #define REDLINE_PORTION_REMOVE       2//removed redlines are NOT visible
689 #define REDLINE_PORTION_INSERT_START 3
690 #define REDLINE_PORTION_INSERT_END   4
691 
692 struct SwXRedlinePortion_Impl
693 {
694     const SwRedline*    m_pRedline;
695     const bool          m_bStart;
696 
SwXRedlinePortion_ImplSwXRedlinePortion_Impl697     SwXRedlinePortion_Impl ( const SwRedline* pRed, const bool bIsStart )
698     : m_pRedline(pRed)
699     , m_bStart(bIsStart)
700     {
701     }
702 
getRealIndexSwXRedlinePortion_Impl703     xub_StrLen getRealIndex ()
704     {
705         return m_bStart ? m_pRedline->Start()->nContent.GetIndex()
706                         : m_pRedline->End()  ->nContent.GetIndex();
707     }
708 };
709 
710 typedef boost::shared_ptr < SwXRedlinePortion_Impl >
711     SwXRedlinePortion_ImplSharedPtr;
712 
713 struct RedlineCompareStruct
714 {
getPositionRedlineCompareStruct715     const SwPosition& getPosition ( const SwXRedlinePortion_ImplSharedPtr &r ) const
716     {
717         return *(r->m_bStart ? r->m_pRedline->Start() : r->m_pRedline->End());
718     }
719 
operator ()RedlineCompareStruct720     bool operator () ( const SwXRedlinePortion_ImplSharedPtr &r1,
721                        const SwXRedlinePortion_ImplSharedPtr &r2 ) const
722     {
723         return getPosition ( r1 ) < getPosition ( r2 );
724     }
725 };
726 
727 typedef std::multiset < SwXRedlinePortion_ImplSharedPtr, RedlineCompareStruct >
728 SwXRedlinePortion_ImplList;
729 
730 //-----------------------------------------------------------------------------
731 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)732 lcl_ExportHints(
733     PortionStack_t & rPortionStack,
734     const Reference<XText> & xParent,
735     SwUnoCrsr * const pUnoCrsr,
736     SwpHints * const pHints,
737     const sal_Int32 i_nStartPos,
738     const sal_Int32 i_nEndPos,
739     const xub_StrLen nCurrentIndex,
740     const bool bRightMoveForbidden,
741     bool & o_rbCursorMoved,
742     sal_Int32 & o_rNextAttrPosition )
743 {
744     // if the attribute has a dummy character, then xRef is set (except META)
745     // otherwise, the portion for the attribute is inserted into rPortions!
746     Reference<XTextRange> xRef;
747     SwDoc* pDoc = pUnoCrsr->GetDoc();
748     //search for special text attributes - first some ends
749     sal_uInt16 nEndIndex = 0;
750     sal_uInt16 nNextEnd = 0;
751     while(nEndIndex < pHints->GetEndCount() &&
752         (!pHints->GetEnd(nEndIndex)->GetEnd() ||
753         nCurrentIndex >= (nNextEnd = (*pHints->GetEnd(nEndIndex)->GetEnd()))))
754     {
755         if(pHints->GetEnd(nEndIndex)->GetEnd())
756         {
757             SwTxtAttr * const pAttr = pHints->GetEnd(nEndIndex);
758             if (nNextEnd == nCurrentIndex)
759             {
760                 const sal_uInt16 nWhich( pAttr->Which() );
761                 switch (nWhich)
762                 {
763                     case RES_TXTATR_TOXMARK:
764                     {
765                         Reference<XTextRange> xTmp = lcl_CreateTOXMarkPortion(
766                                 xParent, pUnoCrsr, *pAttr, true);
767                         rPortionStack.top().first->push_back(xTmp);
768                     }
769                     break;
770                     case RES_TXTATR_REFMARK:
771                     {
772                         Reference<XTextRange> xTmp = lcl_CreateRefMarkPortion(
773                                 xParent, pUnoCrsr, *pAttr, true);
774                         rPortionStack.top().first->push_back(xTmp);
775                     }
776                     break;
777                     case RES_TXTATR_CJK_RUBY:
778                        //#i91534# GetEnd() == 0 mixes the order of ruby start/end
779                         if( *pAttr->GetEnd() == *pAttr->GetStart())
780                         {
781                             lcl_InsertRubyPortion( *rPortionStack.top().first,
782                                     xParent, pUnoCrsr, *pAttr, sal_False);
783                         }
784                         lcl_InsertRubyPortion( *rPortionStack.top().first,
785                                 xParent, pUnoCrsr, *pAttr, sal_True);
786                     break;
787                     case RES_TXTATR_META:
788                     case RES_TXTATR_METAFIELD:
789                     {
790                         ASSERT(*pAttr->GetStart() != *pAttr->GetEnd(),
791                                 "empty meta?");
792                         if ((i_nStartPos > 0) &&
793                             (*pAttr->GetStart() < i_nStartPos))
794                         {
795                             // force skip pAttr and rest of attribute ends
796                             // at nCurrentIndex
797                             // because they are not contained in the meta pAttr
798                             // and the meta pAttr itself is outside selection!
799                             // (necessary for SwXMeta::createEnumeration)
800                             if (*pAttr->GetStart() + 1 == i_nStartPos)
801                             {
802                                 nEndIndex = pHints->GetEndCount() - 1;
803                             }
804                             break;
805                         }
806                         PortionList_t Top = rPortionStack.top();
807                         if (Top.second != pAttr)
808                         {
809                             ASSERT(false, "ExportHints: stack error" );
810                         }
811                         else
812                         {
813                             ::std::auto_ptr<const TextRangeList_t>
814                                 pCurrentPortions(Top.first);
815                             rPortionStack.pop();
816                             const uno::Reference<text::XTextRange> xPortion(
817                                 lcl_CreateMetaPortion(xParent, pUnoCrsr,
818                                     *pAttr, pCurrentPortions));
819                             rPortionStack.top().first->push_back(xPortion);
820                         }
821                     }
822                     break;
823                 }
824             }
825         }
826         nEndIndex++;
827     }
828 
829     // then some starts
830     sal_uInt16 nStartIndex = 0;
831     sal_uInt16 nNextStart = 0;
832     while(nStartIndex < pHints->GetStartCount() &&
833         nCurrentIndex >= (nNextStart = (*pHints->GetStart(nStartIndex)->GetStart())))
834     {
835         SwTxtAttr * const pAttr = pHints->GetStart(nStartIndex);
836         sal_uInt16 nAttrWhich = pAttr->Which();
837         if (nNextStart == nCurrentIndex)
838         {
839             switch( nAttrWhich )
840             {
841                 case RES_TXTATR_FIELD:
842                    if(!bRightMoveForbidden)
843                     {
844                         pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False);
845                         if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() )
846                             break;
847                         SwXTextPortion* pPortion;
848                         xRef = pPortion =
849                             new SwXTextPortion(
850                                 pUnoCrsr, xParent, PORTION_FIELD);
851                         Reference<XTextField> xField =
852                             SwXTextField::CreateSwXTextField(*pDoc, pAttr->GetFmtFld());
853                         pPortion->SetTextField(xField);
854                     }
855                     break;
856 
857                 case RES_TXTATR_ANNOTATION:
858                     if(!bRightMoveForbidden)
859                     {
860                         pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False);
861                         if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() )
862                             break;
863 
864                         const SwTxtAnnotationFld* pTxtAnnotationFld = dynamic_cast<const SwTxtAnnotationFld*>( pAttr );
865                         ::sw::mark::IMark* pAnnotationMark = pTxtAnnotationFld->GetAnnotationMark();
866                         if ( pAnnotationMark != NULL )
867                         {
868                             SwXTextPortion* pPortion = new SwXTextPortion( pUnoCrsr, xParent, PORTION_ANNOTATION_END );
869                             pPortion->SetBookmark( SwXBookmark::CreateXBookmark( *pDoc, *pAnnotationMark ) );
870                             xRef = pPortion;
871                         }
872                         else
873                         {
874                             SwXTextPortion* pPortion = new SwXTextPortion( pUnoCrsr, xParent, PORTION_ANNOTATION );
875                             Reference<XTextField> xField =
876                                 SwXTextField::CreateSwXTextField(*pDoc, pAttr->GetFmtFld());
877                             pPortion->SetTextField(xField);
878                             xRef = pPortion;
879                         }
880                     }
881                     break;
882 
883                 case RES_TXTATR_INPUTFIELD:
884                     if(!bRightMoveForbidden)
885                     {
886 
887                         pUnoCrsr->Right(
888                             pAttr->GetFmtFld().GetField()->ExpandField( true ).Len() + 2,
889                             CRSR_SKIP_CHARS,
890                             sal_False,
891                             sal_False );
892                         if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() )
893                             break;
894                         SwXTextPortion* pPortion =
895                             new SwXTextPortion( pUnoCrsr, xParent, PORTION_FIELD);
896                         xRef = pPortion;
897                         Reference<XTextField> xField =
898                             SwXTextField::CreateSwXTextField(*pDoc, pAttr->GetFmtFld());
899                         pPortion->SetTextField(xField);
900                     }
901                     break;
902 
903                 case RES_TXTATR_FLYCNT:
904                     if(!bRightMoveForbidden)
905                     {
906                         pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False);
907                         if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() )
908                             break; // Robust #i81708 content in covered cells
909                         pUnoCrsr->Exchange();
910                         xRef = new SwXTextPortion( pUnoCrsr, xParent, PORTION_FRAME);
911                     }
912                     break;
913 
914                 case RES_TXTATR_FTN:
915                     {
916                         if(!bRightMoveForbidden)
917                         {
918                             pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False);
919                             if( *pUnoCrsr->GetMark() == *pUnoCrsr->GetPoint() )
920                                 break;
921                             SwXTextPortion* pPortion;
922                             xRef = pPortion = new SwXTextPortion(
923                                 pUnoCrsr, xParent, PORTION_FOOTNOTE);
924                             Reference<XFootnote> xContent =
925                                 SwXFootnotes::GetObject(*pDoc, pAttr->GetFtn());
926                             pPortion->SetFootnote(xContent);
927                         }
928                     }
929                     break;
930 
931                 case RES_TXTATR_TOXMARK:
932                 case RES_TXTATR_REFMARK:
933                 {
934                     bool bIsPoint = !(pAttr->GetEnd());
935                     if (!bRightMoveForbidden || !bIsPoint)
936                     {
937                         if (bIsPoint)
938                         {
939                             pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False);
940                         }
941                         Reference<XTextRange> xTmp =
942                                 (RES_TXTATR_REFMARK == nAttrWhich)
943                             ? lcl_CreateRefMarkPortion(
944                                 xParent, pUnoCrsr, *pAttr, false)
945                             : lcl_CreateTOXMarkPortion(
946                                 xParent, pUnoCrsr, *pAttr, false);
947                         if (bIsPoint) // consume CH_TXTATR!
948                         {
949                             pUnoCrsr->Normalize(sal_False);
950                             pUnoCrsr->DeleteMark();
951                             xRef = xTmp;
952                         }
953                         else // just insert it
954                         {
955                             rPortionStack.top().first->push_back(xTmp);
956                         }
957                     }
958                 }
959                 break;
960                 case RES_TXTATR_CJK_RUBY:
961                     //#i91534# GetEnd() == 0 mixes the order of ruby start/end
962                     if(pAttr->GetEnd() && (*pAttr->GetEnd() != *pAttr->GetStart()))
963                     {
964                         lcl_InsertRubyPortion( *rPortionStack.top().first,
965                             xParent, pUnoCrsr, *pAttr, sal_False);
966                     }
967                 break;
968                 case RES_TXTATR_META:
969                 case RES_TXTATR_METAFIELD:
970                     if (*pAttr->GetStart() != *pAttr->GetEnd())
971                     {
972                         if (!bRightMoveForbidden)
973                         {
974                             pUnoCrsr->Right(1,CRSR_SKIP_CHARS,sal_False,sal_False);
975                             o_rbCursorMoved = true;
976                             // only if the end is included in selection!
977                             if ((i_nEndPos < 0) ||
978                                 (*pAttr->GetEnd() <= i_nEndPos))
979                             {
980                                 rPortionStack.push( ::std::make_pair(
981                                         new TextRangeList_t, pAttr ));
982                             }
983                         }
984                     }
985                 break;
986                 case RES_TXTATR_AUTOFMT:
987                 case RES_TXTATR_INETFMT:
988                 case RES_TXTATR_CHARFMT:
989                 break; // these are handled as properties of a "Text" portion
990                 default:
991                     DBG_ERROR("unknown attribute");
992                 break;
993             }
994         }
995         nStartIndex++;
996     }
997 
998     if (xRef.is()) // implies that we have moved the cursor
999     {
1000         o_rbCursorMoved = true;
1001     }
1002     if (!o_rbCursorMoved)
1003     {
1004         // search for attribute changes behind the current cursor position
1005         // break up at frames, bookmarks, redlines
1006 
1007         nStartIndex = 0;
1008         nNextStart = 0;
1009         while(nStartIndex < pHints->GetStartCount() &&
1010             nCurrentIndex >= (nNextStart = (*pHints->GetStart(nStartIndex)->GetStart())))
1011             nStartIndex++;
1012 
1013         nEndIndex = 0;
1014         nNextEnd = 0;
1015         while(nEndIndex < pHints->GetEndCount() &&
1016             nCurrentIndex >= (nNextEnd = (*pHints->GetEnd(nEndIndex)->GetAnyEnd())))
1017             nEndIndex++;
1018 
1019         sal_Int32 nNextPos =
1020             ((nNextStart > nCurrentIndex) && (nNextStart < nNextEnd))
1021             ?   nNextStart  :   nNextEnd;
1022         if (nNextPos > nCurrentIndex)
1023         {
1024             o_rNextAttrPosition = nNextPos;
1025         }
1026     }
1027     return xRef;
1028 }
1029 
1030 //-----------------------------------------------------------------------------
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)1031 void lcl_MoveCursor( SwUnoCrsr * const pUnoCrsr,
1032     const xub_StrLen nCurrentIndex,
1033     const sal_Int32 nNextFrameIndex,
1034     const sal_Int32 nNextPortionIndex,
1035     const sal_Int32 nNextAttrIndex,
1036     const sal_Int32 nNextMarkIndex,
1037     const sal_Int32 nEndPos )
1038 {
1039     sal_Int32 nMovePos = pUnoCrsr->GetCntntNode()->Len();
1040 
1041     if ((nEndPos >= 0) && (nEndPos < nMovePos))
1042     {
1043         nMovePos = nEndPos;
1044     }
1045 
1046     if ((nNextFrameIndex >= 0) && (nNextFrameIndex < nMovePos))
1047     {
1048         nMovePos = nNextFrameIndex;
1049     }
1050 
1051     if ((nNextPortionIndex >= 0) && (nNextPortionIndex < nMovePos))
1052     {
1053         nMovePos = nNextPortionIndex;
1054     }
1055 
1056     if ((nNextAttrIndex >= 0) && (nNextAttrIndex < nMovePos))
1057     {
1058         nMovePos = nNextAttrIndex;
1059     }
1060 
1061     if ((nNextMarkIndex >= 0) && (nNextMarkIndex < nMovePos))
1062     {
1063         nMovePos = nNextMarkIndex;
1064     }
1065 
1066     if (nMovePos > nCurrentIndex)
1067     {
1068         pUnoCrsr->GetPoint()->nContent = static_cast<sal_uInt16>(nMovePos);
1069     }
1070 }
1071 
1072 //-----------------------------------------------------------------------------
lcl_FillRedlineArray(SwDoc const & rDoc,SwUnoCrsr const & rUnoCrsr,SwXRedlinePortion_ImplList & rRedArr)1073 static void lcl_FillRedlineArray(
1074     SwDoc const & rDoc,
1075     SwUnoCrsr const & rUnoCrsr,
1076     SwXRedlinePortion_ImplList& rRedArr )
1077 {
1078     const SwRedlineTbl& rRedTbl = rDoc.GetRedlineTbl();
1079     sal_uInt16 nRedTblCount = rRedTbl.Count();
1080 
1081     if ( nRedTblCount > 0 )
1082     {
1083         const SwPosition* pStart = rUnoCrsr.GetPoint();
1084         const SwNodeIndex nOwnNode = pStart->nNode;
1085 
1086         for(sal_uInt16 nRed = 0; nRed < nRedTblCount; nRed++)
1087         {
1088             const SwRedline* pRedline = rRedTbl[nRed];
1089             const SwPosition* pRedStart = pRedline->Start();
1090             const SwNodeIndex nRedNode = pRedStart->nNode;
1091             if ( nOwnNode == nRedNode )
1092                 rRedArr.insert( SwXRedlinePortion_ImplSharedPtr (
1093                     new SwXRedlinePortion_Impl ( pRedline, true ) ) );
1094             if( pRedline->HasMark() && pRedline->End()->nNode == nOwnNode )
1095                 rRedArr.insert( SwXRedlinePortion_ImplSharedPtr (
1096                     new SwXRedlinePortion_Impl ( pRedline, false) ) );
1097        }
1098     }
1099 }
1100 
1101 //-----------------------------------------------------------------------------
lcl_FillSoftPageBreakArray(SwUnoCrsr const & rUnoCrsr,SwSoftPageBreakList & rBreakArr)1102 static void lcl_FillSoftPageBreakArray(
1103     SwUnoCrsr const & rUnoCrsr,
1104     SwSoftPageBreakList& rBreakArr )
1105 {
1106     const SwTxtNode *pTxtNode =
1107         rUnoCrsr.GetPoint()->nNode.GetNode().GetTxtNode();
1108     if( pTxtNode )
1109         pTxtNode->fillSoftPageBreakList( rBreakArr );
1110 }
1111 
1112 /* -----------------------------19.12.00 12:25--------------------------------
1113 
1114  ---------------------------------------------------------------------------*/
lcl_ExportRedline(TextRangeList_t & rPortions,Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,SwXRedlinePortion_ImplList & rRedlineArr,const xub_StrLen nIndex)1115 static void lcl_ExportRedline(
1116     TextRangeList_t & rPortions,
1117     Reference<XText> const& xParent,
1118     const SwUnoCrsr * const pUnoCrsr,
1119     SwXRedlinePortion_ImplList& rRedlineArr,
1120     const xub_StrLen nIndex)
1121 {
1122 
1123     // MTG: 23/11/05: We want this loop to iterate over all red lines in this
1124     // array. We will only insert the ones with index matches
1125     for ( SwXRedlinePortion_ImplList::iterator aIter = rRedlineArr.begin(), aEnd = rRedlineArr.end();
1126           aIter != aEnd; )
1127     {
1128         SwXRedlinePortion_ImplSharedPtr pPtr = (*aIter );
1129         sal_uLong nRealIndex = pPtr->getRealIndex();
1130         // MTG: 23/11/05: If there are elements before nIndex, remove them
1131         if ( nIndex > nRealIndex )
1132             rRedlineArr.erase ( aIter++ );
1133         // MTG: 23/11/05: If the elements match, and them to the list
1134         else if ( nIndex == nRealIndex )
1135         {
1136             rPortions.push_back( new SwXRedlinePortion(
1137                         pPtr->m_pRedline, pUnoCrsr, xParent, pPtr->m_bStart) );
1138             rRedlineArr.erase ( aIter++ );
1139         }
1140         // MTG: 23/11/05: If we've iterated past nIndex, exit the loop
1141         else
1142             break;
1143     }
1144 }
1145 
1146 /* -----------------------------19.12.00 13:09--------------------------------
1147 
1148  ---------------------------------------------------------------------------*/
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)1149 static void lcl_ExportBkmAndRedline(
1150     TextRangeList_t & rPortions,
1151     Reference<XText> const & xParent,
1152     const SwUnoCrsr * const pUnoCrsr,
1153     SwXBookmarkPortion_ImplList& rBkmArr,
1154     SwXRedlinePortion_ImplList& rRedlineArr,
1155     SwSoftPageBreakList& rBreakArr,
1156     const xub_StrLen nIndex )
1157 {
1158     if (rBkmArr.size())
1159         lcl_ExportBookmark(rPortions, xParent, pUnoCrsr, rBkmArr, nIndex);
1160 
1161     if (rRedlineArr.size())
1162         lcl_ExportRedline(rPortions, xParent, pUnoCrsr, rRedlineArr, nIndex);
1163 
1164     if (rBreakArr.size())
1165         lcl_ExportSoftPageBreak(rPortions, xParent, pUnoCrsr, rBreakArr, nIndex);
1166 }
1167 
lcl_ExportAnnotationStarts(TextRangeList_t & rPortions,Reference<XText> const & xParent,const SwUnoCrsr * const pUnoCrsr,SwAnnotationStartPortion_ImplList & rAnnotationStartArr,const xub_StrLen nIndex)1168 static void lcl_ExportAnnotationStarts(
1169     TextRangeList_t & rPortions,
1170     Reference<XText> const & xParent,
1171     const SwUnoCrsr * const pUnoCrsr,
1172     SwAnnotationStartPortion_ImplList& rAnnotationStartArr,
1173     const xub_StrLen nIndex)
1174 {
1175     if ( rAnnotationStartArr.size() > 0 )
1176     {
1177         for ( SwAnnotationStartPortion_ImplList::iterator aIter = rAnnotationStartArr.begin(), aEnd = rAnnotationStartArr.end();
1178               aIter != aEnd; )
1179         {
1180             SwAnnotationStartPortion_ImplSharedPtr pPtr = (*aIter);
1181             if ( nIndex > pPtr->getIndex() )
1182             {
1183                 rAnnotationStartArr.erase( aIter++ );
1184                 continue;
1185             }
1186             if ( pPtr->getIndex() > nIndex )
1187             {
1188                 break;
1189             }
1190 
1191             SwXTextPortion* pPortion =
1192                 new SwXTextPortion( pUnoCrsr, xParent, PORTION_ANNOTATION );
1193             pPortion->SetTextField( pPtr->mxAnnotationField );
1194             rPortions.push_back(pPortion);
1195 
1196             rAnnotationStartArr.erase( aIter++ );
1197         }
1198     }
1199 }
1200 
1201 //-----------------------------------------------------------------------------
lcl_ExportFrames(TextRangeList_t & rPortions,Reference<XText> const & i_xParent,SwUnoCrsr * const i_pUnoCrsr,FrameDependSortList_t & i_rFrames,xub_StrLen const i_nCurrentIndex)1202 static sal_Int32 lcl_ExportFrames(
1203     TextRangeList_t & rPortions,
1204     Reference<XText> const & i_xParent,
1205     SwUnoCrsr * const i_pUnoCrsr,
1206     FrameDependSortList_t & i_rFrames,
1207     xub_StrLen const i_nCurrentIndex)
1208 {
1209     // find first Frame in (sorted) i_rFrames at current position
1210     while (i_rFrames.size() && (i_rFrames.front().nIndex == i_nCurrentIndex))
1211     // do not check for i_nEnd here; this is done implicity by lcl_MoveCursor
1212     {
1213         const SwModify * const pFrame =
1214             i_rFrames.front().pFrameDepend->GetRegisteredIn();
1215         if (pFrame) // Frame could be disposed
1216         {
1217             SwXTextPortion* pPortion = new SwXTextPortion(i_pUnoCrsr, i_xParent,
1218                 *static_cast<SwFrmFmt*>( const_cast<SwModify*>( pFrame ) ) );
1219             rPortions.push_back(pPortion);
1220         }
1221         i_rFrames.pop_front();
1222     }
1223 
1224     return i_rFrames.size() ? i_rFrames.front().nIndex : -1;
1225 }
1226 
1227 //-----------------------------------------------------------------------------
lcl_GetNextIndex(SwXBookmarkPortion_ImplList const & rBkmArr,SwXRedlinePortion_ImplList const & rRedlineArr,SwSoftPageBreakList const & rBreakArr)1228 static sal_Int32 lcl_GetNextIndex(
1229     SwXBookmarkPortion_ImplList const & rBkmArr,
1230     SwXRedlinePortion_ImplList const & rRedlineArr,
1231     SwSoftPageBreakList const & rBreakArr )
1232 {
1233     sal_Int32 nRet = -1;
1234     if(rBkmArr.size())
1235     {
1236         SwXBookmarkPortion_ImplSharedPtr pPtr = (*rBkmArr.begin());
1237         nRet = pPtr->getIndex();
1238     }
1239     if(rRedlineArr.size())
1240     {
1241         SwXRedlinePortion_ImplSharedPtr pPtr = (*rRedlineArr.begin());
1242         sal_Int32 nTmp = pPtr->getRealIndex();
1243         if(nRet < 0 || nTmp < nRet)
1244             nRet = nTmp;
1245     }
1246     if(rBreakArr.size())
1247     {
1248         if(nRet < 0 || *rBreakArr.begin() < static_cast<sal_uInt32>(nRet))
1249             nRet = *rBreakArr.begin();
1250     }
1251     return nRet;
1252 };
1253 
1254 //-----------------------------------------------------------------------------
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)1255 static void lcl_CreatePortions(
1256     TextRangeList_t & i_rPortions,
1257     uno::Reference< text::XText > const & i_xParentText,
1258     SwUnoCrsr * const pUnoCrsr,
1259     FrameDependSortList_t & i_rFrames,
1260     const sal_Int32 i_nStartPos,
1261     const sal_Int32 i_nEndPos )
1262 {
1263     if (!pUnoCrsr)
1264         return;
1265 
1266     // set the start if a selection should be exported
1267     if ((i_nStartPos > 0) &&
1268         (pUnoCrsr->Start()->nContent.GetIndex() != i_nStartPos))
1269     {
1270         pUnoCrsr->DeleteMark();
1271         DBG_ASSERT(pUnoCrsr->Start()->nNode.GetNode().GetTxtNode() &&
1272             (i_nStartPos <= pUnoCrsr->Start()->nNode.GetNode().GetTxtNode()->
1273                                 GetTxt().Len()), "Incorrect start position" );
1274         // ??? should this be i_nStartPos - current position ?
1275         pUnoCrsr->Right(static_cast<xub_StrLen>(i_nStartPos),
1276                 CRSR_SKIP_CHARS, sal_False, sal_False);
1277     }
1278 
1279     SwDoc * const pDoc = pUnoCrsr->GetDoc();
1280 
1281     FieldMarks_t FieldMarks;
1282     lcl_FillFieldMarkArray(FieldMarks, *pUnoCrsr, i_nStartPos);
1283 
1284     SwXBookmarkPortion_ImplList Bookmarks;
1285     lcl_FillBookmarkArray(*pDoc, *pUnoCrsr, Bookmarks);
1286 
1287     SwXRedlinePortion_ImplList Redlines;
1288     lcl_FillRedlineArray(*pDoc, *pUnoCrsr, Redlines);
1289 
1290     SwSoftPageBreakList SoftPageBreaks;
1291     lcl_FillSoftPageBreakArray(*pUnoCrsr, SoftPageBreaks);
1292 
1293     SwAnnotationStartPortion_ImplList AnnotationStarts;
1294     lcl_FillAnnotationStartArray( *pDoc, *pUnoCrsr, AnnotationStarts );
1295 
1296     PortionStack_t PortionStack;
1297     PortionStack.push( PortionList_t(&i_rPortions, 0) );
1298 
1299     bool bAtEnd( false );
1300     while (!bAtEnd) // every iteration consumes at least current character!
1301     {
1302         if (pUnoCrsr->HasMark())
1303         {
1304             pUnoCrsr->Normalize(sal_False);
1305             pUnoCrsr->DeleteMark();
1306         }
1307 
1308         SwTxtNode * const pTxtNode = pUnoCrsr->GetNode()->GetTxtNode();
1309         if (!pTxtNode)
1310         {
1311             DBG_ERROR("lcl_CreatePortions: no TextNode - what now ?");
1312             return;
1313         }
1314 
1315         SwpHints * const pHints = pTxtNode->GetpSwpHints();
1316         const xub_StrLen nCurrentIndex =
1317             pUnoCrsr->GetPoint()->nContent.GetIndex();
1318         // this contains the portion which consumes the character in the
1319         // text at nCurrentIndex; i.e. it must be set _once_ per iteration
1320         uno::Reference< XTextRange > xRef;
1321 
1322         SwUnoCursorHelper::SelectPam(*pUnoCrsr, true); // set mark
1323 
1324         const sal_Int32 nFirstFrameIndex =
1325             lcl_ExportFrames( *PortionStack.top().first,
1326                 i_xParentText, pUnoCrsr, i_rFrames, nCurrentIndex);
1327 
1328         lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText,
1329             pUnoCrsr, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex );
1330 
1331         lcl_ExportAnnotationStarts(
1332             *PortionStack.top().first,
1333             i_xParentText,
1334             pUnoCrsr,
1335             AnnotationStarts,
1336             nCurrentIndex );
1337 
1338         bool bCursorMoved( false );
1339         sal_Int32 nNextAttrIndex = -1;
1340         // #111716# the cursor must not move right at the
1341         //          end position of a selection!
1342         bAtEnd = ((i_nEndPos >= 0) && (nCurrentIndex >= i_nEndPos))
1343               || (nCurrentIndex >= pTxtNode->Len());
1344         if (pHints)
1345         {
1346             // N.B.: side-effects nNextAttrIndex, bCursorMoved; may move cursor
1347             xRef = lcl_ExportHints(PortionStack, i_xParentText, pUnoCrsr,
1348                         pHints, i_nStartPos, i_nEndPos, nCurrentIndex, bAtEnd,
1349                         bCursorMoved, nNextAttrIndex);
1350             if (PortionStack.empty())
1351             {
1352                 ASSERT(false, "CreatePortions: stack underflow");
1353                 return;
1354             }
1355         }
1356 
1357         if (!xRef.is() && !bCursorMoved)
1358         {
1359             if (!bAtEnd &&
1360                 FieldMarks.size() && (FieldMarks.front() == nCurrentIndex))
1361             {
1362                 // moves cursor
1363                 xRef = lcl_ExportFieldMark(i_xParentText, pUnoCrsr, pTxtNode);
1364                 FieldMarks.pop_front();
1365             }
1366         }
1367         else
1368         {
1369             ASSERT(!FieldMarks.size() ||
1370                    (FieldMarks.front() != nCurrentIndex),
1371                    "fieldmark and hint with CH_TXTATR at same pos?");
1372         }
1373 
1374         if (!bAtEnd && !xRef.is() && !bCursorMoved)
1375         {
1376             const sal_Int32 nNextPortionIndex =
1377                 lcl_GetNextIndex(Bookmarks, Redlines, SoftPageBreaks);
1378 
1379             sal_Int32 nNextMarkIndex = ( FieldMarks.size() ? FieldMarks.front() : -1 );
1380             if ( AnnotationStarts.size() > 0
1381                  && ( nNextMarkIndex == -1
1382                       || (*AnnotationStarts.begin())->getIndex() < nNextMarkIndex ) )
1383             {
1384                 nNextMarkIndex = (*AnnotationStarts.begin())->getIndex();
1385             }
1386 
1387             lcl_MoveCursor(
1388                 pUnoCrsr,
1389                 nCurrentIndex,
1390                 nFirstFrameIndex,
1391                 nNextPortionIndex,
1392                 nNextAttrIndex,
1393                 nNextMarkIndex,
1394                 i_nEndPos );
1395 
1396             xRef = new SwXTextPortion(pUnoCrsr, i_xParentText, PORTION_TEXT);
1397         }
1398         else if (bAtEnd && !xRef.is() && !pTxtNode->Len())
1399         {
1400             // special case: for an empty paragraph, we better put out a
1401             // text portion because there may be a hyperlink attribute
1402             xRef = new SwXTextPortion(pUnoCrsr, i_xParentText, PORTION_TEXT);
1403         }
1404 
1405         if (xRef.is())
1406         {
1407             PortionStack.top().first->push_back(xRef);
1408         }
1409     }
1410 
1411     ASSERT((PortionStack.size() == 1) && !PortionStack.top().second,
1412             "CreatePortions: stack error" );
1413 }
1414 
1415 /*-- 27.01.99 10:44:45---------------------------------------------------
1416 
1417   -----------------------------------------------------------------------*/
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)1418 void    SwXTextPortionEnumeration::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew)
1419 {
1420     ClientModify(this, pOld, pNew);
1421 }
1422