xref: /trunk/main/sw/source/core/undo/untblk.cxx (revision 61dff127b6698e0bae836c8aedd6ec62111483d1)
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 <hintids.hxx>
32 #include <fmtanchr.hxx>
33 #include <frmfmt.hxx>
34 #include <doc.hxx>
35 #include <IDocumentUndoRedo.hxx>
36 #include <IShellCursorSupplier.hxx>
37 #include <docary.hxx>
38 #include <swundo.hxx>           // fuer die UndoIds
39 #include <pam.hxx>
40 #include <ndtxt.hxx>
41 #include <UndoCore.hxx>
42 #include <rolbck.hxx>
43 #include <redline.hxx>
44 
45 
46 
47 SwUndoInserts::SwUndoInserts( SwUndoId nUndoId, const SwPaM& rPam )
48     : SwUndo( nUndoId ), SwUndRng( rPam ),
49     pTxtFmtColl( 0 ), pLastNdColl(0), pFrmFmts( 0 ), pRedlData( 0 ),
50     bSttWasTxtNd( sal_True ), nNdDiff( 0 ), pPos( 0 ), nSetPos( 0 )
51 {
52     pHistory = new SwHistory;
53     SwDoc* pDoc = (SwDoc*)rPam.GetDoc();
54 
55     SwTxtNode* pTxtNd = rPam.GetPoint()->nNode.GetNode().GetTxtNode();
56     if( pTxtNd )
57     {
58         pTxtFmtColl = pTxtNd->GetTxtColl();
59         pHistory->CopyAttr( pTxtNd->GetpSwpHints(), nSttNode,
60                             0, pTxtNd->GetTxt().Len(), false );
61         if( pTxtNd->HasSwAttrSet() )
62             pHistory->CopyFmtAttr( *pTxtNd->GetpSwAttrSet(), nSttNode );
63 
64         if( !nSttCntnt )    // dann werden Flys mitgenommen !!
65         {
66             sal_uInt16 nArrLen = pDoc->GetSpzFrmFmts()->Count();
67             for( sal_uInt16 n = 0; n < nArrLen; ++n )
68             {
69                 SwFrmFmt* pFmt = (*pDoc->GetSpzFrmFmts())[n];
70                 SwFmtAnchor const*const  pAnchor = &pFmt->GetAnchor();
71                 const SwPosition* pAPos = pAnchor->GetCntntAnchor();
72                 if (pAPos &&
73                     (pAnchor->GetAnchorId() == FLY_AT_PARA) &&
74                      nSttNode == pAPos->nNode.GetIndex() )
75                 {
76                     if( !pFrmFmts )
77                         pFrmFmts = new SvPtrarr;
78                     pFrmFmts->Insert( pFmt, pFrmFmts->Count() );
79                 }
80             }
81         }
82     }
83     // Redline beachten
84     if( pDoc->IsRedlineOn() )
85     {
86         pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_INSERT, pDoc->GetRedlineAuthor() );
87         SetRedlineMode( pDoc->GetRedlineMode() );
88     }
89 }
90 
91 // setze den Destination-Bereich nach dem Einlesen.
92 
93 void SwUndoInserts::SetInsertRange( const SwPaM& rPam, sal_Bool bScanFlys,
94                                     sal_Bool bSttIsTxtNd )
95 {
96     const SwPosition* pTmpPos = rPam.End();
97     nEndNode = pTmpPos->nNode.GetIndex();
98     nEndCntnt = pTmpPos->nContent.GetIndex();
99     if( rPam.HasMark() )
100     {
101         if( pTmpPos == rPam.GetPoint() )
102             pTmpPos = rPam.GetMark();
103         else
104             pTmpPos = rPam.GetPoint();
105 
106         nSttNode = pTmpPos->nNode.GetIndex();
107         nSttCntnt = pTmpPos->nContent.GetIndex();
108 
109         if( !bSttIsTxtNd )      // wird eine Tabellenselektion eingefuegt,
110         {
111             ++nSttNode;         // dann stimmt der CopyPam nicht ganz
112             bSttWasTxtNd = sal_False;
113         }
114     }
115 
116     if( bScanFlys && !nSttCntnt )
117     {
118         // dann alle neuen Flys zusammen sammeln !!
119         SwDoc* pDoc = (SwDoc*)rPam.GetDoc();
120         sal_uInt16 nFndPos, nArrLen = pDoc->GetSpzFrmFmts()->Count();
121         for( sal_uInt16 n = 0; n < nArrLen; ++n )
122         {
123             SwFrmFmt* pFmt = (*pDoc->GetSpzFrmFmts())[n];
124             SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
125             SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
126             if (pAPos &&
127                 (pAnchor->GetAnchorId() == FLY_AT_PARA) &&
128                 nSttNode == pAPos->nNode.GetIndex() )
129             {
130                 if( !pFrmFmts ||
131                     USHRT_MAX == ( nFndPos = pFrmFmts->GetPos( pFmt ) ) )
132                 {
133                     ::boost::shared_ptr<SwUndoInsLayFmt> const pFlyUndo(
134                         new SwUndoInsLayFmt(pFmt, 0, 0));
135                     m_FlyUndos.push_back(pFlyUndo);
136                 }
137                 else
138                     pFrmFmts->Remove( nFndPos );
139             }
140         }
141         delete pFrmFmts, pFrmFmts = 0;
142     }
143 }
144 
145 
146 SwUndoInserts::~SwUndoInserts()
147 {
148     if( pPos )      // loesche noch den Bereich aus dem UndoNodes Array
149     {
150         // Insert speichert den Inhalt in der IconSection
151         SwNodes& rUNds = pPos->nNode.GetNodes();
152         if( pPos->nContent.GetIndex() )         // nicht den gesamten Node loeschen
153         {
154             SwTxtNode* pTxtNd = pPos->nNode.GetNode().GetTxtNode();
155             ASSERT( pTxtNd, "kein TextNode, aus dem geloescht werden soll" );
156             if( pTxtNd ) // Robust
157             {
158                 pTxtNd->EraseText( pPos->nContent );
159             }
160             pPos->nNode++;
161         }
162         pPos->nContent.Assign( 0, 0 );
163         rUNds.Delete( pPos->nNode, rUNds.GetEndOfExtras().GetIndex() -
164                                     pPos->nNode.GetIndex() );
165         delete pPos;
166     }
167     delete pFrmFmts;
168     delete pRedlData;
169 }
170 
171 
172 void SwUndoInserts::UndoImpl(::sw::UndoRedoContext & rContext)
173 {
174     SwDoc *const pDoc = & rContext.GetDoc();
175     SwPaM *const pPam = & AddUndoRedoPaM(rContext);
176 
177     if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
178         pDoc->DeleteRedline( *pPam, true, USHRT_MAX );
179 
180     // sind an Point/Mark 2 unterschiedliche TextNodes, dann muss ein
181     // JoinNext ausgefuehrt werden.
182     sal_Bool bJoinNext = nSttNode != nEndNode &&
183                 pPam->GetMark()->nNode.GetNode().GetTxtNode() &&
184                 pPam->GetPoint()->nNode.GetNode().GetTxtNode();
185 
186 
187     // gibts ueberhaupt Inhalt ? (laden von Zeichenvorlagen hat kein Inhalt!)
188     if( nSttNode != nEndNode || nSttCntnt != nEndCntnt )
189     {
190         if( nSttNode != nEndNode )
191         {
192             SwTxtNode* pTxtNd = pDoc->GetNodes()[ nEndNode ]->GetTxtNode();
193             if( pTxtNd && pTxtNd->GetTxt().Len() == nEndCntnt )
194                 pLastNdColl = pTxtNd->GetTxtColl();
195         }
196 
197         RemoveIdxFromRange( *pPam, sal_False );
198         SetPaM(*pPam);
199 
200         // sind Fussnoten oder CntntFlyFrames im Text ??
201         nSetPos = pHistory->Count();
202         nNdDiff = pPam->GetMark()->nNode.GetIndex();
203         DelCntntIndex( *pPam->GetMark(), *pPam->GetPoint() );
204         nNdDiff -= pPam->GetMark()->nNode.GetIndex();
205 
206         if( *pPam->GetPoint() != *pPam->GetMark() )
207         {
208             pPos = new SwPosition( *pPam->GetPoint() );
209             MoveToUndoNds( *pPam, &pPos->nNode, &pPos->nContent );
210 
211             if( !bSttWasTxtNd )
212                 pPam->Move( fnMoveBackward, fnGoCntnt );
213         }
214     }
215 
216     if (m_FlyUndos.size())
217     {
218         sal_uLong nTmp = pPam->GetPoint()->nNode.GetIndex();
219         for (size_t n = m_FlyUndos.size(); 0 < n; --n)
220         {
221             m_FlyUndos[ n-1 ]->UndoImpl(rContext);
222         }
223         nNdDiff += nTmp - pPam->GetPoint()->nNode.GetIndex();
224     }
225 
226     SwNodeIndex& rIdx = pPam->GetPoint()->nNode;
227     SwTxtNode* pTxtNode = rIdx.GetNode().GetTxtNode();
228     if( pTxtNode )
229     {
230         if( !pTxtFmtColl )      // falls 0, dann war hier auch kein TextNode,
231         {                       // dann muss dieser geloescht werden,
232             SwNodeIndex aDelIdx( rIdx );
233             rIdx++;
234             SwCntntNode* pCNd = rIdx.GetNode().GetCntntNode();
235             xub_StrLen nCnt = 0; if( pCNd ) nCnt = pCNd->Len();
236             pPam->GetPoint()->nContent.Assign( pCNd, nCnt );
237             pPam->SetMark();
238             pPam->DeleteMark();
239 
240             RemoveIdxRel( aDelIdx.GetIndex(), *pPam->GetPoint() );
241 
242             pDoc->GetNodes().Delete( aDelIdx, 1 );
243         }
244         else
245         {
246             if( bJoinNext && pTxtNode->CanJoinNext())
247             {
248                 {
249                     RemoveIdxRel( rIdx.GetIndex()+1, SwPosition( rIdx,
250                             SwIndex( pTxtNode, pTxtNode->GetTxt().Len() )));
251                 }
252                 pTxtNode->JoinNext();
253             }
254             // reset all text attributes in the paragraph!
255             pTxtNode->RstAttr( SwIndex(pTxtNode, 0), pTxtNode->Len(),
256                                 0, 0, true );
257 
258             // setze alle Attribute im Node zurueck
259             pTxtNode->ResetAllAttr();
260 
261             if( USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( pTxtFmtColl ))
262                 pTxtFmtColl = (SwTxtFmtColl*)pTxtNode->ChgFmtColl( pTxtFmtColl );
263 
264             pHistory->SetTmpEnd( nSetPos );
265             pHistory->TmpRollback( pDoc, 0, false );
266         }
267     }
268 }
269 
270 void SwUndoInserts::RedoImpl(::sw::UndoRedoContext & rContext)
271 {
272     // setze noch den Cursor auf den Redo-Bereich
273     SwPaM *const pPam(& rContext.GetCursorSupplier().CreateNewShellCursor());
274     SwDoc* pDoc = pPam->GetDoc();
275     pPam->DeleteMark();
276     pPam->GetPoint()->nNode = nSttNode - nNdDiff;
277     SwCntntNode* pCNd = pPam->GetCntntNode();
278     pPam->GetPoint()->nContent.Assign( pCNd, nSttCntnt );
279 
280     SwTxtFmtColl* pSavTxtFmtColl = pTxtFmtColl;
281     if( pTxtFmtColl && pCNd && pCNd->IsTxtNode() )
282         pSavTxtFmtColl = ((SwTxtNode*)pCNd)->GetTxtColl();
283 
284     pHistory->SetTmpEnd( nSetPos );
285 
286     // alte Anfangs-Position fuers Rollback zurueckholen
287     if( ( nSttNode != nEndNode || nSttCntnt != nEndCntnt ) && pPos )
288     {
289         sal_Bool bMvBkwrd = MovePtBackward( *pPam );
290 
291         // Inhalt wieder einfuegen. (erst pPos abmelden !!)
292         sal_uLong nMvNd = pPos->nNode.GetIndex();
293         xub_StrLen nMvCnt = pPos->nContent.GetIndex();
294         DELETEZ( pPos );
295         MoveFromUndoNds( *pDoc, nMvNd, nMvCnt, *pPam->GetMark() );
296         if( bSttWasTxtNd )
297             MovePtForward( *pPam, bMvBkwrd );
298         pPam->Exchange();
299     }
300 
301     if( USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( pTxtFmtColl ))
302     {
303         SwTxtNode* pTxtNd = pPam->GetMark()->nNode.GetNode().GetTxtNode();
304         if( pTxtNd )
305             pTxtNd->ChgFmtColl( pTxtFmtColl );
306     }
307     pTxtFmtColl = pSavTxtFmtColl;
308 
309     if( pLastNdColl && USHRT_MAX != pDoc->GetTxtFmtColls()->GetPos( pLastNdColl ) &&
310         pPam->GetPoint()->nNode != pPam->GetMark()->nNode )
311     {
312         SwTxtNode* pTxtNd = pPam->GetPoint()->nNode.GetNode().GetTxtNode();
313         if( pTxtNd )
314             pTxtNd->ChgFmtColl( pLastNdColl );
315     }
316 
317     for (size_t n = m_FlyUndos.size(); 0 < n; --n)
318     {
319         m_FlyUndos[ n-1 ]->RedoImpl(rContext);
320     }
321 
322     pHistory->Rollback( pDoc, nSetPos );
323 
324     if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
325     {
326         RedlineMode_t eOld = pDoc->GetRedlineMode();
327         pDoc->SetRedlineMode_intern((RedlineMode_t)( eOld & ~nsRedlineMode_t::REDLINE_IGNORE ));
328         pDoc->AppendRedline( new SwRedline( *pRedlData, *pPam ), true);
329         pDoc->SetRedlineMode_intern( eOld );
330     }
331     else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
332             pDoc->GetRedlineTbl().Count() )
333         pDoc->SplitRedline( *pPam );
334 }
335 
336 void SwUndoInserts::RepeatImpl(::sw::RepeatContext & rContext)
337 {
338     SwPaM aPam( rContext.GetDoc().GetNodes().GetEndOfContent() );
339     SetPaM( aPam );
340     SwPaM & rRepeatPaM( rContext.GetRepeatPaM() );
341     aPam.GetDoc()->CopyRange( aPam, *rRepeatPaM.GetPoint(), false );
342 }
343 
344 
345 //////////////////////////////////////////////////////////////////////////
346 
347 SwUndoInsDoc::SwUndoInsDoc( const SwPaM& rPam )
348     : SwUndoInserts( UNDO_INSDOKUMENT, rPam )
349 {
350 }
351 
352 SwUndoCpyDoc::SwUndoCpyDoc( const SwPaM& rPam )
353     : SwUndoInserts( UNDO_COPY, rPam )
354 {
355 }
356 
357