xref: /aoo42x/main/sw/source/core/doc/docbm.cxx (revision edfeb9b7)
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 <MarkManager.hxx>
29 #include <bookmrk.hxx>
30 #include <boost/bind.hpp>
31 #include <cntfrm.hxx>
32 #include <crossrefbookmark.hxx>
33 #include <annotationmark.hxx>
34 #include <dcontact.hxx>
35 #include <doc.hxx>
36 #include <docary.hxx>
37 #include <xmloff/odffields.hxx>
38 #include <editsh.hxx>
39 #include <errhdl.hxx>
40 #include <fmtanchr.hxx>
41 #include <frmfmt.hxx>
42 #include <functional>
43 #include <hintids.hxx>
44 #include <mvsave.hxx>
45 #include <ndtxt.hxx>
46 #include <node.hxx>
47 #include <pam.hxx>
48 #include <redline.hxx>
49 #include <rolbck.hxx>
50 #include <rtl/ustrbuf.hxx>
51 #include <rtl/ustring.hxx>
52 #include <sal/types.h>
53 #include <sortedobjs.hxx>
54 #include <sfx2/linkmgr.hxx>
55 #include <swserv.hxx>
56 #include <swundo.hxx>
57 #include <tools/pstm.hxx>
58 #include <unocrsr.hxx>
59 #include <viscrs.hxx>
60 #include <stdio.h>
61 
62 
63 using namespace ::sw::mark;
64 
65 namespace
66 {
67     static bool lcl_GreaterThan( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
68     {
69         return pIdx != NULL
70                ? ( rPos.nNode > rNdIdx
71                    || ( rPos.nNode == rNdIdx
72                         && rPos.nContent >= pIdx->GetIndex() ) )
73                : rPos.nNode >= rNdIdx;
74     }
75 
76     static bool lcl_Lower( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
77     {
78         return rPos.nNode < rNdIdx
79                || ( pIdx != NULL
80                     && rPos.nNode == rNdIdx
81                     && rPos.nContent < pIdx->GetIndex() );
82     }
83 
84     static bool lcl_MarkOrderingByStart(const IDocumentMarkAccess::pMark_t& rpFirst,
85         const IDocumentMarkAccess::pMark_t& rpSecond)
86     {
87         return rpFirst->GetMarkStart() < rpSecond->GetMarkStart();
88     }
89 
90     static bool lcl_MarkOrderingByEnd(const IDocumentMarkAccess::pMark_t& rpFirst,
91         const IDocumentMarkAccess::pMark_t& rpSecond)
92     {
93         return rpFirst->GetMarkEnd() < rpSecond->GetMarkEnd();
94     }
95 
96     static void lcl_InsertMarkSorted(IDocumentMarkAccess::container_t& io_vMarks,
97         const IDocumentMarkAccess::pMark_t& pMark)
98     {
99         io_vMarks.insert(
100             lower_bound(
101                 io_vMarks.begin(),
102                 io_vMarks.end(),
103                 pMark,
104                 &lcl_MarkOrderingByStart),
105             pMark);
106     }
107 
108     static inline ::std::auto_ptr<SwPosition> lcl_PositionFromCntntNode(
109         SwCntntNode * const pCntntNode,
110         const bool bAtEnd=false)
111     {
112         ::std::auto_ptr<SwPosition> pResult(new SwPosition(*pCntntNode));
113         pResult->nContent.Assign(pCntntNode, bAtEnd ? pCntntNode->Len() : 0);
114         return pResult;
115     }
116 
117     // return a position at the begin of rEnd, if it is a CntntNode
118     // else set it to the begin of the Node after rEnd, if there is one
119     // else set it to the end of the node before rStt
120     // else set it to the CntntNode of the Pos outside the Range
121     static inline ::std::auto_ptr<SwPosition> lcl_FindExpelPosition(
122         const SwNodeIndex& rStt,
123         const SwNodeIndex& rEnd,
124         const SwPosition& rOtherPosition)
125     {
126         SwCntntNode * pNode = rEnd.GetNode().GetCntntNode();
127         bool bPosAtEndOfNode = false;
128         if ( pNode == NULL)
129         {
130             SwNodeIndex aEnd = SwNodeIndex(rEnd);
131             pNode = rEnd.GetNodes().GoNext( &aEnd );
132             bPosAtEndOfNode = false;
133         }
134         if ( pNode == NULL )
135         {
136             SwNodeIndex aStt = SwNodeIndex(rStt);
137             pNode = rStt.GetNodes().GoPrevious(&aStt);
138             bPosAtEndOfNode = true;
139         }
140         if ( pNode != NULL )
141         {
142             return lcl_PositionFromCntntNode( pNode, bPosAtEndOfNode );
143         }
144 
145         return ::std::auto_ptr<SwPosition>(new SwPosition(rOtherPosition));
146     };
147 
148     static IMark* lcl_getMarkAfter(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos)
149     {
150         IDocumentMarkAccess::const_iterator_t pMarkAfter = upper_bound(
151             rMarks.begin(),
152             rMarks.end(),
153             rPos,
154             bind(&IMark::StartsAfter, _2, _1)); // finds the first that is starting after
155         if(pMarkAfter == rMarks.end()) return NULL;
156         return pMarkAfter->get();
157     };
158 
159     static IMark* lcl_getMarkBefore(const IDocumentMarkAccess::container_t& rMarks, const SwPosition& rPos)
160     {
161         // candidates from which to choose the mark before
162         IDocumentMarkAccess::container_t vCandidates;
163         // no need to consider marks starting after rPos
164         IDocumentMarkAccess::const_iterator_t pCandidatesEnd = upper_bound(
165             rMarks.begin(),
166             rMarks.end(),
167             rPos,
168             bind(&IMark::StartsAfter, _2, _1));
169         vCandidates.reserve(pCandidatesEnd - rMarks.begin());
170         // only marks ending before are candidates
171         remove_copy_if(
172             rMarks.begin(),
173             pCandidatesEnd,
174             back_inserter(vCandidates),
175             boost::bind( ::std::logical_not<bool>(), bind( &IMark::EndsBefore, _1, rPos ) ) );
176         // no candidate left => we are in front of the first mark or there are none
177         if(!vCandidates.size()) return NULL;
178         // return the highest (last) candidate using mark end ordering
179         return max_element(vCandidates.begin(), vCandidates.end(), &lcl_MarkOrderingByEnd)->get();
180     }
181 
182     static bool lcl_FixCorrectedMark(
183         const bool bChangedPos,
184         const bool bChangedOPos,
185         MarkBase* io_pMark )
186     {
187         if ( IDocumentMarkAccess::GetType(*io_pMark) == IDocumentMarkAccess::ANNOTATIONMARK )
188         {
189             // annotation marks are allowed to span a table cell range.
190             // but trigger sorting to be save
191             return true;
192         }
193 
194         if ( ( bChangedPos || bChangedOPos )
195              && io_pMark->IsExpanded()
196              && io_pMark->GetOtherMarkPos().nNode.GetNode().FindTableBoxStartNode() !=
197                     io_pMark->GetMarkPos().nNode.GetNode().FindTableBoxStartNode() )
198         {
199             if ( !bChangedOPos )
200             {
201                 io_pMark->SetMarkPos( io_pMark->GetOtherMarkPos() );
202             }
203             io_pMark->ClearOtherMarkPos();
204             DdeBookmark * const pDdeBkmk = dynamic_cast< DdeBookmark*>(io_pMark);
205             if ( pDdeBkmk != NULL
206                  && pDdeBkmk->IsServer() )
207             {
208                 pDdeBkmk->SetRefObject(NULL);
209             }
210             return true;
211         }
212         return false;
213     }
214 
215     static IDocumentMarkAccess::iterator_t lcl_FindMark(
216         IDocumentMarkAccess::container_t& rMarks,
217         const IDocumentMarkAccess::pMark_t& rpMarkToFind)
218     {
219         IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound(
220             rMarks.begin(), rMarks.end(),
221             rpMarkToFind, &lcl_MarkOrderingByStart);
222         // since there are usually not too many marks on the same start
223         // position, we are not doing a bisect search for the upper bound
224         // but instead start to iterate from pMarkLow directly
225         while(ppCurrentMark != rMarks.end() && **ppCurrentMark == *rpMarkToFind)
226         {
227             if(ppCurrentMark->get() == rpMarkToFind.get())
228             {
229                 //OSL_TRACE("found mark named '%s'",
230                 //    ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr());
231                 return ppCurrentMark;
232             }
233             ++ppCurrentMark;
234         }
235         // reached a mark starting on a later start pos or the end of the
236         // vector => not found
237         return rMarks.end();
238     };
239 
240     static IDocumentMarkAccess::iterator_t lcl_FindMarkAtPos(
241         IDocumentMarkAccess::container_t& rMarks,
242         const SwPosition& rPos,
243         const IDocumentMarkAccess::MarkType eType)
244     {
245         for(IDocumentMarkAccess::iterator_t ppCurrentMark = lower_bound(
246                 rMarks.begin(), rMarks.end(),
247                 rPos,
248                 bind(&IMark::StartsBefore, _1, _2));
249             ppCurrentMark != rMarks.end();
250             ++ppCurrentMark)
251         {
252             // Once we reach a mark starting after the target pos
253             // we do not need to continue
254             if(ppCurrentMark->get()->StartsAfter(rPos))
255                 break;
256             if(IDocumentMarkAccess::GetType(**ppCurrentMark) == eType)
257             {
258                 //OSL_TRACE("found mark named '%s'",
259                 //    ::rtl::OUStringToOString(ppCurrentMark->get()->GetName(), RTL_TEXTENCODING_UTF8).getStr());
260                 return ppCurrentMark;
261             }
262         }
263         // reached a mark starting on a later start pos or the end of the
264         // vector => not found
265         return rMarks.end();
266     };
267 
268     static IDocumentMarkAccess::const_iterator_t lcl_FindMarkByName(
269         const ::rtl::OUString& rName,
270         IDocumentMarkAccess::const_iterator_t ppMarksBegin,
271         IDocumentMarkAccess::const_iterator_t ppMarksEnd)
272     {
273         return find_if(
274             ppMarksBegin,
275             ppMarksEnd,
276             bind(&::rtl::OUString::equals, bind(&IMark::GetName, _1), rName));
277     }
278 
279 #if 0
280     static void lcl_DebugMarks(IDocumentMarkAccess::container_t vMarks)
281     {
282         OSL_TRACE("%d Marks", vMarks.size());
283         for(IDocumentMarkAccess::iterator_t ppMark = vMarks.begin();
284             ppMark != vMarks.end();
285             ppMark++)
286         {
287             IMark* pMark = ppMark->get();
288             ::rtl::OString sName = ::rtl::OUStringToOString(pMark->GetName(), RTL_TEXTENCODING_UTF8);
289             const SwPosition* const pStPos = &pMark->GetMarkStart();
290             const SwPosition* const pEndPos = &pMark->GetMarkEnd();
291             OSL_TRACE("%s %s %d,%d %d,%d",
292                 typeid(*pMark).name(),
293                 sName.getStr(),
294                 pStPos->nNode.GetIndex(),
295                 pStPos->nContent.GetIndex(),
296                 pEndPos->nNode.GetIndex(),
297                 pEndPos->nContent.GetIndex());
298         }
299     };
300 #endif
301 }
302 
303 IDocumentMarkAccess::MarkType IDocumentMarkAccess::GetType(const IMark& rBkmk)
304 {
305     const std::type_info* const pMarkTypeInfo = &typeid(rBkmk);
306     // not using dynamic_cast<> here for performance
307     if(*pMarkTypeInfo == typeid(UnoMark))
308         return UNO_BOOKMARK;
309     else if(*pMarkTypeInfo == typeid(DdeBookmark))
310         return DDE_BOOKMARK;
311     else if(*pMarkTypeInfo == typeid(Bookmark))
312         return BOOKMARK;
313     else if(*pMarkTypeInfo == typeid(CrossRefHeadingBookmark))
314         return CROSSREF_HEADING_BOOKMARK;
315     else if(*pMarkTypeInfo == typeid(CrossRefNumItemBookmark))
316         return CROSSREF_NUMITEM_BOOKMARK;
317     else if(*pMarkTypeInfo == typeid(AnnotationMark))
318         return ANNOTATIONMARK;
319     else if(*pMarkTypeInfo == typeid(TextFieldmark))
320         return TEXT_FIELDMARK;
321     else if(*pMarkTypeInfo == typeid(CheckboxFieldmark))
322         return CHECKBOX_FIELDMARK;
323     else if(*pMarkTypeInfo == typeid(NavigatorReminder))
324         return NAVIGATOR_REMINDER;
325     else
326     {
327         OSL_ENSURE(false,
328             "IDocumentMarkAccess::GetType(..)"
329             " - unknown MarkType. This needs to be fixed!");
330         return UNO_BOOKMARK;
331     }
332 }
333 
334 const ::rtl::OUString& IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix()
335 {
336     static const ::rtl::OUString CrossRefHeadingBookmarkNamePrefix = ::rtl::OUString::createFromAscii("__RefHeading__");
337 
338     return CrossRefHeadingBookmarkNamePrefix;
339 }
340 
341 bool SAL_DLLPUBLIC_EXPORT IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark( const SwPaM& rPaM )
342 {
343     bool bRet( false );
344 
345     bRet = rPaM.Start()->nNode.GetNode().IsTxtNode() &&
346            rPaM.Start()->nContent.GetIndex() == 0 &&
347            ( !rPaM.HasMark() ||
348              ( rPaM.GetMark()->nNode == rPaM.GetPoint()->nNode &&
349                rPaM.End()->nContent.GetIndex() == rPaM.End()->nNode.GetNode().GetTxtNode()->Len() ) );
350 
351     return bRet;
352 }
353 
354 namespace sw { namespace mark
355 {
356     MarkManager::MarkManager(SwDoc& rDoc)
357         : m_vAllMarks()
358         , m_vBookmarks()
359         , m_vFieldmarks()
360         , m_vAnnotationMarks()
361         , m_vCommonMarks()
362         , m_pDoc(&rDoc)
363     { }
364 
365 
366     ::sw::mark::IMark* MarkManager::makeMark(const SwPaM& rPaM,
367         const ::rtl::OUString& rName,
368         const IDocumentMarkAccess::MarkType eType)
369     {
370 #if 0
371         {
372             ::rtl::OString sName = ::rtl::OUStringToOString(rName, RTL_TEXTENCODING_UTF8);
373             const SwPosition* const pPos1 = rPaM.GetPoint();
374             const SwPosition* pPos2 = pPos1;
375             if(rPaM.HasMark())
376                 pPos2 = rPaM.GetMark();
377             OSL_TRACE("%s %d,%d %d,%d",
378                 sName.getStr(),
379                 pPos1->nNode.GetIndex(),
380                 pPos1->nContent.GetIndex(),
381                 pPos2->nNode.GetIndex(),
382                 pPos2->nContent.GetIndex());
383         }
384 #endif
385         // see for example _SaveCntntIdx, Shells
386         OSL_PRECOND(m_vAllMarks.size() < USHRT_MAX,
387             "MarkManager::makeMark(..)"
388             " - more than USHRT_MAX marks are not supported correctly");
389         // There should only be one CrossRefBookmark per Textnode per Type
390         OSL_PRECOND(
391             (eType != CROSSREF_NUMITEM_BOOKMARK && eType != CROSSREF_HEADING_BOOKMARK)
392             || (lcl_FindMarkAtPos(m_vBookmarks, *rPaM.GetPoint(), eType) == m_vBookmarks.end()),
393             "MarkManager::makeMark(..)"
394             " - creating duplicate CrossRefBookmark");
395 
396         // create mark
397         MarkBase* pMarkBase = NULL;
398         switch(eType)
399         {
400             case IDocumentMarkAccess::TEXT_FIELDMARK:
401                 pMarkBase = new TextFieldmark(rPaM);
402                 break;
403             case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
404                 pMarkBase = new CheckboxFieldmark(rPaM);
405                 break;
406             case IDocumentMarkAccess::NAVIGATOR_REMINDER:
407                 pMarkBase = new NavigatorReminder(rPaM);
408                 break;
409             case IDocumentMarkAccess::BOOKMARK:
410                 pMarkBase = new Bookmark(rPaM, KeyCode(), rName, ::rtl::OUString());
411                 break;
412             case IDocumentMarkAccess::DDE_BOOKMARK:
413                 pMarkBase = new DdeBookmark(rPaM);
414                 break;
415             case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
416                 pMarkBase = new CrossRefHeadingBookmark(rPaM, KeyCode(), rName, ::rtl::OUString());
417                 break;
418             case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
419                 pMarkBase = new CrossRefNumItemBookmark(rPaM, KeyCode(), rName, ::rtl::OUString());
420                 break;
421             case IDocumentMarkAccess::UNO_BOOKMARK:
422                 pMarkBase = new UnoMark(rPaM);
423                 break;
424             case IDocumentMarkAccess::ANNOTATIONMARK:
425                 pMarkBase = new AnnotationMark( rPaM, rName );
426                 break;
427         }
428         OSL_ENSURE( pMarkBase!=NULL,
429             "MarkManager::makeMark(..)"
430             " - Mark was not created.");
431 
432         pMark_t pMark = boost::shared_ptr<IMark>( pMarkBase);
433         if(pMark->GetMarkPos() != pMark->GetMarkStart())
434             pMarkBase->Swap();
435 
436         // for performance reasons, we trust UnoMarks to have a (generated) unique name
437         if ( eType != IDocumentMarkAccess::UNO_BOOKMARK )
438             pMarkBase->SetName( getUniqueMarkName( pMarkBase->GetName() ) );
439 
440         // register mark
441         lcl_InsertMarkSorted( m_vAllMarks, pMark );
442         switch(eType)
443         {
444             case IDocumentMarkAccess::BOOKMARK:
445             case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
446             case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
447                 lcl_InsertMarkSorted(m_vCommonMarks, pMark);
448                 // if(dynamic_cast<IBookmark*>)
449                 lcl_InsertMarkSorted(m_vBookmarks, pMark);
450                 break;
451             case IDocumentMarkAccess::TEXT_FIELDMARK:
452             case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
453                 lcl_InsertMarkSorted(m_vCommonMarks, pMark);
454                 // if(dynamic_cast<IFieldmark*>
455                 lcl_InsertMarkSorted(m_vFieldmarks, pMark);
456                 break;
457             case IDocumentMarkAccess::ANNOTATIONMARK:
458                 lcl_InsertMarkSorted( m_vAnnotationMarks, pMark );
459                 break;
460             case IDocumentMarkAccess::NAVIGATOR_REMINDER:
461             case IDocumentMarkAccess::DDE_BOOKMARK:
462             case IDocumentMarkAccess::UNO_BOOKMARK:
463                 lcl_InsertMarkSorted(m_vCommonMarks, pMark);
464                 // no special array for these
465                 break;
466         }
467         pMarkBase->InitDoc(m_pDoc);
468 #if 0
469         OSL_TRACE("--- makeType ---");
470         OSL_TRACE("Marks");
471         lcl_DebugMarks(m_vAllMarks);
472         OSL_TRACE("Bookmarks");
473         lcl_DebugMarks(m_vBookmarks);
474         OSL_TRACE("Fieldmarks");
475         lcl_DebugMarks(m_vFieldmarks);
476 #endif
477         return pMark.get();
478     }
479 
480 
481     ::sw::mark::IFieldmark* MarkManager::makeFieldBookmark(
482         const SwPaM& rPaM,
483         const rtl::OUString& rName,
484         const rtl::OUString& rType )
485     {
486         sw::mark::IMark* pMark =
487             makeMark( rPaM, rName, IDocumentMarkAccess::TEXT_FIELDMARK );
488         sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
489         pFieldMark->SetFieldname( rType );
490 
491         return pFieldMark;
492     }
493 
494 
495     ::sw::mark::IFieldmark* MarkManager::makeNoTextFieldBookmark(
496         const SwPaM& rPaM,
497         const rtl::OUString& rName,
498         const rtl::OUString& rType)
499     {
500         sw::mark::IMark* pMark = makeMark( rPaM, rName,
501                 IDocumentMarkAccess::CHECKBOX_FIELDMARK );
502         sw::mark::IFieldmark* pFieldMark = dynamic_cast<sw::mark::IFieldmark*>( pMark );
503         pFieldMark->SetFieldname( rType );
504 
505         return pFieldMark;
506     }
507 
508 
509     ::sw::mark::IMark* MarkManager::getMarkForTxtNode(
510         const SwTxtNode& rTxtNode,
511         const IDocumentMarkAccess::MarkType eType )
512     {
513         SwPosition aPos(rTxtNode);
514         aPos.nContent.Assign(&(const_cast<SwTxtNode&>(rTxtNode)), 0);
515         const iterator_t ppExistingMark = lcl_FindMarkAtPos(m_vBookmarks, aPos, eType);
516         if(ppExistingMark != m_vBookmarks.end())
517             return ppExistingMark->get();
518         const SwPaM aPaM(aPos);
519         return makeMark(aPaM, ::rtl::OUString(), eType);
520     }
521 
522 
523     sw::mark::IMark* MarkManager::makeAnnotationMark(
524         const SwPaM& rPaM,
525         const ::rtl::OUString& rName )
526     {
527         return makeMark( rPaM, rName, IDocumentMarkAccess::ANNOTATIONMARK );
528     }
529 
530     void MarkManager::repositionMark(
531         ::sw::mark::IMark* const io_pMark,
532         const SwPaM& rPaM)
533     {
534         OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc,
535             "<MarkManager::repositionMark(..)>"
536             " - Mark is not in my doc.");
537         MarkBase* const pMarkBase = dynamic_cast< MarkBase* >(io_pMark);
538         pMarkBase->SetMarkPos(*(rPaM.GetPoint()));
539         if(rPaM.HasMark())
540             pMarkBase->SetOtherMarkPos(*(rPaM.GetMark()));
541         else
542             pMarkBase->ClearOtherMarkPos();
543 
544         if(pMarkBase->GetMarkPos() != pMarkBase->GetMarkStart())
545             pMarkBase->Swap();
546 
547         sortMarks();
548     }
549 
550 
551     bool MarkManager::renameMark(
552         ::sw::mark::IMark* io_pMark,
553         const ::rtl::OUString& rNewName )
554     {
555         OSL_PRECOND(io_pMark->GetMarkPos().GetDoc() == m_pDoc,
556             "<MarkManager::repositionMark(..)>"
557             " - Mark is not in my doc.");
558         if ( io_pMark->GetName() == rNewName )
559             return true;
560         if ( findMark(rNewName) != m_vAllMarks.end() )
561             return false;
562         dynamic_cast< ::sw::mark::MarkBase* >(io_pMark)->SetName(rNewName);
563         return true;
564     }
565 
566 
567     void MarkManager::correctMarksAbsolute(
568         const SwNodeIndex& rOldNode,
569         const SwPosition& rNewPos,
570         const xub_StrLen nOffset)
571     {
572         const SwNode* const pOldNode = &rOldNode.GetNode();
573         SwPosition aNewPos(rNewPos);
574         aNewPos.nContent += nOffset;
575         bool isSortingNeeded = false;
576 
577         for(iterator_t ppMark = m_vAllMarks.begin();
578             ppMark != m_vAllMarks.end();
579             ppMark++)
580         {
581             ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
582             // is on position ??
583             bool bChangedPos = false;
584             if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
585             {
586                 pMark->SetMarkPos(aNewPos);
587                 bChangedPos = true;
588             }
589             bool bChangedOPos = false;
590             if (pMark->IsExpanded() &&
591                 &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
592             {
593                 pMark->SetMarkPos(aNewPos);
594                 bChangedOPos= true;
595             }
596             // illegal selection? collapse the mark and restore sorting later
597             isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
598         }
599 
600         // restore sorting if needed
601         if(isSortingNeeded)
602             sortMarks();
603 #if 0
604         OSL_TRACE("correctMarksAbsolute");
605         lcl_DebugMarks(m_vAllMarks);
606 #endif
607     }
608 
609 
610     void MarkManager::correctMarksRelative(const SwNodeIndex& rOldNode, const SwPosition& rNewPos, const xub_StrLen nOffset)
611     {
612         const SwNode* const pOldNode = &rOldNode.GetNode();
613         SwPosition aNewPos(rNewPos);
614         aNewPos.nContent += nOffset;
615         bool isSortingNeeded = false;
616 
617         for(iterator_t ppMark = m_vAllMarks.begin();
618             ppMark != m_vAllMarks.end();
619             ppMark++)
620         {
621             // is on position ??
622             bool bChangedPos = false, bChangedOPos = false;
623             ::sw::mark::MarkBase* const pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
624             if(&pMark->GetMarkPos().nNode.GetNode() == pOldNode)
625             {
626                 SwPosition aNewPosRel(aNewPos);
627                 aNewPosRel.nContent += pMark->GetMarkPos().nContent.GetIndex();
628                 pMark->SetMarkPos(aNewPosRel);
629                 bChangedPos = true;
630             }
631             if(pMark->IsExpanded() &&
632                 &pMark->GetOtherMarkPos().nNode.GetNode() == pOldNode)
633             {
634                 SwPosition aNewPosRel(aNewPos);
635                 aNewPosRel.nContent += pMark->GetOtherMarkPos().nContent.GetIndex();
636                 pMark->SetOtherMarkPos(aNewPosRel);
637                 bChangedOPos = true;
638             }
639             // illegal selection? collapse the mark and restore sorting later
640             isSortingNeeded |= lcl_FixCorrectedMark(bChangedPos, bChangedOPos, pMark);
641         }
642 
643         // restore sorting if needed
644         if(isSortingNeeded)
645             sortMarks();
646 #if 0
647         OSL_TRACE("correctMarksRelative");
648         lcl_DebugMarks(m_vAllMarks);
649 #endif
650     }
651 
652 
653     void MarkManager::deleteMarks(
654             const SwNodeIndex& rStt,
655             const SwNodeIndex& rEnd,
656             ::std::vector<SaveBookmark>* pSaveBkmk,
657             const SwIndex* pSttIdx,
658             const SwIndex* pEndIdx )
659     {
660         ::std::vector<const_iterator_t> vMarksToDelete;
661         bool bIsSortingNeeded = false;
662 
663         // boolean indicating, if at least one mark has been moved while colleting marks for deletion
664         bool bMarksMoved = false;
665 
666         // copy all bookmarks in the move area to a vector storing all position data as offset
667         // reassignment is performed after the move
668         for(iterator_t ppMark = m_vAllMarks.begin();
669             ppMark != m_vAllMarks.end();
670             ppMark++)
671         {
672             // navigator marks should not be moved
673             // TODO: Check if this might make them invalid
674             if(IDocumentMarkAccess::GetType(**ppMark) == NAVIGATOR_REMINDER)
675                 continue;
676 
677             ::sw::mark::MarkBase* pMark = dynamic_cast< ::sw::mark::MarkBase* >(ppMark->get());
678             // on position ??
679             bool bIsPosInRange = lcl_GreaterThan(pMark->GetMarkPos(), rStt, pSttIdx)
680                                  && lcl_Lower(pMark->GetMarkPos(), rEnd, pEndIdx);
681             bool bIsOtherPosInRange = pMark->IsExpanded()
682                                       && lcl_GreaterThan(pMark->GetOtherMarkPos(), rStt, pSttIdx)
683                                       && lcl_Lower(pMark->GetOtherMarkPos(), rEnd, pEndIdx);
684             // special case: completely in range, touching the end?
685             if ( pEndIdx != NULL
686                  && ( ( bIsOtherPosInRange
687                         && pMark->GetMarkPos().nNode == rEnd
688                         && pMark->GetMarkPos().nContent == *pEndIdx )
689                       || ( bIsPosInRange
690                            && pMark->IsExpanded()
691                            && pMark->GetOtherMarkPos().nNode == rEnd
692                            && pMark->GetOtherMarkPos().nContent == *pEndIdx ) ) )
693             {
694                 bIsPosInRange = true, bIsOtherPosInRange = true;
695             }
696 
697             if ( bIsPosInRange
698                  && ( bIsOtherPosInRange
699                       || !pMark->IsExpanded() ) )
700             {
701                 // completely in range
702 
703                 bool bDeleteMark = true;
704                 {
705                     switch ( IDocumentMarkAccess::GetType( *pMark ) )
706                     {
707                     case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
708                     case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
709                         // no delete of cross-reference bookmarks, if range is inside one paragraph
710                         bDeleteMark = rStt != rEnd;
711                         break;
712                     case IDocumentMarkAccess::UNO_BOOKMARK:
713                         // no delete of UNO mark, if it is not expanded and only touches the start of the range
714                         bDeleteMark = bIsOtherPosInRange
715                                       || pMark->IsExpanded()
716                                       || pSttIdx == NULL
717                                       || !( pMark->GetMarkPos().nNode == rStt
718                                             && pMark->GetMarkPos().nContent == *pSttIdx );
719                         break;
720                     default:
721                         bDeleteMark = true;
722                         break;
723                     }
724                 }
725 
726                 if ( bDeleteMark )
727                 {
728                     if ( pSaveBkmk )
729                     {
730                         pSaveBkmk->push_back( SaveBookmark( true, true, *pMark, rStt, pSttIdx ) );
731                     }
732                     vMarksToDelete.push_back(ppMark);
733                 }
734             }
735             else if ( bIsPosInRange ^ bIsOtherPosInRange )
736             {
737                 // the bookmark is partitially in the range
738                 // move position of that is in the range out of it
739 
740                 ::std::auto_ptr< SwPosition > pNewPos;
741                 {
742                     if ( pEndIdx != NULL )
743                     {
744                         pNewPos = ::std::auto_ptr< SwPosition >( new SwPosition( rEnd, *pEndIdx ) );
745                     }
746                     else
747                     {
748                         pNewPos =
749                             lcl_FindExpelPosition( rStt, rEnd, bIsPosInRange ? pMark->GetOtherMarkPos() : pMark->GetMarkPos() );
750                     }
751                 }
752 
753                 bool bMoveMark = true;
754                 {
755                     switch ( IDocumentMarkAccess::GetType( *pMark ) )
756                     {
757                     case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
758                     case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
759                         // no move of cross-reference bookmarks, if move occurs inside a certain node
760                         bMoveMark = pMark->GetMarkPos().nNode != pNewPos->nNode;
761                         break;
762                     case IDocumentMarkAccess::ANNOTATIONMARK:
763                         // no move of annotation marks, if method is called to collect deleted marks
764                         bMoveMark = pSaveBkmk == NULL;
765                         break;
766                     default:
767                         bMoveMark = true;
768                         break;
769                     }
770                 }
771                 if ( bMoveMark )
772                 {
773                     if ( bIsPosInRange )
774                         pMark->SetMarkPos(*pNewPos);
775                     else
776                         pMark->SetOtherMarkPos(*pNewPos);
777                     bMarksMoved = true;
778 
779                     // illegal selection? collapse the mark and restore sorting later
780                     bIsSortingNeeded |= lcl_FixCorrectedMark( bIsPosInRange, bIsOtherPosInRange, pMark );
781                 }
782             }
783         }
784 
785         // If needed, sort mark containers containing subsets of the marks in order to assure sorting.
786         // The sorting is critical for the deletion of a mark as it is searched in these container for deletion.
787         if ( vMarksToDelete.size() > 0 && bMarksMoved )
788         {
789             sortSubsetMarks();
790         }
791         // we just remembered the iterators to delete, so we do not need to search
792         // for the shared_ptr<> (the entry in m_vAllMarks) again
793         // reverse iteration, since erasing an entry invalidates iterators
794         // behind it (the iterators in vMarksToDelete are sorted)
795         for ( ::std::vector< const_iterator_t >::reverse_iterator pppMark = vMarksToDelete.rbegin();
796               pppMark != vMarksToDelete.rend();
797               ++pppMark )
798         {
799             deleteMark(*pppMark);
800         }
801 
802         if ( bIsSortingNeeded )
803         {
804             sortMarks();
805         }
806 
807 #if 0
808         OSL_TRACE("deleteMarks");
809         lcl_DebugMarks(m_vAllMarks);
810 #endif
811     }
812 
813 
814     void MarkManager::deleteMark(const const_iterator_t ppMark)
815     {
816         if(ppMark == m_vAllMarks.end()) return;
817 
818         switch(IDocumentMarkAccess::GetType(**ppMark))
819         {
820             case IDocumentMarkAccess::BOOKMARK:
821             case IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK:
822             case IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK:
823                 {
824                     IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark);
825                     if ( ppBookmark != m_vBookmarks.end() )
826                     {
827                         m_vBookmarks.erase(ppBookmark);
828                     }
829                     else
830                     {
831                         OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Bookmark not found in Bookmark container.");
832                     }
833 
834                     ppBookmark = lcl_FindMark(m_vCommonMarks, *ppMark);
835                     if ( ppBookmark != m_vCommonMarks.end() )
836                     {
837                         m_vCommonMarks.erase(ppBookmark);
838                     }
839                     else
840                     {
841                         OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Bookmark not found in common mark container.");
842                     }
843                 }
844                 break;
845 
846             case IDocumentMarkAccess::TEXT_FIELDMARK:
847             case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
848                 {
849                     IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark);
850                     if ( ppFieldmark != m_vFieldmarks.end() )
851                     {
852                         m_vFieldmarks.erase(ppFieldmark);
853                     }
854                     else
855                     {
856                         OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Fieldmark not found in Fieldmark container.");
857                     }
858 
859                     sw::mark::TextFieldmark* pTextFieldmark = dynamic_cast<sw::mark::TextFieldmark*>(ppMark->get());
860                     if ( pTextFieldmark )
861                     {
862                         pTextFieldmark->ReleaseDoc(m_pDoc);
863                     }
864 
865                     ppFieldmark = lcl_FindMark(m_vCommonMarks, *ppMark);
866                     if ( ppFieldmark != m_vCommonMarks.end() )
867                     {
868                         m_vCommonMarks.erase(ppFieldmark);
869                     }
870                     else
871                     {
872                         OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Fieldmark not found in common mark container.");
873                     }
874                 }
875                 break;
876 
877             case IDocumentMarkAccess::ANNOTATIONMARK:
878                 {
879                     IDocumentMarkAccess::iterator_t ppAnnotationMark = lcl_FindMark(m_vAnnotationMarks, *ppMark);
880                     if ( ppAnnotationMark != m_vAnnotationMarks.end() )
881                     {
882                         m_vAnnotationMarks.erase(ppAnnotationMark);
883                     }
884                     else
885                     {
886                         OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Annotation Mark not found in Annotation Mark container.");
887                     }
888                 }
889                 break;
890 
891             case IDocumentMarkAccess::NAVIGATOR_REMINDER:
892             case IDocumentMarkAccess::DDE_BOOKMARK:
893             case IDocumentMarkAccess::UNO_BOOKMARK:
894                 {
895                     IDocumentMarkAccess::iterator_t ppOtherMark = lcl_FindMark(m_vCommonMarks, *ppMark);
896                     if ( ppOtherMark != m_vCommonMarks.end() )
897                     {
898                         m_vCommonMarks.erase(ppOtherMark);
899                     }
900                     else
901                     {
902                         OSL_ENSURE( false, "<MarkManager::deleteMark(..)> - Navigator Reminder, DDE Mark or Uno Makr not found in common mark container.");
903                     }
904                 }
905                 break;
906         }
907         DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get());
908         if ( pDdeBookmark )
909         {
910             pDdeBookmark->DeregisterFromDoc(m_pDoc);
911         }
912         // keep a temporary instance of the to-be-deleted mark in order to avoid
913         // recursive deletion of the mark triggered via its destructor.
914         // the temporary hold instance assures that the mark is deleted after the
915         // mark container has been updated. Thus, the mark could not be found anymore
916         // in the mark container by other calls trying to recursively delete the mark.
917         iterator_t aToBeDeletedMarkIter = m_vAllMarks.begin() + (ppMark - m_vAllMarks.begin());
918         pMark_t pToBeDeletedMark = *aToBeDeletedMarkIter;
919         m_vAllMarks.erase( aToBeDeletedMarkIter );
920     }
921 
922     void MarkManager::deleteMark(const IMark* const pMark)
923     {
924         OSL_PRECOND(pMark->GetMarkPos().GetDoc() == m_pDoc,
925             "<MarkManager::repositionMark(..)>"
926             " - Mark is not in my doc.");
927         // finds the last Mark that is starting before pMark
928         // (pMarkLow < pMark)
929         iterator_t pMarkLow =
930             lower_bound(
931                 m_vAllMarks.begin(),
932                 m_vAllMarks.end(),
933                 pMark->GetMarkStart(),
934                 bind(&IMark::StartsBefore, _1, _2) );
935         iterator_t pMarkHigh = m_vAllMarks.end();
936         iterator_t pMarkFound =
937             find_if(
938                 pMarkLow,
939                 pMarkHigh,
940                 boost::bind( ::std::equal_to<const IMark*>(), bind(&boost::shared_ptr<IMark>::get, _1), pMark ) );
941         if(pMarkFound != pMarkHigh)
942             deleteMark(pMarkFound);
943     }
944 
945     void MarkManager::clearAllMarks()
946     {
947         m_vFieldmarks.clear();
948         m_vBookmarks.clear();
949 
950         m_vCommonMarks.clear();
951 
952         m_vAnnotationMarks.clear();
953 
954 #ifdef DEBUG
955         for(iterator_t pBkmk = m_vAllMarks.begin();
956             pBkmk != m_vAllMarks.end();
957             ++pBkmk)
958             OSL_ENSURE( pBkmk->unique(),
959                         "<MarkManager::clearAllMarks(..)> - a Bookmark is still in use.");
960 #endif
961         m_vAllMarks.clear();
962     }
963 
964     IDocumentMarkAccess::const_iterator_t MarkManager::findMark(const ::rtl::OUString& rName) const
965     {
966         return lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end());
967     }
968 
969     IDocumentMarkAccess::const_iterator_t MarkManager::findBookmark(const ::rtl::OUString& rName) const
970     {
971         return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end());
972     }
973 
974     IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksBegin() const
975         { return m_vAllMarks.begin(); }
976 
977     IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksEnd() const
978         { return m_vAllMarks.end(); }
979 
980     sal_Int32 MarkManager::getAllMarksCount() const
981         { return m_vAllMarks.size(); }
982 
983     IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksBegin() const
984         { return m_vBookmarks.begin(); }
985 
986     IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksEnd() const
987         { return m_vBookmarks.end(); }
988 
989     sal_Int32 MarkManager::getBookmarksCount() const
990         { return m_vBookmarks.size(); }
991 
992     IFieldmark* MarkManager::getFieldmarkFor(const SwPosition& rPos) const
993     {
994         const_iterator_t pFieldmark = find_if(
995             m_vFieldmarks.begin(),
996             m_vFieldmarks.end( ),
997             bind(&IMark::IsCoveringPosition, _1, rPos));
998         if(pFieldmark == m_vFieldmarks.end()) return NULL;
999         return dynamic_cast<IFieldmark*>(pFieldmark->get());
1000     }
1001 
1002     IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const
1003         { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
1004 
1005     IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const
1006         { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
1007 
1008 
1009     IDocumentMarkAccess::const_iterator_t MarkManager::getCommonMarksBegin() const
1010     {
1011         return m_vCommonMarks.begin();
1012     }
1013 
1014     IDocumentMarkAccess::const_iterator_t MarkManager::getCommonMarksEnd() const
1015     {
1016         return m_vCommonMarks.end();
1017     }
1018 
1019     sal_Int32 MarkManager::getCommonMarksCount() const
1020     {
1021         return m_vCommonMarks.size();
1022     }
1023 
1024 
1025     IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksBegin() const
1026     {
1027         return m_vAnnotationMarks.begin();
1028     }
1029 
1030     IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksEnd() const
1031     {
1032         return m_vAnnotationMarks.end();
1033     }
1034 
1035     sal_Int32 MarkManager::getAnnotationMarksCount() const
1036     {
1037         return m_vAnnotationMarks.size();
1038     }
1039 
1040     IDocumentMarkAccess::const_iterator_t MarkManager::findAnnotationMark( const ::rtl::OUString& rName ) const
1041     {
1042         return lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() );
1043     }
1044 
1045 
1046     ::rtl::OUString MarkManager::getUniqueMarkName(const ::rtl::OUString& rName) const
1047     {
1048         OSL_ENSURE(rName.getLength(),
1049             "<MarkManager::getUniqueMarkName(..)> - a name should be proposed");
1050         if ( findMark(rName) == getAllMarksEnd() )
1051         {
1052             return rName;
1053         }
1054 
1055         ::rtl::OUStringBuffer sBuf;
1056         ::rtl::OUString sTmp;
1057         for(sal_Int32 nCnt = 1; nCnt < SAL_MAX_INT32; nCnt++)
1058         {
1059             sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear();
1060             if ( findMark(sTmp) == getAllMarksEnd() )
1061             {
1062                 break;
1063             }
1064         }
1065         return sTmp;
1066     }
1067 
1068     void MarkManager::assureSortedMarkContainers() const
1069     {
1070         const_cast< MarkManager* >(this)->sortMarks();
1071     }
1072 
1073     void MarkManager::sortSubsetMarks()
1074     {
1075         sort(m_vCommonMarks.begin(), m_vCommonMarks.end(), &lcl_MarkOrderingByStart);
1076         sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart);
1077         sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart);
1078         sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart);
1079     }
1080 
1081     void MarkManager::sortMarks()
1082     {
1083         sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart);
1084         sortSubsetMarks();
1085     }
1086 
1087 #if OSL_DEBUG_LEVEL > 1
1088     void MarkManager::dumpFieldmarks( ) const
1089     {
1090         const_iterator_t pIt = m_vFieldmarks.begin();
1091         for (; pIt != m_vFieldmarks.end( ); pIt++)
1092         {
1093             rtl::OUString str = (*pIt)->ToString();
1094             OSL_TRACE("%s\n",
1095                 ::rtl::OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr());
1096         }
1097     }
1098 #endif
1099 
1100 }} // namespace ::sw::mark
1101 
1102 
1103 // old implementation
1104 
1105 //SV_IMPL_OP_PTRARR_SORT(SwBookmarks, SwBookmarkPtr)
1106 
1107 #define PCURCRSR (_pCurrCrsr)
1108 #define FOREACHPAM_START(pSttCrsr) \
1109 	{\
1110 		SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \
1111 		do {
1112 
1113 #define FOREACHPAM_END() \
1114 		} while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \
1115 	}
1116 #define PCURSH ((SwCrsrShell*)_pStartShell)
1117 #define FOREACHSHELL_START( pEShell ) \
1118     {\
1119 		ViewShell *_pStartShell = pEShell; \
1120 		do { \
1121 			if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \
1122 			{
1123 
1124 #define FOREACHSHELL_END( pEShell ) \
1125 			} \
1126         } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \
1127 	}
1128 
1129 namespace
1130 {
1131     // Aufbau vom Array: 2 longs,
1132     //	1. Long enthaelt Type und Position im DocArray,
1133     //	2. die ContentPosition
1134     //
1135     //	CntntType --
1136     //			0x8000 = Bookmark Pos1
1137     //			0x8001 = Bookmark Pos2
1138     //			0x2000 = Absatzgebundener Rahmen
1139     //			0x2001 = Auto-Absatzgebundener Rahmen, der umgehaengt werden soll
1140     //			0x1000 = Redline Mark
1141     //			0x1001 = Redline Point
1142     //			0x0800 = Crsr aus der CrsrShell Mark
1143     //			0x0801 = Crsr aus der CrsrShell Point
1144     //			0x0400 = UnoCrsr Mark
1145     //			0x0401 = UnoCrsr Point
1146     //
1147 
1148     class _SwSaveTypeCountContent
1149     {
1150         union {
1151             struct { sal_uInt16 nType, nCount; } TC;
1152             sal_uLong nTypeCount;
1153             } TYPECOUNT;
1154         xub_StrLen nContent;
1155 
1156     public:
1157         _SwSaveTypeCountContent() { TYPECOUNT.nTypeCount = 0; nContent = 0; }
1158         _SwSaveTypeCountContent( sal_uInt16 nType )
1159             {
1160                 SetTypeAndCount( nType, 0 );
1161                 nContent = 0;
1162             }
1163         _SwSaveTypeCountContent( const SvULongs& rArr, sal_uInt16& rPos )
1164             {
1165                 TYPECOUNT.nTypeCount = rArr[ rPos++ ];
1166                 nContent = static_cast<xub_StrLen>(rArr[ rPos++ ]);
1167             }
1168         void Add( SvULongs& rArr )
1169         {
1170             rArr.Insert( TYPECOUNT.nTypeCount, rArr.Count() );
1171             rArr.Insert( nContent, rArr.Count() );
1172         }
1173 
1174         void SetType( sal_uInt16 n )		{ TYPECOUNT.TC.nType = n; }
1175         sal_uInt16 GetType() const 			{ return TYPECOUNT.TC.nType; }
1176         void IncType() 	 				{ ++TYPECOUNT.TC.nType; }
1177         void DecType() 	 				{ --TYPECOUNT.TC.nType; }
1178 
1179         void SetCount( sal_uInt16 n ) 		{ TYPECOUNT.TC.nCount = n; }
1180         sal_uInt16 GetCount() const 		{ return TYPECOUNT.TC.nCount; }
1181         sal_uInt16 IncCount()  				{ return ++TYPECOUNT.TC.nCount; }
1182         sal_uInt16 DecCount()  				{ return --TYPECOUNT.TC.nCount; }
1183 
1184         void SetTypeAndCount( sal_uInt16 nT, sal_uInt16 nC )
1185             { TYPECOUNT.TC.nCount = nC; TYPECOUNT.TC.nType = nT; }
1186 
1187         void SetContent( xub_StrLen n )		{ nContent = n; }
1188         xub_StrLen GetContent() const		{ return nContent; }
1189     };
1190 
1191     // #i59534: If a paragraph will be splitted we have to restore some redline positions
1192     // This help function checks a position compared with a node and an content index
1193 
1194     static const int BEFORE_NODE = 0;          // Position before the given node index
1195     static const int BEFORE_SAME_NODE = 1;     // Same node index but content index before given content index
1196     static const int SAME_POSITION = 2;        // Same node index and samecontent index
1197     static const int BEHIND_SAME_NODE = 3;     // Same node index but content index behind given content index
1198     static const int BEHIND_NODE = 4;          // Position behind the given node index
1199 
1200     static int lcl_RelativePosition( const SwPosition& rPos, sal_uLong nNode, xub_StrLen nCntnt )
1201     {
1202         sal_uLong nIndex = rPos.nNode.GetIndex();
1203         int nReturn = BEFORE_NODE;
1204         if( nIndex == nNode )
1205         {
1206             xub_StrLen nCntIdx = rPos.nContent.GetIndex();
1207             if( nCntIdx < nCntnt )
1208                 nReturn = BEFORE_SAME_NODE;
1209             else if( nCntIdx == nCntnt )
1210                 nReturn = SAME_POSITION;
1211             else
1212                 nReturn = BEHIND_SAME_NODE;
1213         }
1214         else if( nIndex > nNode )
1215             nReturn = BEHIND_NODE;
1216         return nReturn;
1217     }
1218 
1219 
1220     static inline int lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
1221     {
1222         return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() );
1223     }
1224 
1225     static void lcl_ChkPaM( SvULongs& rSaveArr, sal_uLong nNode, xub_StrLen nCntnt,
1226                     const SwPaM& rPam, _SwSaveTypeCountContent& rSave,
1227                     sal_Bool bChkSelDirection )
1228     {
1229         // SelektionsRichtung beachten
1230         bool bBound1IsStart = !bChkSelDirection ? sal_True :
1231                             ( *rPam.GetPoint() < *rPam.GetMark()
1232                                 ? rPam.GetPoint() == &rPam.GetBound()
1233                                 : rPam.GetMark() == &rPam.GetBound());
1234 
1235         const SwPosition* pPos = &rPam.GetBound( sal_True );
1236         if( pPos->nNode.GetIndex() == nNode &&
1237             ( bBound1IsStart ? pPos->nContent.GetIndex() < nCntnt
1238                                 : pPos->nContent.GetIndex() <= nCntnt ))
1239         {
1240             rSave.SetContent( pPos->nContent.GetIndex() );
1241             rSave.Add( rSaveArr );
1242         }
1243 
1244         pPos = &rPam.GetBound( sal_False );
1245         if( pPos->nNode.GetIndex() == nNode &&
1246             ( (bBound1IsStart && bChkSelDirection)
1247                         ? pPos->nContent.GetIndex() <= nCntnt
1248                         : pPos->nContent.GetIndex() < nCntnt ))
1249         {
1250             rSave.SetContent( pPos->nContent.GetIndex() );
1251             rSave.IncType();
1252             rSave.Add( rSaveArr );
1253             rSave.DecType();
1254         }
1255     }
1256 
1257 }
1258 
1259 
1260 // IDocumentMarkAccess for SwDoc
1261 
1262 IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess()
1263     { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); }
1264 
1265 const IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() const
1266     { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); }
1267 
1268 // SaveBookmark
1269 
1270 SaveBookmark::SaveBookmark(
1271     bool bSavePos,
1272     bool bSaveOtherPos,
1273     const IMark& rBkmk,
1274     const SwNodeIndex & rMvPos,
1275     const SwIndex* pIdx)
1276     : m_aName(rBkmk.GetName())
1277     , m_aShortName()
1278     , m_aCode()
1279     , m_bSavePos(bSavePos)
1280     , m_bSaveOtherPos(bSaveOtherPos)
1281     , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk))
1282 {
1283     const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk);
1284     if(pBookmark)
1285     {
1286         m_aShortName = pBookmark->GetShortName();
1287         m_aCode = pBookmark->GetKeyCode();
1288 
1289         ::sfx2::Metadatable const*const pMetadatable(
1290                 dynamic_cast< ::sfx2::Metadatable const* >(pBookmark));
1291         if (pMetadatable)
1292         {
1293             m_pMetadataUndo = pMetadatable->CreateUndo();
1294         }
1295     }
1296     m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex();
1297     m_nCntnt1 = rBkmk.GetMarkPos().nContent.GetIndex();
1298 
1299     if(m_bSavePos)
1300     {
1301         m_nNode1 -= rMvPos.GetIndex();
1302         if(pIdx && !m_nNode1)
1303             m_nCntnt1 -= pIdx->GetIndex();
1304     }
1305 
1306     if(rBkmk.IsExpanded())
1307     {
1308         m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex();
1309         m_nCntnt2 = rBkmk.GetOtherMarkPos().nContent.GetIndex();
1310 
1311         if(m_bSaveOtherPos)
1312         {
1313             m_nNode2 -= rMvPos.GetIndex();
1314             if(pIdx && !m_nNode2)
1315                 m_nCntnt2 -= pIdx->GetIndex();
1316         }
1317     }
1318     else
1319         m_nNode2 = ULONG_MAX, m_nCntnt2 = STRING_NOTFOUND;
1320 }
1321 
1322 void SaveBookmark::SetInDoc(
1323     SwDoc* pDoc,
1324     const SwNodeIndex& rNewPos,
1325     const SwIndex* pIdx)
1326 {
1327     SwPaM aPam(rNewPos.GetNode());
1328     if(pIdx)
1329         aPam.GetPoint()->nContent = *pIdx;
1330 
1331     if(ULONG_MAX != m_nNode2)
1332     {
1333         aPam.SetMark();
1334 
1335         if(m_bSaveOtherPos)
1336         {
1337             aPam.GetMark()->nNode += m_nNode2;
1338             if(pIdx && !m_nNode2)
1339                 aPam.GetMark()->nContent += m_nCntnt2;
1340             else
1341                 aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2);
1342         }
1343         else
1344         {
1345             aPam.GetMark()->nNode = m_nNode2;
1346             aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2);
1347         }
1348     }
1349 
1350     if(m_bSavePos)
1351     {
1352         aPam.GetPoint()->nNode += m_nNode1;
1353 
1354         if(pIdx && !m_nNode1)
1355             aPam.GetPoint()->nContent += m_nCntnt1;
1356         else
1357             aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1);
1358     }
1359     else
1360     {
1361         aPam.GetPoint()->nNode = m_nNode1;
1362         aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1);
1363     }
1364 
1365     if(!aPam.HasMark()
1366         || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, sal_True))
1367     {
1368         ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName, m_eOrigBkmType));
1369         if(pBookmark)
1370         {
1371             pBookmark->SetKeyCode(m_aCode);
1372             pBookmark->SetShortName(m_aShortName);
1373             if (m_pMetadataUndo)
1374             {
1375                 ::sfx2::Metadatable * const pMeta(
1376                     dynamic_cast< ::sfx2::Metadatable* >(pBookmark));
1377                 OSL_ENSURE(pMeta, "metadata undo, but not metadatable?");
1378                 if (pMeta)
1379                 {
1380                     pMeta->RestoreMetadata(m_pMetadataUndo);
1381                 }
1382             }
1383         }
1384     }
1385 }
1386 
1387 
1388 // _DelBookmarks, _{Save,Restore}CntntIdx
1389 
1390 void _DelBookmarks(
1391     const SwNodeIndex& rStt,
1392     const SwNodeIndex& rEnd,
1393     ::std::vector<SaveBookmark> * pSaveBkmk,
1394     const SwIndex* pSttIdx,
1395     const SwIndex* pEndIdx)
1396 {
1397     // illegal range ??
1398     if(rStt.GetIndex() > rEnd.GetIndex()
1399         || (rStt == rEnd && (!pSttIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex())))
1400         return;
1401     SwDoc* const pDoc = rStt.GetNode().GetDoc();
1402 
1403     pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx);
1404 
1405     // kopiere alle Redlines, die im Move Bereich stehen in ein
1406     // Array, das alle Angaben auf die Position als Offset speichert.
1407     // Die neue Zuordung erfolgt nach dem Moven.
1408     SwRedlineTbl& rTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
1409     for(sal_uInt16 nCnt = 0; nCnt < rTbl.Count(); ++nCnt )
1410     {
1411         // liegt auf der Position ??
1412         SwRedline* pRedl = rTbl[ nCnt ];
1413 
1414         SwPosition *pRStt = &pRedl->GetBound(sal_True),
1415                    *pREnd = &pRedl->GetBound(sal_False);
1416         if( *pRStt > *pREnd )
1417         {
1418             SwPosition *pTmp = pRStt; pRStt = pREnd, pREnd = pTmp;
1419         }
1420 
1421         if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx ))
1422         {
1423             pRStt->nNode = rEnd;
1424             if( pEndIdx )
1425                 pRStt->nContent = *pEndIdx;
1426             else
1427             {
1428                 sal_Bool bStt = sal_True;
1429                 SwCntntNode* pCNd = pRStt->nNode.GetNode().GetCntntNode();
1430                 if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) )
1431                 {
1432                     bStt = sal_False;
1433                     pRStt->nNode = rStt;
1434                     if( 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pRStt->nNode )) )
1435                     {
1436                         pRStt->nNode = pREnd->nNode;
1437                         pCNd = pRStt->nNode.GetNode().GetCntntNode();
1438                     }
1439                 }
1440                 xub_StrLen nTmp = bStt ? 0 : pCNd->Len();
1441                 pRStt->nContent.Assign( pCNd, nTmp );
1442             }
1443         }
1444         if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx ))
1445         {
1446             pREnd->nNode = rStt;
1447             if( pSttIdx )
1448                 pREnd->nContent = *pSttIdx;
1449             else
1450             {
1451                 sal_Bool bStt = sal_False;
1452                 SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode();
1453                 if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pREnd->nNode )) )
1454                 {
1455                     bStt = sal_True;
1456                     pREnd->nNode = rEnd;
1457                     if( 0 == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) )
1458                     {
1459                         pREnd->nNode = pRStt->nNode;
1460                         pCNd = pREnd->nNode.GetNode().GetCntntNode();
1461                     }
1462                 }
1463                 xub_StrLen nTmp = bStt ? 0 : pCNd->Len();
1464                 pREnd->nContent.Assign( pCNd, nTmp );
1465             }
1466         }
1467     }
1468 }
1469 
1470 void _SaveCntntIdx(SwDoc* pDoc,
1471     sal_uLong nNode,
1472     xub_StrLen nCntnt,
1473     SvULongs& rSaveArr,
1474     sal_uInt8 nSaveFly)
1475 {
1476     // 1. Bookmarks
1477     _SwSaveTypeCountContent aSave;
1478     aSave.SetTypeAndCount( 0x8000, 0 );
1479 
1480     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1481     const sal_Int32 nMarksCount = pMarkAccess->getAllMarksCount();
1482     for ( ; aSave.GetCount() < nMarksCount; aSave.IncCount() )
1483     {
1484         bool bMarkPosEqual = false;
1485         const ::sw::mark::IMark* pBkmk = (pMarkAccess->getAllMarksBegin() + aSave.GetCount())->get();
1486         if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode
1487             && pBkmk->GetMarkPos().nContent.GetIndex() <= nCntnt)
1488         {
1489             if(pBkmk->GetMarkPos().nContent.GetIndex() < nCntnt)
1490             {
1491                 aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex());
1492                 aSave.Add(rSaveArr);
1493             }
1494             else // if a bookmark position is equal nCntnt, the other position
1495                 bMarkPosEqual = true; // has to decide if it is added to the array
1496         }
1497 
1498         if(pBkmk->IsExpanded()
1499             && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode
1500             && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nCntnt)
1501         {
1502             if(bMarkPosEqual)
1503             { // the other position is before, the (main) position is equal
1504                 aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex());
1505                 aSave.Add(rSaveArr);
1506             }
1507             aSave.SetContent(pBkmk->GetOtherMarkPos().nContent.GetIndex());
1508             aSave.IncType();
1509             aSave.Add(rSaveArr);
1510             aSave.DecType();
1511         }
1512     }
1513 
1514 	// 2. Redlines
1515 	aSave.SetTypeAndCount( 0x1000, 0 );
1516 	const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl();
1517 	for( ; aSave.GetCount() < rRedlTbl.Count(); aSave.IncCount() )
1518 	{
1519 		const SwRedline* pRdl = rRedlTbl[ aSave.GetCount() ];
1520         int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nCntnt );
1521         int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nCntnt ) :
1522                                           nPointPos;
1523         // #i59534: We have to store the positions inside the same node before the insert position
1524         // and the one at the insert position if the corresponding Point/Mark position is before
1525         // the insert position.
1526         if( nPointPos == BEFORE_SAME_NODE ||
1527             ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) )
1528 		{
1529 			aSave.SetContent( pRdl->GetPoint()->nContent.GetIndex() );
1530 			aSave.IncType();
1531 			aSave.Add( rSaveArr );
1532 			aSave.DecType();
1533 		}
1534 		if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE ||
1535             ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) )
1536         {
1537 			aSave.SetContent( pRdl->GetMark()->nContent.GetIndex() );
1538 			aSave.Add( rSaveArr );
1539 		}
1540 	}
1541 
1542 	// 4. Absatzgebundene Objekte
1543 	{
1544 		SwCntntNode *pNode = pDoc->GetNodes()[nNode]->GetCntntNode();
1545 		if( pNode )
1546 		{
1547 
1548 			SwFrm* pFrm = pNode->getLayoutFrm( pDoc->GetCurrentLayout() );
1549 #if OSL_DEBUG_LEVEL > 1
1550 			static sal_Bool bViaDoc = sal_False;
1551 			if( bViaDoc )
1552 				pFrm = NULL;
1553 #endif
1554 			if( pFrm ) // gibt es ein Layout? Dann ist etwas billiger...
1555 			{
1556 				if( pFrm->GetDrawObjs() )
1557 				{
1558                     const SwSortedObjs& rDObj = *pFrm->GetDrawObjs();
1559                     for( sal_uInt32 n = rDObj.Count(); n; )
1560 					{
1561                         SwAnchoredObject* pObj = rDObj[ --n ];
1562                         const SwFrmFmt& rFmt = pObj->GetFrmFmt();
1563                         const SwFmtAnchor& rAnchor = rFmt.GetAnchor();
1564                         SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
1565                         if ( pAPos &&
1566                              ( ( nSaveFly &&
1567                                  FLY_AT_PARA == rAnchor.GetAnchorId() ) ||
1568                                ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) )
1569                         {
1570 							aSave.SetType( 0x2000 );
1571 							aSave.SetContent( pAPos->nContent.GetIndex() );
1572 
1573 							OSL_ENSURE( nNode == pAPos->nNode.GetIndex(),
1574 									"_SaveCntntIdx: Wrong Node-Index" );
1575                             if ( FLY_AT_CHAR == rAnchor.GetAnchorId() )
1576 							{
1577 								if( nCntnt <= aSave.GetContent() )
1578 								{
1579 									if( SAVEFLY_SPLIT == nSaveFly )
1580 										aSave.IncType(); // = 0x2001;
1581 									else
1582 										continue;
1583 								}
1584 							}
1585 							aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() );
1586 							while( aSave.GetCount() &&
1587                                     &rFmt != (*pDoc->GetSpzFrmFmts())[
1588                                     aSave.DecCount() ] )
1589 								; // nothing
1590                             OSL_ENSURE( &rFmt == (*pDoc->GetSpzFrmFmts())[
1591 													aSave.GetCount() ],
1592 									"_SaveCntntIdx: Lost FrameFormat" );
1593 							aSave.Add( rSaveArr );
1594 						}
1595 					}
1596 				}
1597 			}
1598 			else // Schade, kein Layout, dann ist es eben etwas teurer...
1599 			{
1600 				for( aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() );
1601 						aSave.GetCount() ; )
1602 				{
1603 					SwFrmFmt* pFrmFmt = (*pDoc->GetSpzFrmFmts())[
1604 												aSave.DecCount() ];
1605 					if ( RES_FLYFRMFMT != pFrmFmt->Which() &&
1606 							RES_DRAWFRMFMT != pFrmFmt->Which() )
1607 						continue;
1608 
1609 					const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
1610                     SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
1611                     if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) &&
1612                          ( FLY_AT_PARA == rAnchor.GetAnchorId() ||
1613                            FLY_AT_CHAR == rAnchor.GetAnchorId() ) )
1614                     {
1615 						aSave.SetType( 0x2000 );
1616 						aSave.SetContent( pAPos->nContent.GetIndex() );
1617                         if ( FLY_AT_CHAR == rAnchor.GetAnchorId() )
1618 						{
1619 							if( nCntnt <= aSave.GetContent() )
1620 							{
1621 								if( SAVEFLY_SPLIT == nSaveFly )
1622 									aSave.IncType(); // = 0x2001;
1623 								else
1624 									continue;
1625 							}
1626 						}
1627 						aSave.Add( rSaveArr );
1628 					}
1629 				}
1630 			}
1631 		}
1632 	}
1633 	// 5. CrsrShell
1634 	{
1635 		SwCrsrShell* pShell = pDoc->GetEditShell();
1636 		if( pShell )
1637 		{
1638 			aSave.SetTypeAndCount( 0x800, 0 );
1639 			FOREACHSHELL_START( pShell )
1640 				SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
1641 				if( _pStkCrsr )
1642 				do {
1643 					lcl_ChkPaM( rSaveArr, nNode, nCntnt, *_pStkCrsr,
1644 								aSave, sal_False );
1645 					aSave.IncCount();
1646 				} while ( (_pStkCrsr != 0 ) &&
1647 					((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
1648 
1649 				FOREACHPAM_START( PCURSH->_GetCrsr() )
1650 					lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR,
1651 								aSave, sal_False );
1652 					aSave.IncCount();
1653 				FOREACHPAM_END()
1654 
1655 			FOREACHSHELL_END( pShell )
1656 		}
1657 	}
1658 	// 6. UnoCrsr
1659 	{
1660 		aSave.SetTypeAndCount( 0x400, 0 );
1661 		const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl();
1662 		for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
1663 		{
1664 			FOREACHPAM_START( rTbl[ n ] )
1665 				lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False );
1666 				aSave.IncCount();
1667 			FOREACHPAM_END()
1668 
1669             SwUnoTableCrsr* pUnoTblCrsr =
1670                 dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]);
1671 			if( pUnoTblCrsr )
1672 			{
1673 				FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
1674 					lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False );
1675 					aSave.IncCount();
1676 				FOREACHPAM_END()
1677 			}
1678 		}
1679 	}
1680 }
1681 
1682 
1683 void _RestoreCntntIdx(SwDoc* pDoc,
1684     SvULongs& rSaveArr,
1685     sal_uLong nNode,
1686     xub_StrLen nOffset,
1687     sal_Bool bAuto)
1688 {
1689 	SwCntntNode* pCNd = pDoc->GetNodes()[ nNode ]->GetCntntNode();
1690 	const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl();
1691 	SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts();
1692     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1693 	sal_uInt16 n = 0;
1694 	while( n < rSaveArr.Count() )
1695 	{
1696 		_SwSaveTypeCountContent aSave( rSaveArr, n );
1697 		SwPosition* pPos = 0;
1698         switch( aSave.GetType() )
1699         {
1700             case 0x8000:
1701             {
1702                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1703                 SwPosition aNewPos(pMark->GetMarkPos());
1704                 aNewPos.nNode = *pCNd;
1705                 aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset);
1706                 pMark->SetMarkPos(aNewPos);
1707             }
1708             break;
1709             case 0x8001:
1710             {
1711                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1712                 SwPosition aNewPos(pMark->GetOtherMarkPos());
1713                 aNewPos.nNode = *pCNd;
1714                 aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset);
1715                 pMark->SetOtherMarkPos(aNewPos);
1716             }
1717             break;
1718             case 0x1001:
1719                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint();
1720                 break;
1721             case 0x1000:
1722                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark();
1723                 break;
1724             case 0x2000:
1725                 {
1726                     SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ];
1727                     const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor();
1728                     if( rFlyAnchor.GetCntntAnchor() )
1729                     {
1730                         SwFmtAnchor aNew( rFlyAnchor );
1731                         SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() );
1732                         aNewPos.nNode = *pCNd;
1733                         if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() )
1734                         {
1735                             aNewPos.nContent.Assign( pCNd,
1736                                                      aSave.GetContent() + nOffset );
1737                         }
1738                         else
1739                         {
1740                             aNewPos.nContent.Assign( 0, 0 );
1741                         }
1742                         aNew.SetAnchor( &aNewPos );
1743                         pFrmFmt->SetFmtAttr( aNew );
1744                     }
1745                 }
1746                 break;
1747             case 0x2001:
1748                 if( bAuto )
1749                 {
1750                     SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ];
1751                     SfxPoolItem *pAnchor = (SfxPoolItem*)&pFrmFmt->GetAnchor();
1752                     pFrmFmt->NotifyClients( pAnchor, pAnchor );
1753                 }
1754                 break;
1755 
1756             case 0x0800:
1757             case 0x0801:
1758                 {
1759                     sal_uInt16 nCnt = 0;
1760                     SwCrsrShell* pShell = pDoc->GetEditShell();
1761                     if( pShell )
1762                     {
1763                         FOREACHSHELL_START( pShell )
1764                             SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
1765                             if( _pStkCrsr )
1766                             do {
1767                                 if( aSave.GetCount() == nCnt )
1768                                 {
1769                                     pPos = &_pStkCrsr->GetBound( 0x0800 ==
1770                                                         aSave.GetType() );
1771                                     break;
1772                                 }
1773                                 ++nCnt;
1774                             } while ( (_pStkCrsr != 0 ) &&
1775                                 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
1776 
1777                             if( pPos )
1778                                 break;
1779 
1780                             FOREACHPAM_START( PCURSH->_GetCrsr() )
1781                                 if( aSave.GetCount() == nCnt )
1782                                 {
1783                                     pPos = &PCURCRSR->GetBound( 0x0800 ==
1784                                                         aSave.GetType() );
1785                                     break;
1786                                 }
1787                                 ++nCnt;
1788                             FOREACHPAM_END()
1789                             if( pPos )
1790                                 break;
1791 
1792                         FOREACHSHELL_END( pShell )
1793                     }
1794             }
1795             break;
1796 
1797         case 0x0400:
1798         case 0x0401:
1799             {
1800                 sal_uInt16 nCnt = 0;
1801                 const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl();
1802                 for( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
1803                 {
1804                     FOREACHPAM_START( rTbl[ i ] )
1805                         if( aSave.GetCount() == nCnt )
1806                         {
1807                             pPos = &PCURCRSR->GetBound( 0x0400 ==
1808                                                     aSave.GetType() );
1809                             break;
1810                         }
1811                         ++nCnt;
1812                     FOREACHPAM_END()
1813                     if( pPos )
1814                         break;
1815 
1816                     SwUnoTableCrsr* pUnoTblCrsr =
1817                         dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]);
1818                     if ( pUnoTblCrsr )
1819                     {
1820                         FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
1821                             if( aSave.GetCount() == nCnt )
1822                             {
1823                                 pPos = &PCURCRSR->GetBound( 0x0400 ==
1824                                                     aSave.GetType() );
1825                                 break;
1826                             }
1827                             ++nCnt;
1828                         FOREACHPAM_END()
1829                     }
1830                     if ( pPos )
1831                         break;
1832                 }
1833             }
1834             break;
1835         }
1836 
1837         if( pPos )
1838         {
1839             pPos->nNode = *pCNd;
1840             pPos->nContent.Assign( pCNd, aSave.GetContent() + nOffset );
1841         }
1842     }
1843 }
1844 
1845 void _RestoreCntntIdx(SvULongs& rSaveArr,
1846     const SwNode& rNd,
1847     xub_StrLen nLen,
1848     xub_StrLen nChkLen)
1849 {
1850     const SwDoc* pDoc = rNd.GetDoc();
1851     const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl();
1852     const SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts();
1853     const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1854     SwCntntNode* pCNd = (SwCntntNode*)rNd.GetCntntNode();
1855 
1856     sal_uInt16 n = 0;
1857     while( n < rSaveArr.Count() )
1858     {
1859         _SwSaveTypeCountContent aSave( rSaveArr, n );
1860         if( aSave.GetContent() >= nChkLen )
1861             rSaveArr[ n-1 ] -= nChkLen;
1862         else
1863         {
1864             SwPosition* pPos = 0;
1865             switch( aSave.GetType() )
1866             {
1867             case 0x8000:
1868             {
1869                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1870                 SwPosition aNewPos(pMark->GetMarkPos());
1871                 aNewPos.nNode = rNd;
1872                 aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen));
1873                 pMark->SetMarkPos(aNewPos);
1874             }
1875             break;
1876             case 0x8001:
1877             {
1878                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1879                 SwPosition aNewPos(pMark->GetOtherMarkPos());
1880                 aNewPos.nNode = rNd;
1881                 aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen));
1882                 pMark->SetOtherMarkPos(aNewPos);
1883             }
1884             break;
1885             case 0x1001:
1886                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint();
1887                 break;
1888             case 0x1000:
1889                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark();
1890                 break;
1891             case 0x2000:
1892             case 0x2001:
1893                 {
1894                     SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ];
1895                     const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor();
1896                     if( rFlyAnchor.GetCntntAnchor() )
1897                     {
1898                         SwFmtAnchor aNew( rFlyAnchor );
1899                         SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() );
1900                         aNewPos.nNode = rNd;
1901                         if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() )
1902                         {
1903                             aNewPos.nContent.Assign( pCNd, Min(
1904                                                      aSave.GetContent(), nLen ) );
1905                         }
1906                         else
1907                         {
1908                             aNewPos.nContent.Assign( 0, 0 );
1909                         }
1910                         aNew.SetAnchor( &aNewPos );
1911                         pFrmFmt->SetFmtAttr( aNew );
1912                     }
1913                 }
1914                 break;
1915 
1916             case 0x0800:
1917             case 0x0801:
1918                 {
1919                     sal_uInt16 nCnt = 0;
1920                     SwCrsrShell* pShell = pDoc->GetEditShell();
1921                     if( pShell )
1922                     {
1923                         FOREACHSHELL_START( pShell )
1924                             SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
1925                             if( _pStkCrsr )
1926                             do {
1927                                 if( aSave.GetCount() == nCnt )
1928                                 {
1929                                     pPos = &_pStkCrsr->GetBound( 0x0800 ==
1930                                                 aSave.GetType() );
1931                                     break;
1932                                 }
1933                                 ++nCnt;
1934                             } while ( (_pStkCrsr != 0 ) &&
1935                                 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
1936 
1937                             if( pPos )
1938                                 break;
1939 
1940                             FOREACHPAM_START( PCURSH->_GetCrsr() )
1941                                 if( aSave.GetCount() == nCnt )
1942                                 {
1943                                     pPos = &PCURCRSR->GetBound( 0x0800 ==
1944                                                 aSave.GetType() );
1945                                     break;
1946                                 }
1947                                 ++nCnt;
1948                             FOREACHPAM_END()
1949                             if( pPos )
1950                                 break;
1951 
1952                         FOREACHSHELL_END( pShell )
1953                     }
1954                 }
1955                 break;
1956 
1957             case 0x0400:
1958             case 0x0401:
1959                 {
1960                     sal_uInt16 nCnt = 0;
1961                     const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl();
1962                     for( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
1963                     {
1964                         FOREACHPAM_START( rTbl[ i ] )
1965                             if( aSave.GetCount() == nCnt )
1966                             {
1967                                 pPos = &PCURCRSR->GetBound( 0x0400 ==
1968                                                     aSave.GetType() );
1969                                 break;
1970                             }
1971                             ++nCnt;
1972                         FOREACHPAM_END()
1973                         if( pPos )
1974                             break;
1975 
1976                         SwUnoTableCrsr* pUnoTblCrsr =
1977                             dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]);
1978                         if ( pUnoTblCrsr )
1979                         {
1980                             FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
1981                                 if( aSave.GetCount() == nCnt )
1982                                 {
1983                                     pPos = &PCURCRSR->GetBound( 0x0400 ==
1984                                                     aSave.GetType() );
1985                                     break;
1986                                 }
1987                                 ++nCnt;
1988                             FOREACHPAM_END()
1989                         }
1990                         if ( pPos )
1991                             break;
1992                     }
1993                 }
1994                 break;
1995             }
1996 
1997             if( pPos )
1998             {
1999                 pPos->nNode = rNd;
2000                 pPos->nContent.Assign( pCNd, Min( aSave.GetContent(), nLen ) );
2001             }
2002             n -= 2;
2003             rSaveArr.Remove( n, 2 );
2004         }
2005     }
2006 }
2007