xref: /AOO41X/main/sw/source/core/undo/unredln.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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 <UndoRedline.hxx>
32 
33 #include <hintids.hxx>
34 #include <unotools/charclass.hxx>
35 #include <doc.hxx>
36 #include <swundo.hxx>			// fuer die UndoIds
37 #include <pam.hxx>
38 #include <ndtxt.hxx>
39 #include <UndoCore.hxx>
40 #include <UndoDelete.hxx>
41 #include <rolbck.hxx>
42 #include <redline.hxx>
43 #include <docary.hxx>
44 #include <sortopt.hxx>
45 
46 extern void lcl_JoinText( SwPaM& rPam, sal_Bool bJoinPrev );
47 extern void lcl_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev );
48 
49 //------------------------------------------------------------------
50 
51 SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange )
52 	: SwUndo( UNDO_REDLINE ), SwUndRng( rRange ),
53 	pRedlData( 0 ), pRedlSaveData( 0 ), nUserId( nUsrId ),
54 	bHiddenRedlines( sal_False )
55 {
56 	// Redline beachten
57 	SwDoc& rDoc = *rRange.GetDoc();
58 	if( rDoc.IsRedlineOn() )
59 	{
60 		switch( nUserId )
61 		{
62 		case UNDO_DELETE:
63 		case UNDO_REPLACE:
64 			pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_DELETE, rDoc.GetRedlineAuthor() );
65 			break;
66         default:
67             ;
68 		}
69 		SetRedlineMode( rDoc.GetRedlineMode() );
70 	}
71 
72 	sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex();
73 
74 	pRedlSaveData = new SwRedlineSaveDatas;
75 	if( !FillSaveData( rRange, *pRedlSaveData, sal_False,
76 						UNDO_REJECT_REDLINE != nUserId ))
77 		delete pRedlSaveData, pRedlSaveData = 0;
78 	else
79 	{
80 		bHiddenRedlines = HasHiddenRedlines( *pRedlSaveData );
81 		if( bHiddenRedlines ) 			// dann muessen die NodeIndizies
82 		{   							// vom SwUndRng korrigiert werden
83 			nEndExtra -= rDoc.GetNodes().GetEndOfExtras().GetIndex();
84 			nSttNode -= nEndExtra;
85 			nEndNode -= nEndExtra;
86 		}
87 	}
88 }
89 
90 SwUndoRedline::~SwUndoRedline()
91 {
92 	delete pRedlData;
93 	delete pRedlSaveData;
94 }
95 
96 sal_uInt16 SwUndoRedline::GetRedlSaveCount() const
97 {
98     return pRedlSaveData ? pRedlSaveData->Count() : 0;
99 }
100 
101 
102 void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & rContext)
103 {
104     SwDoc *const pDoc = & rContext.GetDoc();
105     SwPaM & rPam( AddUndoRedoPaM(rContext) );
106 
107     UndoRedlineImpl(*pDoc, rPam);
108 
109 	if( pRedlSaveData )
110 	{
111 		sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex();
112 		SetSaveData( *pDoc, *pRedlSaveData );
113 		if( bHiddenRedlines )
114 		{
115 			pRedlSaveData->DeleteAndDestroy( 0, pRedlSaveData->Count() );
116 
117 			nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex() - nEndExtra;
118 			nSttNode += nEndExtra;
119 			nEndNode += nEndExtra;
120 		}
121         SetPaM(rPam, true);
122     }
123 }
124 
125 
126 void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & rContext)
127 {
128     SwDoc *const pDoc = & rContext.GetDoc();
129 	RedlineMode_t eOld = pDoc->GetRedlineMode();
130 	pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
131 
132     SwPaM & rPam( AddUndoRedoPaM(rContext) );
133 	if( pRedlSaveData && bHiddenRedlines )
134 	{
135 		sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex();
136         FillSaveData(rPam, *pRedlSaveData, sal_False,
137 						UNDO_REJECT_REDLINE != nUserId );
138 
139 		nEndExtra -= pDoc->GetNodes().GetEndOfExtras().GetIndex();
140 		nSttNode -= nEndExtra;
141 		nEndNode -= nEndExtra;
142 	}
143 
144     RedoRedlineImpl(*pDoc, rPam);
145 
146     SetPaM(rPam, true);
147 	pDoc->SetRedlineMode_intern( eOld );
148 }
149 
150 void SwUndoRedline::UndoRedlineImpl(SwDoc &, SwPaM &)
151 {
152 }
153 
154 // default: remove redlines
155 void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
156 {
157     rDoc.DeleteRedline(rPam, true, USHRT_MAX);
158 }
159 
160 
161 // SwUndoRedlineDelete ///////////////////////////////////////////////////
162 
163 SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId )
164     : SwUndoRedline( nUsrId = (nUsrId ? nUsrId : UNDO_DELETE), rRange ),
165 	bCanGroup( sal_False ), bIsDelim( sal_False ), bIsBackspace( sal_False )
166 {
167 	const SwTxtNode* pTNd;
168 	if( UNDO_DELETE == nUserId &&
169 		nSttNode == nEndNode && nSttCntnt + 1 == nEndCntnt &&
170 		0 != (pTNd = rRange.GetNode()->GetTxtNode()) )
171 	{
172 		sal_Unicode cCh = pTNd->GetTxt().GetChar( nSttCntnt );
173 		if( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh )
174 		{
175 			bCanGroup = sal_True;
176 			bIsDelim = !GetAppCharClass().isLetterNumeric( pTNd->GetTxt(),
177 															nSttCntnt );
178 			bIsBackspace = nSttCntnt == rRange.GetPoint()->nContent.GetIndex();
179 		}
180 	}
181 
182     bCacheComment = false;
183 }
184 
185 void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
186 {
187     rDoc.DeleteRedline(rPam, true, USHRT_MAX);
188 }
189 
190 void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
191 {
192     if (rPam.GetPoint() != rPam.GetMark())
193     {
194         rDoc.AppendRedline( new SwRedline(*pRedlData, rPam), sal_False );
195     }
196 }
197 
198 sal_Bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext )
199 {
200 	sal_Bool bRet = sal_False;
201 	if( UNDO_DELETE == nUserId && nUserId == rNext.nUserId &&
202 		bCanGroup == rNext.bCanGroup &&
203 		bIsDelim == rNext.bIsDelim &&
204 		bIsBackspace == rNext.bIsBackspace &&
205 		nSttNode == nEndNode &&
206 		rNext.nSttNode == nSttNode &&
207 		rNext.nEndNode == nEndNode )
208 	{
209 		int bIsEnd = 0;
210 		if( rNext.nSttCntnt == nEndCntnt )
211 			bIsEnd = 1;
212 		else if( rNext.nEndCntnt == nSttCntnt )
213 			bIsEnd = -1;
214 
215 		if( bIsEnd &&
216 			(( !pRedlSaveData && !rNext.pRedlSaveData ) ||
217 			 ( pRedlSaveData && rNext.pRedlSaveData &&
218 				SwUndo::CanRedlineGroup( *pRedlSaveData,
219 							*rNext.pRedlSaveData, 1 != bIsEnd )
220 			 )))
221 		{
222 			if( 1 == bIsEnd )
223 				nEndCntnt = rNext.nEndCntnt;
224 			else
225 				nSttCntnt = rNext.nSttCntnt;
226 			bRet = sal_True;
227 		}
228 	}
229 	return bRet;
230 }
231 
232 /*  */
233 
234 SwUndoRedlineSort::SwUndoRedlineSort( const SwPaM& rRange,
235 									const SwSortOptions& rOpt )
236 	: SwUndoRedline( UNDO_SORT_TXT, rRange ),
237 	pOpt( new SwSortOptions( rOpt ) ),
238 	nSaveEndNode( nEndNode ), nOffset( 0 ), nSaveEndCntnt( nEndCntnt )
239 {
240 }
241 
242 SwUndoRedlineSort::~SwUndoRedlineSort()
243 {
244 	delete pOpt;
245 }
246 
247 void SwUndoRedlineSort::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
248 {
249     // rPam contains the sorted range
250     // aSaveRange contains copied (i.e. original) range
251 
252     SwPosition *const pStart = rPam.Start();
253     SwPosition *const pEnd   = rPam.End();
254 
255 	SwNodeIndex aPrevIdx( pStart->nNode, -1 );
256 	sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex();
257 
258 	if( 0 == ( nsRedlineMode_t::REDLINE_SHOW_DELETE & rDoc.GetRedlineMode()) )
259 	{
260 		// die beiden Redline Objecte suchen und diese dann anzeigen lassen,
261 		// damit die Nodes wieder uebereinstimmen!
262 		// das Geloeschte ist versteckt, also suche das INSERT
263 		// Redline Object. Dahinter steht das Geloeschte
264 		sal_uInt16 nFnd = rDoc.GetRedlinePos(
265 							*rDoc.GetNodes()[ nSttNode + 1 ],
266 							nsRedlineType_t::REDLINE_INSERT );
267 		ASSERT( USHRT_MAX != nFnd && nFnd+1 < rDoc.GetRedlineTbl().Count(),
268 					"kein Insert Object gefunden" );
269 		++nFnd;
270 		rDoc.GetRedlineTbl()[nFnd]->Show( 1 );
271 	}
272 
273 	{
274         SwPaM aTmp( *rPam.GetMark() );
275 		aTmp.GetMark()->nContent = 0;
276 		aTmp.SetMark();
277 		aTmp.GetPoint()->nNode = nSaveEndNode;
278 		aTmp.GetPoint()->nContent.Assign( aTmp.GetCntntNode(), nSaveEndCntnt );
279 		rDoc.DeleteRedline( aTmp, true, USHRT_MAX );
280 	}
281 
282     rDoc.DelFullPara(rPam);
283 
284     SwPaM *const pPam = & rPam;
285 	pPam->DeleteMark();
286 	pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 );
287 	SwCntntNode* pCNd = pPam->GetCntntNode();
288 	pPam->GetPoint()->nContent.Assign(pCNd, 0 );
289 	pPam->SetMark();
290 
291 	pPam->GetPoint()->nNode += nOffsetTemp;
292 	pCNd = pPam->GetCntntNode();
293 	pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
294 
295 	SetValues( *pPam );
296 
297     SetPaM(rPam);
298 }
299 
300 void SwUndoRedlineSort::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
301 {
302 	SwPaM* pPam = &rPam;
303 	SwPosition* pStart = pPam->Start();
304 	SwPosition* pEnd   = pPam->End();
305 
306 	SwNodeIndex aPrevIdx( pStart->nNode, -1 );
307 	sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex();
308 	xub_StrLen nCntStt	= pStart->nContent.GetIndex();
309 
310     rDoc.SortText(rPam, *pOpt);
311 
312 	pPam->DeleteMark();
313 	pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 );
314 	SwCntntNode* pCNd = pPam->GetCntntNode();
315 	xub_StrLen nLen = pCNd->Len();
316 	if( nLen > nCntStt )
317 		nLen = nCntStt;
318 	pPam->GetPoint()->nContent.Assign(pCNd, nLen );
319 	pPam->SetMark();
320 
321 	pPam->GetPoint()->nNode += nOffsetTemp;
322 	pCNd = pPam->GetCntntNode();
323 	pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
324 
325 	SetValues( rPam );
326 
327 	SetPaM( rPam );
328 	rPam.GetPoint()->nNode = nSaveEndNode;
329 	rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), nSaveEndCntnt );
330 }
331 
332 void SwUndoRedlineSort::RepeatImpl(::sw::RepeatContext & rContext)
333 {
334     rContext.GetDoc().SortText( rContext.GetRepeatPaM(), *pOpt );
335 }
336 
337 void SwUndoRedlineSort::SetSaveRange( const SwPaM& rRange )
338 {
339 	const SwPosition& rPos = *rRange.End();
340 	nSaveEndNode = rPos.nNode.GetIndex();
341 	nSaveEndCntnt = rPos.nContent.GetIndex();
342 }
343 
344 void SwUndoRedlineSort::SetOffset( const SwNodeIndex& rIdx )
345 {
346 	nOffset = rIdx.GetIndex() - nSttNode;
347 }
348 
349 // SwUndoAcceptRedline ///////////////////////////////////////////////////
350 
351 SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange )
352 	: SwUndoRedline( UNDO_ACCEPT_REDLINE, rRange )
353 {
354 }
355 
356 void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
357 {
358     rDoc.AcceptRedline(rPam, false);
359 }
360 
361 void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext)
362 {
363     rContext.GetDoc().AcceptRedline(rContext.GetRepeatPaM(), true);
364 }
365 
366 SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange )
367 	: SwUndoRedline( UNDO_REJECT_REDLINE, rRange )
368 {
369 }
370 
371 void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
372 {
373     rDoc.RejectRedline(rPam, false);
374 }
375 
376 void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext)
377 {
378     rContext.GetDoc().RejectRedline(rContext.GetRepeatPaM(), true);
379 }
380 
381 // SwUndoCompDoc /////////////////////////////////////////////////////////
382 
383 SwUndoCompDoc::SwUndoCompDoc( const SwPaM& rRg, sal_Bool bIns )
384 	: SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRg ), pRedlData( 0 ),
385 	pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ), bInsert( bIns )
386 {
387 	SwDoc* pDoc = (SwDoc*)rRg.GetDoc();
388 	if( pDoc->IsRedlineOn() )
389 	{
390 		RedlineType_t eTyp = bInsert ? nsRedlineType_t::REDLINE_INSERT : nsRedlineType_t::REDLINE_DELETE;
391 		pRedlData = new SwRedlineData( eTyp, pDoc->GetRedlineAuthor() );
392 		SetRedlineMode( pDoc->GetRedlineMode() );
393 	}
394 }
395 
396 SwUndoCompDoc::SwUndoCompDoc( const SwRedline& rRedl )
397 	: SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRedl ), pRedlData( 0 ),
398 	pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ),
399 	// fuers MergeDoc wird aber der jeweils umgekehrte Zweig benoetigt!
400 	bInsert( nsRedlineType_t::REDLINE_DELETE == rRedl.GetType() )
401 {
402 	SwDoc* pDoc = (SwDoc*)rRedl.GetDoc();
403 	if( pDoc->IsRedlineOn() )
404 	{
405 		pRedlData = new SwRedlineData( rRedl.GetRedlineData() );
406 		SetRedlineMode( pDoc->GetRedlineMode() );
407 	}
408 
409 	pRedlSaveData = new SwRedlineSaveDatas;
410 	if( !FillSaveData( rRedl, *pRedlSaveData, sal_False, sal_True ))
411 		delete pRedlSaveData, pRedlSaveData = 0;
412 }
413 
414 SwUndoCompDoc::~SwUndoCompDoc()
415 {
416 	delete pRedlData;
417 	delete pUnDel;
418 	delete pUnDel2;
419 	delete pRedlSaveData;
420 }
421 
422 void SwUndoCompDoc::UndoImpl(::sw::UndoRedoContext & rContext)
423 {
424     SwDoc *const pDoc = & rContext.GetDoc();
425     SwPaM *const pPam( & AddUndoRedoPaM(rContext) );
426 
427 	if( !bInsert )
428 	{
429 		// die Redlines loeschen
430 		RedlineMode_t eOld = pDoc->GetRedlineMode();
431 		pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON));
432 
433 		pDoc->DeleteRedline( *pPam, true, USHRT_MAX );
434 
435 		pDoc->SetRedlineMode_intern( eOld );
436 
437 		//per definition Point is end (in SwUndRng!)
438 		SwCntntNode* pCSttNd = pPam->GetCntntNode( sal_False );
439 		SwCntntNode* pCEndNd = pPam->GetCntntNode( sal_True );
440 
441 		// if start- and end-content is zero, then the doc-compare moves
442 		// complete nodes into the current doc. And then the selection
443 		// must be from end to start, so the delete join into the right
444 		// direction.
445 		if( !nSttCntnt && !nEndCntnt )
446 			pPam->Exchange();
447 
448 		sal_Bool bJoinTxt, bJoinPrev;
449 		::lcl_GetJoinFlags( *pPam, bJoinTxt, bJoinPrev );
450 
451 		pUnDel = new SwUndoDelete( *pPam, sal_False );
452 
453 		if( bJoinTxt )
454 			::lcl_JoinText( *pPam, bJoinPrev );
455 
456 		if( pCSttNd && !pCEndNd)
457 		{
458             // #112139# Do not step behind the end of content.
459             SwNode * pTmp = pPam->GetNode(sal_True);
460             if (pTmp)
461             {
462                 SwNode * pEnd = pDoc->GetNodes().DocumentSectionEndNode(pTmp);
463 
464                 if (pTmp != pEnd)
465                 {
466                     pPam->SetMark();
467                     pPam->GetPoint()->nNode++;
468                     pPam->GetBound( sal_True ).nContent.Assign( 0, 0 );
469                     pPam->GetBound( sal_False ).nContent.Assign( 0, 0 );
470                     pUnDel2 = new SwUndoDelete( *pPam, sal_True );
471                 }
472             }
473         }
474 		pPam->DeleteMark();
475 	}
476 	else
477 	{
478 		if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
479 		{
480 			pDoc->DeleteRedline( *pPam, true, USHRT_MAX );
481 
482 			if( pRedlSaveData )
483 				SetSaveData( *pDoc, *pRedlSaveData );
484 		}
485         SetPaM(*pPam, true);
486     }
487 }
488 
489 void SwUndoCompDoc::RedoImpl(::sw::UndoRedoContext & rContext)
490 {
491     SwDoc *const pDoc = & rContext.GetDoc();
492     SwPaM *const pPam( & AddUndoRedoPaM(rContext) );
493 
494 	if( bInsert )
495 	{
496 		if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
497 		{
498 			SwRedline* pTmp = new SwRedline( *pRedlData, *pPam );
499 			((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp );
500 			pTmp->InvalidateRange();
501 
502 /*
503 			SwRedlineMode eOld = pDoc->GetRedlineMode();
504 			pDoc->SetRedlineMode_intern( eOld & ~REDLINE_IGNORE );
505 			pDoc->AppendRedline( new SwRedline( *pRedlData, *pPam ));
506 			pDoc->SetRedlineMode_intern( eOld );
507 */
508 		}
509 		else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
510 				pDoc->GetRedlineTbl().Count() )
511 			pDoc->SplitRedline( *pPam );
512 	}
513 	else
514 	{
515 //		SwRedlineMode eOld = pDoc->GetRedlineMode();
516 //		pDoc->SetRedlineMode_intern( ( eOld & ~REDLINE_IGNORE) | REDLINE_ON );
517 
518 		if( pUnDel2 )
519         {
520             pUnDel2->UndoImpl(rContext);
521 			delete pUnDel2, pUnDel2 = 0;
522         }
523         pUnDel->UndoImpl(rContext);
524 		delete pUnDel, pUnDel = 0;
525 
526 		SetPaM( *pPam );
527 
528 		SwRedline* pTmp = new SwRedline( *pRedlData, *pPam );
529 		((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp );
530         if (pTmp) // #i19649#
531             pTmp->InvalidateRange();
532 
533 //		pDoc->SetRedlineMode_intern( eOld );
534 	}
535 
536     SetPaM(*pPam, true);
537 }
538 
539