xref: /trunk/main/sw/source/core/doc/doccorr.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <doc.hxx>
33 #include <node.hxx>
34 #include <rootfrm.hxx>
35 #include <editsh.hxx>
36 #include <viscrs.hxx>
37 #include <IMark.hxx>
38 #include <bookmrk.hxx>
39 #include <redline.hxx>
40 #include <mvsave.hxx>
41 #include <docary.hxx>
42 #include <unocrsr.hxx>
43 #include <swundo.hxx>
44 #include <hints.hxx>
45 
46 /*
47  * MACROS um ueber alle CrsrShells zu iterieren
48  */
49 #define PCURSH ((SwCrsrShell*)_pStartShell)
50 #define FOREACHSHELL_START( pEShell ) \
51     {\
52         ViewShell *_pStartShell = pEShell; \
53         do { \
54             if( _pStartShell->IsA( TYPE( SwCrsrShell )) ) \
55             {
56 
57 #define FOREACHSHELL_END( pEShell ) \
58             } \
59         } while((_pStartShell=(ViewShell*)_pStartShell->GetNext())!= pEShell ); \
60     }
61 
62 #define PCURCRSR (_pCurrCrsr)
63 #define FOREACHPAM_START(pSttCrsr) \
64     {\
65         SwPaM *_pStartCrsr = pSttCrsr, *_pCurrCrsr = pSttCrsr; \
66         do {
67 
68 #define FOREACHPAM_END() \
69         } while( (_pCurrCrsr=(SwPaM *)_pCurrCrsr->GetNext()) != _pStartCrsr ); \
70     }
71 
72 namespace
73 {
74     // find the relevant section in which the SwUnoCrsr may wander.
75     // returns NULL if no restrictions apply
76     static const SwStartNode* lcl_FindUnoCrsrSection( const SwNode& rNode )
77     {
78         const SwStartNode* pStartNode = rNode.StartOfSectionNode();
79         while( ( pStartNode != NULL ) &&
80                ( pStartNode->StartOfSectionNode() != pStartNode ) &&
81                ( pStartNode->GetStartNodeType() == SwNormalStartNode ) )
82             pStartNode = pStartNode->StartOfSectionNode();
83 
84         return pStartNode;
85     }
86 
87     static inline bool lcl_PosCorrAbs(SwPosition & rPos,
88         const SwPosition& rStart,
89         const SwPosition& rEnd,
90         const SwPosition& rNewPos)
91     {
92         if ((rStart <= rPos) && (rPos <= rEnd))
93         {
94             rPos = rNewPos;
95             return true;
96         }
97         return false;
98     };
99 
100     static inline bool lcl_PaMCorrAbs(SwPaM & rPam,
101         const SwPosition& rStart,
102         const SwPosition& rEnd,
103         const SwPosition& rNewPos)
104     {
105         bool bRet = false;
106         bRet |= lcl_PosCorrAbs(rPam.GetBound(true ), rStart, rEnd, rNewPos);
107         bRet |= lcl_PosCorrAbs(rPam.GetBound(false), rStart, rEnd, rNewPos);
108         return bRet;
109     };
110 
111     static inline void lcl_PaMCorrRel1(SwPaM * pPam,
112         SwNode const * const pOldNode,
113         const SwPosition& rNewPos,
114         const xub_StrLen nCntIdx)
115     {
116         for(int nb = 0; nb < 2; ++nb)
117             if(&((pPam)->GetBound(sal_Bool(nb)).nNode.GetNode()) == pOldNode)
118             {
119                 (pPam)->GetBound(sal_Bool(nb)).nNode = rNewPos.nNode;
120                 (pPam)->GetBound(sal_Bool(nb)).nContent.Assign(
121                     const_cast<SwIndexReg*>(rNewPos.nContent.GetIdxReg()),
122                     nCntIdx + (pPam)->GetBound(sal_Bool(nb)).nContent.GetIndex());
123             }
124     }
125 }
126 
127 
128 void PaMCorrAbs( const SwPaM& rRange,
129                 const SwPosition& rNewPos )
130 {
131     SwPosition const aStart( *rRange.Start() );
132     SwPosition const aEnd( *rRange.End() );
133     SwPosition const aNewPos( rNewPos );
134     SwDoc *const pDoc = aStart.nNode.GetNode().GetDoc();
135     SwCrsrShell *const pShell = pDoc->GetEditShell();
136 
137     if( pShell )
138     {
139         FOREACHSHELL_START( pShell )
140             SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
141             if( _pStkCrsr )
142             do {
143                 lcl_PaMCorrAbs( *_pStkCrsr, aStart, aEnd, aNewPos );
144             } while ( (_pStkCrsr != 0 ) &&
145                 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
146 
147             FOREACHPAM_START( PCURSH->_GetCrsr() )
148                 lcl_PaMCorrAbs( *PCURCRSR, aStart, aEnd, aNewPos );
149             FOREACHPAM_END()
150 
151             if( PCURSH->IsTableMode() )
152                 lcl_PaMCorrAbs( *PCURSH->GetTblCrs(), aStart, aEnd, aNewPos );
153 
154         FOREACHSHELL_END( pShell )
155     }
156     {
157         SwUnoCrsrTbl& rTbl = const_cast<SwUnoCrsrTbl&>(pDoc->GetUnoCrsrTbl());
158 
159         for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
160         {
161             SwUnoCrsr *const pUnoCursor = rTbl[ n ];
162 
163             bool bChange = false; // has the UNO cursor been corrected?
164 
165             // determine whether the UNO cursor will leave it's designated
166             // section
167             bool const bLeaveSection =
168                 pUnoCursor->IsRemainInSection() &&
169                 ( lcl_FindUnoCrsrSection( aNewPos.nNode.GetNode() ) !=
170                   lcl_FindUnoCrsrSection(
171                       pUnoCursor->GetPoint()->nNode.GetNode() ) );
172 
173             FOREACHPAM_START( pUnoCursor )
174                 bChange |= lcl_PaMCorrAbs( *PCURCRSR, aStart, aEnd, aNewPos );
175             FOREACHPAM_END()
176 
177             SwUnoTableCrsr *const pUnoTblCrsr =
178                 dynamic_cast<SwUnoTableCrsr *>(rTbl[ n ]);
179             if( pUnoTblCrsr )
180             {
181                 FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
182                     bChange |=
183                         lcl_PaMCorrAbs( *PCURCRSR, aStart, aEnd, aNewPos );
184                 FOREACHPAM_END()
185             }
186 
187             // if a UNO cursor leaves its designated section, we must inform
188             // (and invalidate) said cursor
189             if (bChange && bLeaveSection)
190             {
191                 // the UNO cursor has left its section. We need to notify it!
192                 SwMsgPoolItem aHint( RES_UNOCURSOR_LEAVES_SECTION );
193                 pUnoCursor->ModifyNotification( &aHint, NULL );
194             }
195         }
196     }
197 }
198 
199 void SwDoc::CorrAbs(const SwNodeIndex& rOldNode,
200     const SwPosition& rNewPos,
201     const xub_StrLen nOffset,
202     sal_Bool bMoveCrsr)
203 {
204     SwCntntNode *const pCntntNode( rOldNode.GetNode().GetCntntNode() );
205     SwPaM const aPam(rOldNode, 0,
206                      rOldNode, (pCntntNode) ? pCntntNode->Len() : 0);
207     SwPosition aNewPos(rNewPos);
208     aNewPos.nContent += nOffset;
209 
210     getIDocumentMarkAccess()->correctMarksAbsolute(rOldNode, rNewPos, nOffset);
211     {   // fix redlines
212         SwRedlineTbl& rTbl = *pRedlineTbl;
213         for (sal_uInt16 n = 0; n < rTbl.Count(); )
214         {
215             // is on position ??
216             SwRedline *const pRedline( rTbl[ n ] );
217             bool const bChanged =
218                 lcl_PaMCorrAbs(*pRedline, *aPam.Start(), *aPam.End(), aNewPos);
219             // clean up empty redlines: docredln.cxx asserts these as invalid
220             if (bChanged && (*pRedline->GetPoint() == *pRedline->GetMark())
221                          && (pRedline->GetContentIdx() == NULL))
222             {
223                 rTbl.DeleteAndDestroy(n);
224             }
225             else
226             {
227                 ++n;
228             }
229         }
230     }
231 
232     if(bMoveCrsr)
233     {
234         ::PaMCorrAbs(aPam, aNewPos);
235     }
236 }
237 
238 void SwDoc::CorrAbs(const SwPaM& rRange,
239     const SwPosition& rNewPos,
240     sal_Bool bMoveCrsr)
241 {
242     SwPosition aStart(*rRange.Start());
243     SwPosition aEnd(*rRange.End());
244     SwPosition aNewPos(rNewPos);
245 
246     _DelBookmarks(aStart.nNode, aEnd.nNode, NULL,
247         &aStart.nContent, &aEnd.nContent);
248     if(bMoveCrsr)
249         ::PaMCorrAbs(rRange, rNewPos);
250 }
251 
252 void SwDoc::CorrAbs(const SwNodeIndex& rStartNode,
253      const SwNodeIndex& rEndNode,
254      const SwPosition& rNewPos,
255      sal_Bool bMoveCrsr)
256 {
257     _DelBookmarks(rStartNode, rEndNode);
258 
259     if(bMoveCrsr)
260     {
261         SwCntntNode *const pCntntNode( rEndNode.GetNode().GetCntntNode() );
262         SwPaM const aPam(rStartNode, 0,
263                          rEndNode, (pCntntNode) ? pCntntNode->Len() : 0);
264         ::PaMCorrAbs(aPam, rNewPos);
265     }
266 }
267 
268 
269 
270 
271 
272 void PaMCorrRel( const SwNodeIndex &rOldNode,
273                  const SwPosition &rNewPos,
274                  const xub_StrLen nOffset )
275 {
276     const SwNode* pOldNode = &rOldNode.GetNode();
277     SwPosition aNewPos( rNewPos );
278     const SwDoc* pDoc = pOldNode->GetDoc();
279 
280     xub_StrLen nCntIdx = rNewPos.nContent.GetIndex() + nOffset;
281 
282     SwCrsrShell* pShell = pDoc->GetEditShell();
283     if( pShell )
284     {
285         FOREACHSHELL_START( pShell )
286             SwPaM *_pStkCrsr = PCURSH->GetStkCrsr();
287             if( _pStkCrsr )
288             do {
289                 lcl_PaMCorrRel1( _pStkCrsr, pOldNode, aNewPos, nCntIdx );
290             } while ( (_pStkCrsr != 0 ) &&
291                 ((_pStkCrsr=(SwPaM *)_pStkCrsr->GetNext()) != PCURSH->GetStkCrsr()) );
292 
293             FOREACHPAM_START( PCURSH->_GetCrsr() )
294                 lcl_PaMCorrRel1( PCURCRSR, pOldNode, aNewPos, nCntIdx);
295             FOREACHPAM_END()
296 
297             if( PCURSH->IsTableMode() )
298                 lcl_PaMCorrRel1( PCURSH->GetTblCrs(), pOldNode, aNewPos, nCntIdx );
299 
300         FOREACHSHELL_END( pShell )
301     }
302     {
303         SwUnoCrsrTbl& rTbl = (SwUnoCrsrTbl&)pDoc->GetUnoCrsrTbl();
304         for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
305         {
306             FOREACHPAM_START( rTbl[ n ] )
307                 lcl_PaMCorrRel1( PCURCRSR, pOldNode, aNewPos, nCntIdx );
308             FOREACHPAM_END()
309 
310             SwUnoTableCrsr* pUnoTblCrsr =
311                 dynamic_cast<SwUnoTableCrsr*>(rTbl[ n ]);
312             if( pUnoTblCrsr )
313             {
314                 FOREACHPAM_START( &pUnoTblCrsr->GetSelRing() )
315                     lcl_PaMCorrRel1( PCURCRSR, pOldNode, aNewPos, nCntIdx );
316                 FOREACHPAM_END()
317             }
318         }
319     }
320 }
321 
322 void SwDoc::CorrRel(const SwNodeIndex& rOldNode,
323     const SwPosition& rNewPos,
324     const xub_StrLen nOffset,
325     sal_Bool bMoveCrsr)
326 {
327     getIDocumentMarkAccess()->correctMarksRelative(rOldNode, rNewPos, nOffset);
328 
329     { // dann die Redlines korrigieren
330         SwRedlineTbl& rTbl = *pRedlineTbl;
331         SwPosition aNewPos(rNewPos);
332         for( sal_uInt16 n = 0; n < rTbl.Count(); ++n )
333         {
334             // liegt auf der Position ??
335             lcl_PaMCorrRel1( rTbl[ n ], &rOldNode.GetNode(), aNewPos, aNewPos.nContent.GetIndex() + nOffset );
336         }
337     }
338 
339     if(bMoveCrsr)
340         ::PaMCorrRel(rOldNode, rNewPos, nOffset);
341 }
342 
343 
344 SwEditShell* SwDoc::GetEditShell( ViewShell** ppSh ) const
345 {
346     // Layout und OLE-Shells sollten vorhanden sein!
347     if( pCurrentView )
348     {
349         ViewShell *pSh = pCurrentView, *pVSh = pSh;
350         if( ppSh )
351             *ppSh = pSh;
352 
353         // wir suchen uns eine EditShell, falls diese existiert
354         do {
355             if( pSh->IsA( TYPE( SwEditShell ) ) )
356                 return (SwEditShell*)pSh;
357 
358         } while( pVSh != ( pSh = (ViewShell*)pSh->GetNext() ));
359     }
360     else if( ppSh )
361         *ppSh = 0;  //swmod 071029//swmod 071225
362 
363     return 0;
364 }
365 
366 ::sw::IShellCursorSupplier * SwDoc::GetIShellCursorSupplier()
367 {
368     return GetEditShell(0);
369 }
370 
371