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