xref: /trunk/main/sw/source/core/undo/untblk.cxx (revision 352af06a)
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