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