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