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