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