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