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