xref: /trunk/main/sw/source/core/undo/unmove.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 #include <UndoSplitMove.hxx>
32 
33 #include <doc.hxx>
34 #include <IDocumentUndoRedo.hxx>
35 #include <pam.hxx>
36 #include <swundo.hxx>           // fuer die UndoIds
37 #include <ndtxt.hxx>
38 #include <UndoCore.hxx>
39 #include <rolbck.hxx>
40 
41 
42 // MOVE
43 
44 SwUndoMove::SwUndoMove( const SwPaM& rRange, const SwPosition& rMvPos )
45     : SwUndo( UNDO_MOVE ), SwUndRng( rRange ),
46     nMvDestNode( rMvPos.nNode.GetIndex() ),
47     nMvDestCntnt( rMvPos.nContent.GetIndex() ),
48     bMoveRedlines( false )
49 {
50     bMoveRange = bJoinNext = bJoinPrev = sal_False;
51 
52     // StartNode vorm loeschen von Fussnoten besorgen!
53     SwDoc* pDoc = rRange.GetDoc();
54     SwTxtNode* pTxtNd = pDoc->GetNodes()[ nSttNode ]->GetTxtNode();
55     SwTxtNode* pEndTxtNd = pDoc->GetNodes()[ nEndNode ]->GetTxtNode();
56 
57     pHistory = new SwHistory;
58 
59     if( pTxtNd )
60     {
61         pHistory->Add( pTxtNd->GetTxtColl(), nSttNode, ND_TEXTNODE );
62         if ( pTxtNd->GetpSwpHints() )
63         {
64             pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode,
65                                 0, pTxtNd->GetTxt().Len(), false );
66         }
67         if( pTxtNd->HasSwAttrSet() )
68             pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nSttNode );
69     }
70     if( pEndTxtNd && pEndTxtNd != pTxtNd )
71     {
72         pHistory->Add( pEndTxtNd->GetTxtColl(), nEndNode, ND_TEXTNODE );
73         if ( pEndTxtNd->GetpSwpHints() )
74         {
75             pHistory->CopyAttr( pEndTxtNd->GetpSwpHints(), nEndNode,
76                                 0, pEndTxtNd->GetTxt().Len(), false );
77         }
78         if( pEndTxtNd->HasSwAttrSet() )
79             pHistory->CopyFmtAttr( *pEndTxtNd->GetpSwAttrSet(), nEndNode );
80     }
81 
82     pTxtNd = rMvPos.nNode.GetNode().GetTxtNode();
83     if (0 != pTxtNd)
84     {
85         pHistory->Add( pTxtNd->GetTxtColl(), nMvDestNode, ND_TEXTNODE );
86         if ( pTxtNd->GetpSwpHints() )
87         {
88             pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nMvDestNode,
89                                 0, pTxtNd->GetTxt().Len(), false );
90         }
91         if( pTxtNd->HasSwAttrSet() )
92             pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nMvDestNode );
93     }
94 
95 
96     nFtnStt = pHistory->Count();
97     DelFtn( rRange );
98 
99     if( pHistory && !pHistory->Count() )
100         DELETEZ( pHistory );
101 }
102 
103 
104 SwUndoMove::SwUndoMove( SwDoc* pDoc, const SwNodeRange& rRg,
105                         const SwNodeIndex& rMvPos )
106     : SwUndo( UNDO_MOVE ),
107     nMvDestNode( rMvPos.GetIndex() ),
108     bMoveRedlines( false )
109 {
110     bMoveRange = sal_True;
111     bJoinNext = bJoinPrev = sal_False;
112 
113     nSttCntnt = nEndCntnt = nMvDestCntnt = STRING_MAXLEN;
114 
115     nSttNode = rRg.aStart.GetIndex();
116     nEndNode = rRg.aEnd.GetIndex();
117 
118 //  DelFtn( rRange );
119 
120     // wird aus dem CntntBereich in den Sonderbereich verschoben ?
121     sal_uLong nCntntStt = pDoc->GetNodes().GetEndOfAutotext().GetIndex();
122     if( nMvDestNode < nCntntStt && rRg.aStart.GetIndex() > nCntntStt )
123     {
124         // loesche alle Fussnoten. Diese sind dort nicht erwuenscht.
125         SwPosition aPtPos( rRg.aEnd );
126         SwCntntNode* pCNd = rRg.aEnd.GetNode().GetCntntNode();
127         if( pCNd )
128             aPtPos.nContent.Assign( pCNd, pCNd->Len() );
129         SwPosition aMkPos( rRg.aStart );
130         if( 0 != ( pCNd = aMkPos.nNode.GetNode().GetCntntNode() ))
131             aMkPos.nContent.Assign( pCNd, 0 );
132 
133         DelCntntIndex( aMkPos, aPtPos, nsDelCntntType::DELCNT_FTN );
134 
135         if( pHistory && !pHistory->Count() )
136             DELETEZ( pHistory );
137     }
138 
139     nFtnStt = 0;
140 }
141 
142 
143 
144 void SwUndoMove::SetDestRange( const SwPaM& rRange,
145                                 const SwPosition& rInsPos,
146                                 sal_Bool bJoin, sal_Bool bCorrPam )
147 {
148     const SwPosition *pStt = rRange.Start(),
149                     *pEnd = rRange.GetPoint() == pStt
150                         ? rRange.GetMark()
151                         : rRange.GetPoint();
152 
153     nDestSttNode    = pStt->nNode.GetIndex();
154     nDestSttCntnt   = pStt->nContent.GetIndex();
155     nDestEndNode    = pEnd->nNode.GetIndex();
156     nDestEndCntnt   = pEnd->nContent.GetIndex();
157 
158     nInsPosNode     = rInsPos.nNode.GetIndex();
159     nInsPosCntnt    = rInsPos.nContent.GetIndex();
160 
161     if( bCorrPam )
162     {
163         nDestSttNode--;
164         nDestEndNode--;
165     }
166 
167     bJoinNext = nDestSttNode != nDestEndNode &&
168                 pStt->nNode.GetNode().GetTxtNode() &&
169                 pEnd->nNode.GetNode().GetTxtNode();
170     bJoinPrev = bJoin;
171 }
172 
173 
174 void SwUndoMove::SetDestRange( const SwNodeIndex& rStt,
175                                 const SwNodeIndex& rEnd,
176                                 const SwNodeIndex& rInsPos )
177 {
178     nDestSttNode = rStt.GetIndex();
179     nDestEndNode = rEnd.GetIndex();
180     if( nDestSttNode > nDestEndNode )
181     {
182         nDestSttNode = nDestEndNode;
183         nDestEndNode = rStt.GetIndex();
184     }
185     nInsPosNode  = rInsPos.GetIndex();
186 
187     nDestSttCntnt = nDestEndCntnt = nInsPosCntnt = STRING_MAXLEN;
188 }
189 
190 
191 void SwUndoMove::UndoImpl(::sw::UndoRedoContext & rContext)
192 {
193     SwDoc *const pDoc = & rContext.GetDoc();
194 
195     // Block, damit aus diesem gesprungen werden kann
196     do {
197         // erzeuge aus den Werten die Insert-Position und den Bereich
198         SwNodeIndex aIdx( pDoc->GetNodes(), nDestSttNode );
199 
200         if( bMoveRange )
201         {
202             // nur ein Move mit SwRange
203             SwNodeRange aRg( aIdx, aIdx );
204             aRg.aEnd = nDestEndNode;
205             aIdx = nInsPosNode;
206             bool bSuccess = pDoc->MoveNodeRange( aRg, aIdx,
207                     IDocumentContentOperations::DOC_MOVEDEFAULT );
208             if (!bSuccess)
209                 break;
210         }
211         else
212         {
213             SwPaM aPam( aIdx.GetNode(), nDestSttCntnt,
214                         *pDoc->GetNodes()[ nDestEndNode ], nDestEndCntnt );
215 
216             // #i17764# if redlines are to be moved, we may not remove them before
217             //          pDoc->Move gets a chance to handle them
218             if( ! bMoveRedlines )
219                 RemoveIdxFromRange( aPam, sal_False );
220 
221             SwPosition aPos( *pDoc->GetNodes()[ nInsPosNode] );
222             SwCntntNode* pCNd = aPos.nNode.GetNode().GetCntntNode();
223             aPos.nContent.Assign( pCNd, nInsPosCntnt );
224 
225             if( pCNd->HasSwAttrSet() )
226                 pCNd->ResetAllAttr();
227 
228             if( pCNd->IsTxtNode() && ((SwTxtNode*)pCNd)->GetpSwpHints() )
229                 ((SwTxtNode*)pCNd)->ClearSwpHintsArr( false );
230 
231             // an der InsertPos erstmal alle Attribute entfernen,
232             const bool bSuccess = pDoc->MoveRange( aPam, aPos, (bMoveRedlines)
233                         ? IDocumentContentOperations::DOC_MOVEREDLINES
234                         : IDocumentContentOperations::DOC_MOVEDEFAULT );
235             if (!bSuccess)
236                 break;
237 
238             aPam.Exchange();
239             aPam.DeleteMark();
240 //          pDoc->ResetAttr( aPam, sal_False );
241             if( aPam.GetNode()->IsCntntNode() )
242                 aPam.GetNode()->GetCntntNode()->ResetAllAttr();
243             // der Pam wird jetzt aufgegeben.
244         }
245 
246         SwTxtNode* pTxtNd = aIdx.GetNode().GetTxtNode();
247         if( bJoinNext )
248         {
249             {
250                 RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx,
251                         SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) );
252             }
253             // sind keine Pams mehr im naechsten TextNode
254             pTxtNd->JoinNext();
255         }
256 
257         if( bJoinPrev && pTxtNd->CanJoinPrev( &aIdx ) )
258         {
259             // ?? sind keine Pams mehr im naechsten TextNode ??
260             pTxtNd = aIdx.GetNode().GetTxtNode();
261             {
262                 RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx,
263                         SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) );
264             }
265             pTxtNd->JoinNext();
266         }
267 
268     } while( sal_False );
269 
270     if( pHistory )
271     {
272         if( nFtnStt != pHistory->Count() )
273             pHistory->Rollback( pDoc, nFtnStt );
274         pHistory->TmpRollback( pDoc, 0 );
275         pHistory->SetTmpEnd( pHistory->Count() );
276     }
277 
278     // setze noch den Cursor auf den Undo-Bereich
279     if( !bMoveRange )
280     {
281         AddUndoRedoPaM(rContext);
282     }
283 }
284 
285 
286 void SwUndoMove::RedoImpl(::sw::UndoRedoContext & rContext)
287 {
288     SwPaM *const pPam = & AddUndoRedoPaM(rContext);
289     SwDoc & rDoc = rContext.GetDoc();
290 
291     SwNodes& rNds = rDoc.GetNodes();
292     SwNodeIndex aIdx( rNds, nMvDestNode );
293 
294     if( bMoveRange )
295     {
296         // nur ein Move mit SwRange
297         SwNodeRange aRg( rNds, nSttNode, rNds, nEndNode );
298         rDoc.MoveNodeRange( aRg, aIdx, (bMoveRedlines)
299                 ? IDocumentContentOperations::DOC_MOVEREDLINES
300                 : IDocumentContentOperations::DOC_MOVEDEFAULT );
301     }
302     else
303     {
304         SwPaM aPam( *pPam->GetPoint() );
305         SetPaM( aPam );
306         SwPosition aMvPos( aIdx, SwIndex( aIdx.GetNode().GetCntntNode(),
307                                         nMvDestCntnt ));
308 
309         DelFtn( aPam );
310         RemoveIdxFromRange( aPam, sal_False );
311 
312         aIdx = aPam.Start()->nNode;
313         sal_Bool bJoinTxt = aIdx.GetNode().IsTxtNode();
314 
315         aIdx--;
316         rDoc.MoveRange( aPam, aMvPos,
317             IDocumentContentOperations::DOC_MOVEDEFAULT );
318 
319         if( nSttNode != nEndNode && bJoinTxt )
320         {
321             aIdx++;
322             SwTxtNode * pTxtNd = aIdx.GetNode().GetTxtNode();
323             if( pTxtNd && pTxtNd->CanJoinNext() )
324             {
325                 {
326                     RemoveIdxRel( aIdx.GetIndex() + 1, SwPosition( aIdx,
327                             SwIndex( pTxtNd, pTxtNd->GetTxt().Len() ) ) );
328                 }
329                 pTxtNd->JoinNext();
330             }
331         }
332         *pPam->GetPoint() = *aPam.GetPoint();
333         pPam->SetMark();
334         *pPam->GetMark() = *aPam.GetMark();
335     }
336 }
337 
338 
339 void SwUndoMove::DelFtn( const SwPaM& rRange )
340 {
341     // wird aus dem CntntBereich in den Sonderbereich verschoben ?
342     SwDoc* pDoc = rRange.GetDoc();
343     sal_uLong nCntntStt = pDoc->GetNodes().GetEndOfAutotext().GetIndex();
344     if( nMvDestNode < nCntntStt &&
345         rRange.GetPoint()->nNode.GetIndex() >= nCntntStt )
346     {
347         // loesche alle Fussnoten. Diese sind dort nicht erwuenscht.
348         DelCntntIndex( *rRange.GetMark(), *rRange.GetPoint(),
349                             nsDelCntntType::DELCNT_FTN );
350 
351         if( pHistory && !pHistory->Count() )
352             delete pHistory, pHistory = 0;
353     }
354 }
355 
356