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