xref: /trunk/main/sw/source/core/doc/docbm.cxx (revision fb3f75f2)
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                 // if(dynamic_cast<IBookmark*>)
824                 {
825                     IDocumentMarkAccess::iterator_t ppBookmark = lcl_FindMark(m_vBookmarks, *ppMark);
826                     OSL_ENSURE(ppBookmark != m_vBookmarks.end(),
827                         "<MarkManager::deleteMark(..)>"
828                         " - Bookmark not found.");
829                     m_vBookmarks.erase(ppBookmark);
830 
831                     ppBookmark = lcl_FindMark(m_vCommonMarks, *ppMark);
832                     m_vCommonMarks.erase(ppBookmark);
833                 }
834                 break;
835 
836             case IDocumentMarkAccess::TEXT_FIELDMARK:
837             case IDocumentMarkAccess::CHECKBOX_FIELDMARK:
838                 // if(dynamic_cast<IFieldmark*>
839                 {
840                     IDocumentMarkAccess::iterator_t ppFieldmark = lcl_FindMark(m_vFieldmarks, *ppMark);
841                     OSL_ENSURE(ppFieldmark != m_vFieldmarks.end(),
842                         "<MarkManager::deleteMark(..)>"
843                         " - Bookmark not found.");
844                     m_vFieldmarks.erase(ppFieldmark);
845 
846                     sw::mark::TextFieldmark* pTextFieldmark = dynamic_cast<sw::mark::TextFieldmark*>(ppMark->get());
847                     if ( pTextFieldmark )
848                     {
849                         pTextFieldmark->ReleaseDoc(m_pDoc);
850                     }
851 
852                     ppFieldmark = lcl_FindMark(m_vCommonMarks, *ppMark);
853                     m_vCommonMarks.erase(ppFieldmark);
854                 }
855                 break;
856 
857             case IDocumentMarkAccess::ANNOTATIONMARK:
858                 {
859                     IDocumentMarkAccess::iterator_t ppAnnotationMark = lcl_FindMark(m_vAnnotationMarks, *ppMark);
860                     OSL_ENSURE( ppAnnotationMark != m_vAnnotationMarks.end(), "<MarkManager::deleteMark(..)> - Annotation Mark not found." );
861                     m_vAnnotationMarks.erase(ppAnnotationMark);
862                 }
863                 break;
864 
865             case IDocumentMarkAccess::NAVIGATOR_REMINDER:
866             case IDocumentMarkAccess::DDE_BOOKMARK:
867             case IDocumentMarkAccess::UNO_BOOKMARK:
868                 {
869                     IDocumentMarkAccess::iterator_t ppOtherMark = lcl_FindMark(m_vCommonMarks, *ppMark);
870                     m_vCommonMarks.erase(ppOtherMark);
871                 }
872                 break;
873         }
874         DdeBookmark* const pDdeBookmark = dynamic_cast<DdeBookmark*>(ppMark->get());
875         if ( pDdeBookmark )
876         {
877             pDdeBookmark->DeregisterFromDoc(m_pDoc);
878         }
879         // keep a temporary instance of the to-be-deleted mark in order to avoid
880         // recursive deletion of the mark triggered via its destructor.
881         // the temporary hold instance assures that the mark is deleted after the
882         // mark container has been updated. Thus, the mark could not be found anymore
883         // in the mark container by other calls trying to recursively delete the mark.
884         iterator_t aToBeDeletedMarkIter = m_vAllMarks.begin() + (ppMark - m_vAllMarks.begin());
885         pMark_t pToBeDeletedMark = *aToBeDeletedMarkIter;
886         m_vAllMarks.erase( aToBeDeletedMarkIter );
887     }
888 
889     void MarkManager::deleteMark(const IMark* const pMark)
890     {
891         OSL_PRECOND(pMark->GetMarkPos().GetDoc() == m_pDoc,
892             "<MarkManager::repositionMark(..)>"
893             " - Mark is not in my doc.");
894         // finds the last Mark that is starting before pMark
895         // (pMarkLow < pMark)
896         iterator_t pMarkLow =
897             lower_bound(
898                 m_vAllMarks.begin(),
899                 m_vAllMarks.end(),
900                 pMark->GetMarkStart(),
901                 bind(&IMark::StartsBefore, _1, _2) );
902         iterator_t pMarkHigh = m_vAllMarks.end();
903         iterator_t pMarkFound =
904             find_if(
905                 pMarkLow,
906                 pMarkHigh,
907                 boost::bind( ::std::equal_to<const IMark*>(), bind(&boost::shared_ptr<IMark>::get, _1), pMark ) );
908         if(pMarkFound != pMarkHigh)
909             deleteMark(pMarkFound);
910     }
911 
912     void MarkManager::clearAllMarks()
913     {
914         m_vFieldmarks.clear();
915         m_vBookmarks.clear();
916 
917         m_vCommonMarks.clear();
918 
919         m_vAnnotationMarks.clear();
920 
921 #ifdef DEBUG
922         for(iterator_t pBkmk = m_vAllMarks.begin();
923             pBkmk != m_vAllMarks.end();
924             ++pBkmk)
925             OSL_ENSURE( pBkmk->unique(),
926                         "<MarkManager::clearAllMarks(..)> - a Bookmark is still in use.");
927 #endif
928         m_vAllMarks.clear();
929     }
930 
931     IDocumentMarkAccess::const_iterator_t MarkManager::findMark(const ::rtl::OUString& rName) const
932     {
933         return lcl_FindMarkByName(rName, m_vAllMarks.begin(), m_vAllMarks.end());
934     }
935 
936     IDocumentMarkAccess::const_iterator_t MarkManager::findBookmark(const ::rtl::OUString& rName) const
937     {
938         return lcl_FindMarkByName(rName, m_vBookmarks.begin(), m_vBookmarks.end());
939     }
940 
941     IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksBegin() const
942         { return m_vAllMarks.begin(); }
943 
944     IDocumentMarkAccess::const_iterator_t MarkManager::getAllMarksEnd() const
945         { return m_vAllMarks.end(); }
946 
947     sal_Int32 MarkManager::getAllMarksCount() const
948         { return m_vAllMarks.size(); }
949 
950     IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksBegin() const
951         { return m_vBookmarks.begin(); }
952 
953     IDocumentMarkAccess::const_iterator_t MarkManager::getBookmarksEnd() const
954         { return m_vBookmarks.end(); }
955 
956     sal_Int32 MarkManager::getBookmarksCount() const
957         { return m_vBookmarks.size(); }
958 
959     IFieldmark* MarkManager::getFieldmarkFor(const SwPosition& rPos) const
960     {
961         const_iterator_t pFieldmark = find_if(
962             m_vFieldmarks.begin(),
963             m_vFieldmarks.end( ),
964             bind(&IMark::IsCoveringPosition, _1, rPos));
965         if(pFieldmark == m_vFieldmarks.end()) return NULL;
966         return dynamic_cast<IFieldmark*>(pFieldmark->get());
967     }
968 
969     IFieldmark* MarkManager::getFieldmarkAfter(const SwPosition& rPos) const
970         { return dynamic_cast<IFieldmark*>(lcl_getMarkAfter(m_vFieldmarks, rPos)); }
971 
972     IFieldmark* MarkManager::getFieldmarkBefore(const SwPosition& rPos) const
973         { return dynamic_cast<IFieldmark*>(lcl_getMarkBefore(m_vFieldmarks, rPos)); }
974 
975 
976     IDocumentMarkAccess::const_iterator_t MarkManager::getCommonMarksBegin() const
977     {
978         return m_vCommonMarks.begin();
979     }
980 
981     IDocumentMarkAccess::const_iterator_t MarkManager::getCommonMarksEnd() const
982     {
983         return m_vCommonMarks.end();
984     }
985 
986     sal_Int32 MarkManager::getCommonMarksCount() const
987     {
988         return m_vCommonMarks.size();
989     }
990 
991 
992     IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksBegin() const
993     {
994         return m_vAnnotationMarks.begin();
995     }
996 
997     IDocumentMarkAccess::const_iterator_t MarkManager::getAnnotationMarksEnd() const
998     {
999         return m_vAnnotationMarks.end();
1000     }
1001 
1002     sal_Int32 MarkManager::getAnnotationMarksCount() const
1003     {
1004         return m_vAnnotationMarks.size();
1005     }
1006 
1007     IDocumentMarkAccess::const_iterator_t MarkManager::findAnnotationMark( const ::rtl::OUString& rName ) const
1008     {
1009         return lcl_FindMarkByName( rName, m_vAnnotationMarks.begin(), m_vAnnotationMarks.end() );
1010     }
1011 
1012 
1013     ::rtl::OUString MarkManager::getUniqueMarkName(const ::rtl::OUString& rName) const
1014     {
1015         OSL_ENSURE(rName.getLength(),
1016             "<MarkManager::getUniqueMarkName(..)> - a name should be proposed");
1017         if ( findMark(rName) == getAllMarksEnd() )
1018         {
1019             return rName;
1020         }
1021 
1022         ::rtl::OUStringBuffer sBuf;
1023         ::rtl::OUString sTmp;
1024         for(sal_Int32 nCnt = 1; nCnt < SAL_MAX_INT32; nCnt++)
1025         {
1026             sTmp = sBuf.append(rName).append(nCnt).makeStringAndClear();
1027             if ( findMark(sTmp) == getAllMarksEnd() )
1028             {
1029                 break;
1030             }
1031         }
1032         return sTmp;
1033     }
1034 
1035     void MarkManager::sortSubsetMarks()
1036     {
1037         sort(m_vCommonMarks.begin(), m_vCommonMarks.end(), &lcl_MarkOrderingByStart);
1038         sort(m_vBookmarks.begin(), m_vBookmarks.end(), &lcl_MarkOrderingByStart);
1039         sort(m_vFieldmarks.begin(), m_vFieldmarks.end(), &lcl_MarkOrderingByStart);
1040         sort(m_vAnnotationMarks.begin(), m_vAnnotationMarks.end(), &lcl_MarkOrderingByStart);
1041     }
1042 
1043     void MarkManager::sortMarks()
1044     {
1045         sort(m_vAllMarks.begin(), m_vAllMarks.end(), &lcl_MarkOrderingByStart);
1046         sortSubsetMarks();
1047     }
1048 
1049 #if OSL_DEBUG_LEVEL > 1
1050     void MarkManager::dumpFieldmarks( ) const
1051     {
1052         const_iterator_t pIt = m_vFieldmarks.begin();
1053         for (; pIt != m_vFieldmarks.end( ); pIt++)
1054         {
1055             rtl::OUString str = (*pIt)->ToString();
1056             OSL_TRACE("%s\n",
1057                 ::rtl::OUStringToOString(str, RTL_TEXTENCODING_UTF8).getStr());
1058         }
1059     }
1060 #endif
1061 
1062 }} // namespace ::sw::mark
1063 
1064 
1065 // old implementation
1066 
1067 //SV_IMPL_OP_PTRARR_SORT(SwBookmarks, SwBookmarkPtr)
1068 
1069 #define PCURCRSR (_pCurrCrsr)
1070 #define FOREACHPAM_START(pSttCrsr) \
1071 	{\
1072 		SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \
1073 		do {
1074 
1075 #define FOREACHPAM_END() \
1076 		} while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \
1077 	}
1078 #define PCURSH ((SwCrsrShell*)_pStartShell)
1079 #define FOREACHSHELL_START( pEShell ) \
1080     {\
1081 		ViewShell *_pStartShell = pEShell; \
1082 		do { \
1083 			if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \
1084 			{
1085 
1086 #define FOREACHSHELL_END( pEShell ) \
1087 			} \
1088         } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \
1089 	}
1090 
1091 namespace
1092 {
1093     // Aufbau vom Array: 2 longs,
1094     //	1. Long enthaelt Type und Position im DocArray,
1095     //	2. die ContentPosition
1096     //
1097     //	CntntType --
1098     //			0x8000 = Bookmark Pos1
1099     //			0x8001 = Bookmark Pos2
1100     //			0x2000 = Absatzgebundener Rahmen
1101     //			0x2001 = Auto-Absatzgebundener Rahmen, der umgehaengt werden soll
1102     //			0x1000 = Redline Mark
1103     //			0x1001 = Redline Point
1104     //			0x0800 = Crsr aus der CrsrShell Mark
1105     //			0x0801 = Crsr aus der CrsrShell Point
1106     //			0x0400 = UnoCrsr Mark
1107     //			0x0401 = UnoCrsr Point
1108     //
1109 
1110     class _SwSaveTypeCountContent
1111     {
1112         union {
1113             struct { sal_uInt16 nType, nCount; } TC;
1114             sal_uLong nTypeCount;
1115             } TYPECOUNT;
1116         xub_StrLen nContent;
1117 
1118     public:
1119         _SwSaveTypeCountContent() { TYPECOUNT.nTypeCount = 0; nContent = 0; }
1120         _SwSaveTypeCountContent( sal_uInt16 nType )
1121             {
1122                 SetTypeAndCount( nType, 0 );
1123                 nContent = 0;
1124             }
1125         _SwSaveTypeCountContent( const SvULongs& rArr, sal_uInt16& rPos )
1126             {
1127                 TYPECOUNT.nTypeCount = rArr[ rPos++ ];
1128                 nContent = static_cast<xub_StrLen>(rArr[ rPos++ ]);
1129             }
1130         void Add( SvULongs& rArr )
1131         {
1132             rArr.Insert( TYPECOUNT.nTypeCount, rArr.Count() );
1133             rArr.Insert( nContent, rArr.Count() );
1134         }
1135 
1136         void SetType( sal_uInt16 n )		{ TYPECOUNT.TC.nType = n; }
1137         sal_uInt16 GetType() const 			{ return TYPECOUNT.TC.nType; }
1138         void IncType() 	 				{ ++TYPECOUNT.TC.nType; }
1139         void DecType() 	 				{ --TYPECOUNT.TC.nType; }
1140 
1141         void SetCount( sal_uInt16 n ) 		{ TYPECOUNT.TC.nCount = n; }
1142         sal_uInt16 GetCount() const 		{ return TYPECOUNT.TC.nCount; }
1143         sal_uInt16 IncCount()  				{ return ++TYPECOUNT.TC.nCount; }
1144         sal_uInt16 DecCount()  				{ return --TYPECOUNT.TC.nCount; }
1145 
1146         void SetTypeAndCount( sal_uInt16 nT, sal_uInt16 nC )
1147             { TYPECOUNT.TC.nCount = nC; TYPECOUNT.TC.nType = nT; }
1148 
1149         void SetContent( xub_StrLen n )		{ nContent = n; }
1150         xub_StrLen GetContent() const		{ return nContent; }
1151     };
1152 
1153     // #i59534: If a paragraph will be splitted we have to restore some redline positions
1154     // This help function checks a position compared with a node and an content index
1155 
1156     static const int BEFORE_NODE = 0;          // Position before the given node index
1157     static const int BEFORE_SAME_NODE = 1;     // Same node index but content index before given content index
1158     static const int SAME_POSITION = 2;        // Same node index and samecontent index
1159     static const int BEHIND_SAME_NODE = 3;     // Same node index but content index behind given content index
1160     static const int BEHIND_NODE = 4;          // Position behind the given node index
1161 
1162     static int lcl_RelativePosition( const SwPosition& rPos, sal_uLong nNode, xub_StrLen nCntnt )
1163     {
1164         sal_uLong nIndex = rPos.nNode.GetIndex();
1165         int nReturn = BEFORE_NODE;
1166         if( nIndex == nNode )
1167         {
1168             xub_StrLen nCntIdx = rPos.nContent.GetIndex();
1169             if( nCntIdx < nCntnt )
1170                 nReturn = BEFORE_SAME_NODE;
1171             else if( nCntIdx == nCntnt )
1172                 nReturn = SAME_POSITION;
1173             else
1174                 nReturn = BEHIND_SAME_NODE;
1175         }
1176         else if( nIndex > nNode )
1177             nReturn = BEHIND_NODE;
1178         return nReturn;
1179     }
1180 
1181 
1182     static inline int lcl_Greater( const SwPosition& rPos, const SwNodeIndex& rNdIdx, const SwIndex* pIdx )
1183     {
1184         return rPos.nNode > rNdIdx || ( pIdx && rPos.nNode == rNdIdx && rPos.nContent > pIdx->GetIndex() );
1185     }
1186 
1187     static void lcl_ChkPaM( SvULongs& rSaveArr, sal_uLong nNode, xub_StrLen nCntnt,
1188                     const SwPaM& rPam, _SwSaveTypeCountContent& rSave,
1189                     sal_Bool bChkSelDirection )
1190     {
1191         // SelektionsRichtung beachten
1192         bool bBound1IsStart = !bChkSelDirection ? sal_True :
1193                             ( *rPam.GetPoint() < *rPam.GetMark()
1194                                 ? rPam.GetPoint() == &rPam.GetBound()
1195                                 : rPam.GetMark() == &rPam.GetBound());
1196 
1197         const SwPosition* pPos = &rPam.GetBound( sal_True );
1198         if( pPos->nNode.GetIndex() == nNode &&
1199             ( bBound1IsStart ? pPos->nContent.GetIndex() < nCntnt
1200                                 : pPos->nContent.GetIndex() <= nCntnt ))
1201         {
1202             rSave.SetContent( pPos->nContent.GetIndex() );
1203             rSave.Add( rSaveArr );
1204         }
1205 
1206         pPos = &rPam.GetBound( sal_False );
1207         if( pPos->nNode.GetIndex() == nNode &&
1208             ( (bBound1IsStart && bChkSelDirection)
1209                         ? pPos->nContent.GetIndex() <= nCntnt
1210                         : pPos->nContent.GetIndex() < nCntnt ))
1211         {
1212             rSave.SetContent( pPos->nContent.GetIndex() );
1213             rSave.IncType();
1214             rSave.Add( rSaveArr );
1215             rSave.DecType();
1216         }
1217     }
1218 
1219 }
1220 
1221 
1222 // IDocumentMarkAccess for SwDoc
1223 
1224 IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess()
1225     { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); }
1226 
1227 const IDocumentMarkAccess* SwDoc::getIDocumentMarkAccess() const
1228     { return static_cast< IDocumentMarkAccess* >(pMarkManager.get()); }
1229 
1230 // SaveBookmark
1231 
1232 SaveBookmark::SaveBookmark(
1233     bool bSavePos,
1234     bool bSaveOtherPos,
1235     const IMark& rBkmk,
1236     const SwNodeIndex & rMvPos,
1237     const SwIndex* pIdx)
1238     : m_aName(rBkmk.GetName())
1239     , m_aShortName()
1240     , m_aCode()
1241     , m_bSavePos(bSavePos)
1242     , m_bSaveOtherPos(bSaveOtherPos)
1243     , m_eOrigBkmType(IDocumentMarkAccess::GetType(rBkmk))
1244 {
1245     const IBookmark* const pBookmark = dynamic_cast< const IBookmark* >(&rBkmk);
1246     if(pBookmark)
1247     {
1248         m_aShortName = pBookmark->GetShortName();
1249         m_aCode = pBookmark->GetKeyCode();
1250 
1251         ::sfx2::Metadatable const*const pMetadatable(
1252                 dynamic_cast< ::sfx2::Metadatable const* >(pBookmark));
1253         if (pMetadatable)
1254         {
1255             m_pMetadataUndo = pMetadatable->CreateUndo();
1256         }
1257     }
1258     m_nNode1 = rBkmk.GetMarkPos().nNode.GetIndex();
1259     m_nCntnt1 = rBkmk.GetMarkPos().nContent.GetIndex();
1260 
1261     if(m_bSavePos)
1262     {
1263         m_nNode1 -= rMvPos.GetIndex();
1264         if(pIdx && !m_nNode1)
1265             m_nCntnt1 -= pIdx->GetIndex();
1266     }
1267 
1268     if(rBkmk.IsExpanded())
1269     {
1270         m_nNode2 = rBkmk.GetOtherMarkPos().nNode.GetIndex();
1271         m_nCntnt2 = rBkmk.GetOtherMarkPos().nContent.GetIndex();
1272 
1273         if(m_bSaveOtherPos)
1274         {
1275             m_nNode2 -= rMvPos.GetIndex();
1276             if(pIdx && !m_nNode2)
1277                 m_nCntnt2 -= pIdx->GetIndex();
1278         }
1279     }
1280     else
1281         m_nNode2 = ULONG_MAX, m_nCntnt2 = STRING_NOTFOUND;
1282 }
1283 
1284 void SaveBookmark::SetInDoc(
1285     SwDoc* pDoc,
1286     const SwNodeIndex& rNewPos,
1287     const SwIndex* pIdx)
1288 {
1289     SwPaM aPam(rNewPos.GetNode());
1290     if(pIdx)
1291         aPam.GetPoint()->nContent = *pIdx;
1292 
1293     if(ULONG_MAX != m_nNode2)
1294     {
1295         aPam.SetMark();
1296 
1297         if(m_bSaveOtherPos)
1298         {
1299             aPam.GetMark()->nNode += m_nNode2;
1300             if(pIdx && !m_nNode2)
1301                 aPam.GetMark()->nContent += m_nCntnt2;
1302             else
1303                 aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2);
1304         }
1305         else
1306         {
1307             aPam.GetMark()->nNode = m_nNode2;
1308             aPam.GetMark()->nContent.Assign(aPam.GetCntntNode(sal_False), m_nCntnt2);
1309         }
1310     }
1311 
1312     if(m_bSavePos)
1313     {
1314         aPam.GetPoint()->nNode += m_nNode1;
1315 
1316         if(pIdx && !m_nNode1)
1317             aPam.GetPoint()->nContent += m_nCntnt1;
1318         else
1319             aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1);
1320     }
1321     else
1322     {
1323         aPam.GetPoint()->nNode = m_nNode1;
1324         aPam.GetPoint()->nContent.Assign(aPam.GetCntntNode(), m_nCntnt1);
1325     }
1326 
1327     if(!aPam.HasMark()
1328         || CheckNodesRange(aPam.GetPoint()->nNode, aPam.GetMark()->nNode, sal_True))
1329     {
1330         ::sw::mark::IBookmark* const pBookmark = dynamic_cast< ::sw::mark::IBookmark* >(pDoc->getIDocumentMarkAccess()->makeMark(aPam, m_aName, m_eOrigBkmType));
1331         if(pBookmark)
1332         {
1333             pBookmark->SetKeyCode(m_aCode);
1334             pBookmark->SetShortName(m_aShortName);
1335             if (m_pMetadataUndo)
1336             {
1337                 ::sfx2::Metadatable * const pMeta(
1338                     dynamic_cast< ::sfx2::Metadatable* >(pBookmark));
1339                 OSL_ENSURE(pMeta, "metadata undo, but not metadatable?");
1340                 if (pMeta)
1341                 {
1342                     pMeta->RestoreMetadata(m_pMetadataUndo);
1343                 }
1344             }
1345         }
1346     }
1347 }
1348 
1349 
1350 // _DelBookmarks, _{Save,Restore}CntntIdx
1351 
1352 void _DelBookmarks(
1353     const SwNodeIndex& rStt,
1354     const SwNodeIndex& rEnd,
1355     ::std::vector<SaveBookmark> * pSaveBkmk,
1356     const SwIndex* pSttIdx,
1357     const SwIndex* pEndIdx)
1358 {
1359     // illegal range ??
1360     if(rStt.GetIndex() > rEnd.GetIndex()
1361         || (rStt == rEnd && (!pSttIdx || pSttIdx->GetIndex() >= pEndIdx->GetIndex())))
1362         return;
1363     SwDoc* const pDoc = rStt.GetNode().GetDoc();
1364 
1365     pDoc->getIDocumentMarkAccess()->deleteMarks(rStt, rEnd, pSaveBkmk, pSttIdx, pEndIdx);
1366 
1367     // kopiere alle Redlines, die im Move Bereich stehen in ein
1368     // Array, das alle Angaben auf die Position als Offset speichert.
1369     // Die neue Zuordung erfolgt nach dem Moven.
1370     SwRedlineTbl& rTbl = (SwRedlineTbl&)pDoc->GetRedlineTbl();
1371     for(sal_uInt16 nCnt = 0; nCnt < rTbl.Count(); ++nCnt )
1372     {
1373         // liegt auf der Position ??
1374         SwRedline* pRedl = rTbl[ nCnt ];
1375 
1376         SwPosition *pRStt = &pRedl->GetBound(sal_True),
1377                    *pREnd = &pRedl->GetBound(sal_False);
1378         if( *pRStt > *pREnd )
1379         {
1380             SwPosition *pTmp = pRStt; pRStt = pREnd, pREnd = pTmp;
1381         }
1382 
1383         if( lcl_Greater( *pRStt, rStt, pSttIdx ) && lcl_Lower( *pRStt, rEnd, pEndIdx ))
1384         {
1385             pRStt->nNode = rEnd;
1386             if( pEndIdx )
1387                 pRStt->nContent = *pEndIdx;
1388             else
1389             {
1390                 sal_Bool bStt = sal_True;
1391                 SwCntntNode* pCNd = pRStt->nNode.GetNode().GetCntntNode();
1392                 if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoNext( &pRStt->nNode )) )
1393                 {
1394                     bStt = sal_False;
1395                     pRStt->nNode = rStt;
1396                     if( 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pRStt->nNode )) )
1397                     {
1398                         pRStt->nNode = pREnd->nNode;
1399                         pCNd = pRStt->nNode.GetNode().GetCntntNode();
1400                     }
1401                 }
1402                 xub_StrLen nTmp = bStt ? 0 : pCNd->Len();
1403                 pRStt->nContent.Assign( pCNd, nTmp );
1404             }
1405         }
1406         if( lcl_Greater( *pREnd, rStt, pSttIdx ) && lcl_Lower( *pREnd, rEnd, pEndIdx ))
1407         {
1408             pREnd->nNode = rStt;
1409             if( pSttIdx )
1410                 pREnd->nContent = *pSttIdx;
1411             else
1412             {
1413                 sal_Bool bStt = sal_False;
1414                 SwCntntNode* pCNd = pREnd->nNode.GetNode().GetCntntNode();
1415                 if( !pCNd && 0 == ( pCNd = pDoc->GetNodes().GoPrevious( &pREnd->nNode )) )
1416                 {
1417                     bStt = sal_True;
1418                     pREnd->nNode = rEnd;
1419                     if( 0 == ( pCNd = pDoc->GetNodes().GoNext( &pREnd->nNode )) )
1420                     {
1421                         pREnd->nNode = pRStt->nNode;
1422                         pCNd = pREnd->nNode.GetNode().GetCntntNode();
1423                     }
1424                 }
1425                 xub_StrLen nTmp = bStt ? 0 : pCNd->Len();
1426                 pREnd->nContent.Assign( pCNd, nTmp );
1427             }
1428         }
1429     }
1430 }
1431 
1432 void _SaveCntntIdx(SwDoc* pDoc,
1433     sal_uLong nNode,
1434     xub_StrLen nCntnt,
1435     SvULongs& rSaveArr,
1436     sal_uInt8 nSaveFly)
1437 {
1438     // 1. Bookmarks
1439     _SwSaveTypeCountContent aSave;
1440     aSave.SetTypeAndCount( 0x8000, 0 );
1441 
1442     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1443     const sal_Int32 nMarksCount = pMarkAccess->getAllMarksCount();
1444     for ( ; aSave.GetCount() < nMarksCount; aSave.IncCount() )
1445     {
1446         bool bMarkPosEqual = false;
1447         const ::sw::mark::IMark* pBkmk = (pMarkAccess->getAllMarksBegin() + aSave.GetCount())->get();
1448         if(pBkmk->GetMarkPos().nNode.GetIndex() == nNode
1449             && pBkmk->GetMarkPos().nContent.GetIndex() <= nCntnt)
1450         {
1451             if(pBkmk->GetMarkPos().nContent.GetIndex() < nCntnt)
1452             {
1453                 aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex());
1454                 aSave.Add(rSaveArr);
1455             }
1456             else // if a bookmark position is equal nCntnt, the other position
1457                 bMarkPosEqual = true; // has to decide if it is added to the array
1458         }
1459 
1460         if(pBkmk->IsExpanded()
1461             && pBkmk->GetOtherMarkPos().nNode.GetIndex() == nNode
1462             && pBkmk->GetOtherMarkPos().nContent.GetIndex() <= nCntnt)
1463         {
1464             if(bMarkPosEqual)
1465             { // the other position is before, the (main) position is equal
1466                 aSave.SetContent(pBkmk->GetMarkPos().nContent.GetIndex());
1467                 aSave.Add(rSaveArr);
1468             }
1469             aSave.SetContent(pBkmk->GetOtherMarkPos().nContent.GetIndex());
1470             aSave.IncType();
1471             aSave.Add(rSaveArr);
1472             aSave.DecType();
1473         }
1474     }
1475 
1476 	// 2. Redlines
1477 	aSave.SetTypeAndCount( 0x1000, 0 );
1478 	const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl();
1479 	for( ; aSave.GetCount() < rRedlTbl.Count(); aSave.IncCount() )
1480 	{
1481 		const SwRedline* pRdl = rRedlTbl[ aSave.GetCount() ];
1482         int nPointPos = lcl_RelativePosition( *pRdl->GetPoint(), nNode, nCntnt );
1483         int nMarkPos = pRdl->HasMark() ? lcl_RelativePosition( *pRdl->GetMark(), nNode, nCntnt ) :
1484                                           nPointPos;
1485         // #i59534: We have to store the positions inside the same node before the insert position
1486         // and the one at the insert position if the corresponding Point/Mark position is before
1487         // the insert position.
1488         if( nPointPos == BEFORE_SAME_NODE ||
1489             ( nPointPos == SAME_POSITION && nMarkPos < SAME_POSITION ) )
1490 		{
1491 			aSave.SetContent( pRdl->GetPoint()->nContent.GetIndex() );
1492 			aSave.IncType();
1493 			aSave.Add( rSaveArr );
1494 			aSave.DecType();
1495 		}
1496 		if( pRdl->HasMark() && ( nMarkPos == BEFORE_SAME_NODE ||
1497             ( nMarkPos == SAME_POSITION && nPointPos < SAME_POSITION ) ) )
1498         {
1499 			aSave.SetContent( pRdl->GetMark()->nContent.GetIndex() );
1500 			aSave.Add( rSaveArr );
1501 		}
1502 	}
1503 
1504 	// 4. Absatzgebundene Objekte
1505 	{
1506 		SwCntntNode *pNode = pDoc->GetNodes()[nNode]->GetCntntNode();
1507 		if( pNode )
1508 		{
1509 
1510 			SwFrm* pFrm = pNode->getLayoutFrm( pDoc->GetCurrentLayout() );
1511 #if OSL_DEBUG_LEVEL > 1
1512 			static sal_Bool bViaDoc = sal_False;
1513 			if( bViaDoc )
1514 				pFrm = NULL;
1515 #endif
1516 			if( pFrm ) // gibt es ein Layout? Dann ist etwas billiger...
1517 			{
1518 				if( pFrm->GetDrawObjs() )
1519 				{
1520                     const SwSortedObjs& rDObj = *pFrm->GetDrawObjs();
1521                     for( sal_uInt32 n = rDObj.Count(); n; )
1522 					{
1523                         SwAnchoredObject* pObj = rDObj[ --n ];
1524                         const SwFrmFmt& rFmt = pObj->GetFrmFmt();
1525                         const SwFmtAnchor& rAnchor = rFmt.GetAnchor();
1526                         SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
1527                         if ( pAPos &&
1528                              ( ( nSaveFly &&
1529                                  FLY_AT_PARA == rAnchor.GetAnchorId() ) ||
1530                                ( FLY_AT_CHAR == rAnchor.GetAnchorId() ) ) )
1531                         {
1532 							aSave.SetType( 0x2000 );
1533 							aSave.SetContent( pAPos->nContent.GetIndex() );
1534 
1535 							OSL_ENSURE( nNode == pAPos->nNode.GetIndex(),
1536 									"_SaveCntntIdx: Wrong Node-Index" );
1537                             if ( FLY_AT_CHAR == rAnchor.GetAnchorId() )
1538 							{
1539 								if( nCntnt <= aSave.GetContent() )
1540 								{
1541 									if( SAVEFLY_SPLIT == nSaveFly )
1542 										aSave.IncType(); // = 0x2001;
1543 									else
1544 										continue;
1545 								}
1546 							}
1547 							aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() );
1548 							while( aSave.GetCount() &&
1549                                     &rFmt != (*pDoc->GetSpzFrmFmts())[
1550                                     aSave.DecCount() ] )
1551 								; // nothing
1552                             OSL_ENSURE( &rFmt == (*pDoc->GetSpzFrmFmts())[
1553 													aSave.GetCount() ],
1554 									"_SaveCntntIdx: Lost FrameFormat" );
1555 							aSave.Add( rSaveArr );
1556 						}
1557 					}
1558 				}
1559 			}
1560 			else // Schade, kein Layout, dann ist es eben etwas teurer...
1561 			{
1562 				for( aSave.SetCount( pDoc->GetSpzFrmFmts()->Count() );
1563 						aSave.GetCount() ; )
1564 				{
1565 					SwFrmFmt* pFrmFmt = (*pDoc->GetSpzFrmFmts())[
1566 												aSave.DecCount() ];
1567 					if ( RES_FLYFRMFMT != pFrmFmt->Which() &&
1568 							RES_DRAWFRMFMT != pFrmFmt->Which() )
1569 						continue;
1570 
1571 					const SwFmtAnchor& rAnchor = pFrmFmt->GetAnchor();
1572                     SwPosition const*const pAPos = rAnchor.GetCntntAnchor();
1573                     if ( pAPos && ( nNode == pAPos->nNode.GetIndex() ) &&
1574                          ( FLY_AT_PARA == rAnchor.GetAnchorId() ||
1575                            FLY_AT_CHAR == rAnchor.GetAnchorId() ) )
1576                     {
1577 						aSave.SetType( 0x2000 );
1578 						aSave.SetContent( pAPos->nContent.GetIndex() );
1579                         if ( FLY_AT_CHAR == rAnchor.GetAnchorId() )
1580 						{
1581 							if( nCntnt <= aSave.GetContent() )
1582 							{
1583 								if( SAVEFLY_SPLIT == nSaveFly )
1584 									aSave.IncType(); // = 0x2001;
1585 								else
1586 									continue;
1587 							}
1588 						}
1589 						aSave.Add( rSaveArr );
1590 					}
1591 				}
1592 			}
1593 		}
1594 	}
1595 	// 5. CrsrShell
1596 	{
1597 		SwCrsrShell* pShell = pDoc->GetEditShell();
1598 		if( pShell )
1599 		{
1600 			aSave.SetTypeAndCount( 0x800, 0 );
1601 			FOREACHSHELL_START( pShell )
1602 				SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
1603 				if( _pStkCrsr )
1604 				do {
1605 					lcl_ChkPaM( rSaveArr, nNode, nCntnt, *_pStkCrsr,
1606 								aSave, sal_False );
1607 					aSave.IncCount();
1608 				} while ( (_pStkCrsr != 0 ) &&
1609 					((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
1610 
1611 				FOREACHPAM_START( PCURSH->_GetCrsr() )
1612 					lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR,
1613 								aSave, sal_False );
1614 					aSave.IncCount();
1615 				FOREACHPAM_END()
1616 
1617 			FOREACHSHELL_END( pShell )
1618 		}
1619 	}
1620 	// 6. UnoCrsr
1621 	{
1622 		aSave.SetTypeAndCount( 0x400, 0 );
1623 		const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl();
1624 		for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
1625 		{
1626 			FOREACHPAM_START( rTbl[ n ] )
1627 				lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False );
1628 				aSave.IncCount();
1629 			FOREACHPAM_END()
1630 
1631             SwUnoTableCrsr* pUnoTblCrsr =
1632                 dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]);
1633 			if( pUnoTblCrsr )
1634 			{
1635 				FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
1636 					lcl_ChkPaM( rSaveArr, nNode, nCntnt, *PCURCRSR, aSave, sal_False );
1637 					aSave.IncCount();
1638 				FOREACHPAM_END()
1639 			}
1640 		}
1641 	}
1642 }
1643 
1644 
1645 void _RestoreCntntIdx(SwDoc* pDoc,
1646     SvULongs& rSaveArr,
1647     sal_uLong nNode,
1648     xub_StrLen nOffset,
1649     sal_Bool bAuto)
1650 {
1651 	SwCntntNode* pCNd = pDoc->GetNodes()[ nNode ]->GetCntntNode();
1652 	const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl();
1653 	SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts();
1654     IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1655 	sal_uInt16 n = 0;
1656 	while( n < rSaveArr.Count() )
1657 	{
1658 		_SwSaveTypeCountContent aSave( rSaveArr, n );
1659 		SwPosition* pPos = 0;
1660         switch( aSave.GetType() )
1661         {
1662             case 0x8000:
1663             {
1664                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1665                 SwPosition aNewPos(pMark->GetMarkPos());
1666                 aNewPos.nNode = *pCNd;
1667                 aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset);
1668                 pMark->SetMarkPos(aNewPos);
1669             }
1670             break;
1671             case 0x8001:
1672             {
1673                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1674                 SwPosition aNewPos(pMark->GetOtherMarkPos());
1675                 aNewPos.nNode = *pCNd;
1676                 aNewPos.nContent.Assign(pCNd, aSave.GetContent() + nOffset);
1677                 pMark->SetOtherMarkPos(aNewPos);
1678             }
1679             break;
1680             case 0x1001:
1681                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint();
1682                 break;
1683             case 0x1000:
1684                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark();
1685                 break;
1686             case 0x2000:
1687                 {
1688                     SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ];
1689                     const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor();
1690                     if( rFlyAnchor.GetCntntAnchor() )
1691                     {
1692                         SwFmtAnchor aNew( rFlyAnchor );
1693                         SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() );
1694                         aNewPos.nNode = *pCNd;
1695                         if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() )
1696                         {
1697                             aNewPos.nContent.Assign( pCNd,
1698                                                      aSave.GetContent() + nOffset );
1699                         }
1700                         else
1701                         {
1702                             aNewPos.nContent.Assign( 0, 0 );
1703                         }
1704                         aNew.SetAnchor( &aNewPos );
1705                         pFrmFmt->SetFmtAttr( aNew );
1706                     }
1707                 }
1708                 break;
1709             case 0x2001:
1710                 if( bAuto )
1711                 {
1712                     SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ];
1713                     SfxPoolItem *pAnchor = (SfxPoolItem*)&pFrmFmt->GetAnchor();
1714                     pFrmFmt->NotifyClients( pAnchor, pAnchor );
1715                 }
1716                 break;
1717 
1718             case 0x0800:
1719             case 0x0801:
1720                 {
1721                     sal_uInt16 nCnt = 0;
1722                     SwCrsrShell* pShell = pDoc->GetEditShell();
1723                     if( pShell )
1724                     {
1725                         FOREACHSHELL_START( pShell )
1726                             SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
1727                             if( _pStkCrsr )
1728                             do {
1729                                 if( aSave.GetCount() == nCnt )
1730                                 {
1731                                     pPos = &_pStkCrsr->GetBound( 0x0800 ==
1732                                                         aSave.GetType() );
1733                                     break;
1734                                 }
1735                                 ++nCnt;
1736                             } while ( (_pStkCrsr != 0 ) &&
1737                                 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
1738 
1739                             if( pPos )
1740                                 break;
1741 
1742                             FOREACHPAM_START( PCURSH->_GetCrsr() )
1743                                 if( aSave.GetCount() == nCnt )
1744                                 {
1745                                     pPos = &PCURCRSR->GetBound( 0x0800 ==
1746                                                         aSave.GetType() );
1747                                     break;
1748                                 }
1749                                 ++nCnt;
1750                             FOREACHPAM_END()
1751                             if( pPos )
1752                                 break;
1753 
1754                         FOREACHSHELL_END( pShell )
1755                     }
1756             }
1757             break;
1758 
1759         case 0x0400:
1760         case 0x0401:
1761             {
1762                 sal_uInt16 nCnt = 0;
1763                 const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl();
1764                 for( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
1765                 {
1766                     FOREACHPAM_START( rTbl[ i ] )
1767                         if( aSave.GetCount() == nCnt )
1768                         {
1769                             pPos = &PCURCRSR->GetBound( 0x0400 ==
1770                                                     aSave.GetType() );
1771                             break;
1772                         }
1773                         ++nCnt;
1774                     FOREACHPAM_END()
1775                     if( pPos )
1776                         break;
1777 
1778                     SwUnoTableCrsr* pUnoTblCrsr =
1779                         dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]);
1780                     if ( pUnoTblCrsr )
1781                     {
1782                         FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
1783                             if( aSave.GetCount() == nCnt )
1784                             {
1785                                 pPos = &PCURCRSR->GetBound( 0x0400 ==
1786                                                     aSave.GetType() );
1787                                 break;
1788                             }
1789                             ++nCnt;
1790                         FOREACHPAM_END()
1791                     }
1792                     if ( pPos )
1793                         break;
1794                 }
1795             }
1796             break;
1797         }
1798 
1799         if( pPos )
1800         {
1801             pPos->nNode = *pCNd;
1802             pPos->nContent.Assign( pCNd, aSave.GetContent() + nOffset );
1803         }
1804     }
1805 }
1806 
1807 void _RestoreCntntIdx(SvULongs& rSaveArr,
1808     const SwNode& rNd,
1809     xub_StrLen nLen,
1810     xub_StrLen nChkLen)
1811 {
1812     const SwDoc* pDoc = rNd.GetDoc();
1813     const SwRedlineTbl& rRedlTbl = pDoc->GetRedlineTbl();
1814     const SwSpzFrmFmts* pSpz = pDoc->GetSpzFrmFmts();
1815     const IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
1816     SwCntntNode* pCNd = (SwCntntNode*)rNd.GetCntntNode();
1817 
1818     sal_uInt16 n = 0;
1819     while( n < rSaveArr.Count() )
1820     {
1821         _SwSaveTypeCountContent aSave( rSaveArr, n );
1822         if( aSave.GetContent() >= nChkLen )
1823             rSaveArr[ n-1 ] -= nChkLen;
1824         else
1825         {
1826             SwPosition* pPos = 0;
1827             switch( aSave.GetType() )
1828             {
1829             case 0x8000:
1830             {
1831                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1832                 SwPosition aNewPos(pMark->GetMarkPos());
1833                 aNewPos.nNode = rNd;
1834                 aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen));
1835                 pMark->SetMarkPos(aNewPos);
1836             }
1837             break;
1838             case 0x8001:
1839             {
1840                 MarkBase* pMark = dynamic_cast<MarkBase*>(pMarkAccess->getAllMarksBegin()[aSave.GetCount()].get());
1841                 SwPosition aNewPos(pMark->GetOtherMarkPos());
1842                 aNewPos.nNode = rNd;
1843                 aNewPos.nContent.Assign(pCNd, Min(aSave.GetContent(), nLen));
1844                 pMark->SetOtherMarkPos(aNewPos);
1845             }
1846             break;
1847             case 0x1001:
1848                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetPoint();
1849                 break;
1850             case 0x1000:
1851                 pPos = (SwPosition*)rRedlTbl[ aSave.GetCount() ]->GetMark();
1852                 break;
1853             case 0x2000:
1854             case 0x2001:
1855                 {
1856                     SwFrmFmt *pFrmFmt = (*pSpz)[ aSave.GetCount() ];
1857                     const SwFmtAnchor& rFlyAnchor = pFrmFmt->GetAnchor();
1858                     if( rFlyAnchor.GetCntntAnchor() )
1859                     {
1860                         SwFmtAnchor aNew( rFlyAnchor );
1861                         SwPosition aNewPos( *rFlyAnchor.GetCntntAnchor() );
1862                         aNewPos.nNode = rNd;
1863                         if ( FLY_AT_CHAR == rFlyAnchor.GetAnchorId() )
1864                         {
1865                             aNewPos.nContent.Assign( pCNd, Min(
1866                                                      aSave.GetContent(), nLen ) );
1867                         }
1868                         else
1869                         {
1870                             aNewPos.nContent.Assign( 0, 0 );
1871                         }
1872                         aNew.SetAnchor( &aNewPos );
1873                         pFrmFmt->SetFmtAttr( aNew );
1874                     }
1875                 }
1876                 break;
1877 
1878             case 0x0800:
1879             case 0x0801:
1880                 {
1881                     sal_uInt16 nCnt = 0;
1882                     SwCrsrShell* pShell = pDoc->GetEditShell();
1883                     if( pShell )
1884                     {
1885                         FOREACHSHELL_START( pShell )
1886                             SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
1887                             if( _pStkCrsr )
1888                             do {
1889                                 if( aSave.GetCount() == nCnt )
1890                                 {
1891                                     pPos = &_pStkCrsr->GetBound( 0x0800 ==
1892                                                 aSave.GetType() );
1893                                     break;
1894                                 }
1895                                 ++nCnt;
1896                             } while ( (_pStkCrsr != 0 ) &&
1897                                 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
1898 
1899                             if( pPos )
1900                                 break;
1901 
1902                             FOREACHPAM_START( PCURSH->_GetCrsr() )
1903                                 if( aSave.GetCount() == nCnt )
1904                                 {
1905                                     pPos = &PCURCRSR->GetBound( 0x0800 ==
1906                                                 aSave.GetType() );
1907                                     break;
1908                                 }
1909                                 ++nCnt;
1910                             FOREACHPAM_END()
1911                             if( pPos )
1912                                 break;
1913 
1914                         FOREACHSHELL_END( pShell )
1915                     }
1916                 }
1917                 break;
1918 
1919             case 0x0400:
1920             case 0x0401:
1921                 {
1922                     sal_uInt16 nCnt = 0;
1923                     const SwUnoCrsrTbl& rTbl = pDoc->GetUnoCrsrTbl();
1924                     for( sal_uInt16 i = 0; i < rTbl.Count(); ++i )
1925                     {
1926                         FOREACHPAM_START( rTbl[ i ] )
1927                             if( aSave.GetCount() == nCnt )
1928                             {
1929                                 pPos = &PCURCRSR->GetBound( 0x0400 ==
1930                                                     aSave.GetType() );
1931                                 break;
1932                             }
1933                             ++nCnt;
1934                         FOREACHPAM_END()
1935                         if( pPos )
1936                             break;
1937 
1938                         SwUnoTableCrsr* pUnoTblCrsr =
1939                             dynamic_cast<SwUnoTableCrsr*>(rTbl[ i ]);
1940                         if ( pUnoTblCrsr )
1941                         {
1942                             FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
1943                                 if( aSave.GetCount() == nCnt )
1944                                 {
1945                                     pPos = &PCURCRSR->GetBound( 0x0400 ==
1946                                                     aSave.GetType() );
1947                                     break;
1948                                 }
1949                                 ++nCnt;
1950                             FOREACHPAM_END()
1951                         }
1952                         if ( pPos )
1953                             break;
1954                     }
1955                 }
1956                 break;
1957             }
1958 
1959             if( pPos )
1960             {
1961                 pPos->nNode = rNd;
1962                 pPos->nContent.Assign( pCNd, Min( aSave.GetContent(), nLen ) );
1963             }
1964             n -= 2;
1965             rSaveArr.Remove( n, 2 );
1966         }
1967     }
1968 }
1969