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