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
SwUndoRedline(SwUndoId nUsrId,const SwPaM & rRange)47 SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange )
48 : SwUndo( UNDO_REDLINE ), SwUndRng( rRange ),
49 mpRedlData( 0 ), mpRedlSaveData( 0 ), mnUserId( nUsrId ),
50 mbHiddenRedlines( sal_False )
51 {
52 // Redline beachten
53 SwDoc& rDoc = *rRange.GetDoc();
54 if( rDoc.IsRedlineOn() )
55 {
56 switch( mnUserId )
57 {
58 case UNDO_DELETE:
59 case UNDO_REPLACE:
60 mpRedlData = 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 mpRedlSaveData = new SwRedlineSaveDatas;
71 if( !FillSaveData( rRange, *mpRedlSaveData, sal_False,
72 UNDO_REJECT_REDLINE != mnUserId ))
73 delete mpRedlSaveData, mpRedlSaveData = 0;
74 else
75 {
76 mbHiddenRedlines = HasHiddenRedlines( *mpRedlSaveData );
77 if( mbHiddenRedlines ) // 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
~SwUndoRedline()86 SwUndoRedline::~SwUndoRedline()
87 {
88 delete mpRedlData;
89 delete mpRedlSaveData;
90 }
91
GetRedlSaveCount() const92 sal_uInt16 SwUndoRedline::GetRedlSaveCount() const
93 {
94 return mpRedlSaveData ? mpRedlSaveData->Count() : 0;
95 }
96
97
UndoImpl(::sw::UndoRedoContext & rContext)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( mpRedlSaveData )
106 {
107 sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex();
108 SetSaveData( *pDoc, *mpRedlSaveData );
109 if( mbHiddenRedlines )
110 {
111 mpRedlSaveData->DeleteAndDestroy( 0, mpRedlSaveData->Count() );
112
113 nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex() - nEndExtra;
114 nSttNode += nEndExtra;
115 nEndNode += nEndExtra;
116 }
117 SetPaM(rPam, true);
118 }
119 }
120
121
RedoImpl(::sw::UndoRedoContext & rContext)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( mpRedlSaveData && mbHiddenRedlines )
130 {
131 sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex();
132 FillSaveData(rPam, *mpRedlSaveData, sal_False,
133 UNDO_REJECT_REDLINE != mnUserId );
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
UndoRedlineImpl(SwDoc &,SwPaM &)146 void SwUndoRedline::UndoRedlineImpl(SwDoc &, SwPaM &)
147 {
148 }
149
150 // default: remove redlines
RedoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)151 void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
152 {
153 rDoc.DeleteRedline(rPam, true, USHRT_MAX);
154 }
155
156
157 // SwUndoRedlineDelete ///////////////////////////////////////////////////
158
SwUndoRedlineDelete(const SwPaM & rRange,SwUndoId nUsrId)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 == mnUserId &&
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
UndoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)181 void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
182 {
183 rDoc.DeleteRedline(rPam, true, USHRT_MAX);
184 }
185
RedoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)186 void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
187 {
188 if (rPam.GetPoint() != rPam.GetMark())
189 {
190 rDoc.AppendRedline( new SwRedline(*mpRedlData, rPam), sal_False );
191 }
192 }
193
CanGrouping(const SwUndoRedlineDelete & rNext)194 sal_Bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext )
195 {
196 sal_Bool bRet = sal_False;
197 if( UNDO_DELETE == mnUserId && mnUserId == rNext.mnUserId &&
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 (( !mpRedlSaveData && !rNext.mpRedlSaveData ) ||
213 ( mpRedlSaveData && rNext.mpRedlSaveData &&
214 SwUndo::CanRedlineGroup( *mpRedlSaveData,
215 *rNext.mpRedlSaveData, 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
SwUndoRedlineSort(const SwPaM & rRange,const SwSortOptions & rOpt)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
~SwUndoRedlineSort()238 SwUndoRedlineSort::~SwUndoRedlineSort()
239 {
240 delete pOpt;
241 }
242
UndoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)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
RedoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)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
RepeatImpl(::sw::RepeatContext & rContext)328 void SwUndoRedlineSort::RepeatImpl(::sw::RepeatContext & rContext)
329 {
330 rContext.GetDoc().SortText( rContext.GetRepeatPaM(), *pOpt );
331 }
332
SetSaveRange(const SwPaM & rRange)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
SetOffset(const SwNodeIndex & rIdx)340 void SwUndoRedlineSort::SetOffset( const SwNodeIndex& rIdx )
341 {
342 nOffset = rIdx.GetIndex() - nSttNode;
343 }
344
345 // SwUndoAcceptRedline ///////////////////////////////////////////////////
346
SwUndoAcceptRedline(const SwPaM & rRange)347 SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange )
348 : SwUndoRedline( UNDO_ACCEPT_REDLINE, rRange )
349 {
350 }
351
RedoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)352 void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
353 {
354 rDoc.AcceptRedline(rPam, false);
355 }
356
RepeatImpl(::sw::RepeatContext & rContext)357 void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext)
358 {
359 rContext.GetDoc().AcceptRedline(rContext.GetRepeatPaM(), true);
360 }
361
SwUndoRejectRedline(const SwPaM & rRange)362 SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange )
363 : SwUndoRedline( UNDO_REJECT_REDLINE, rRange )
364 {
365 }
366
RedoRedlineImpl(SwDoc & rDoc,SwPaM & rPam)367 void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
368 {
369 rDoc.RejectRedline(rPam, false);
370 }
371
RepeatImpl(::sw::RepeatContext & rContext)372 void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext)
373 {
374 rContext.GetDoc().RejectRedline(rContext.GetRepeatPaM(), true);
375 }
376
377 // SwUndoCompDoc /////////////////////////////////////////////////////////
378
SwUndoCompDoc(const SwPaM & rRg,sal_Bool bIns)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
SwUndoCompDoc(const SwRedline & rRedl)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
~SwUndoCompDoc()410 SwUndoCompDoc::~SwUndoCompDoc()
411 {
412 delete pRedlData;
413 delete pUnDel;
414 delete pUnDel2;
415 delete pRedlSaveData;
416 }
417
UndoImpl(::sw::UndoRedoContext & rContext)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
RedoImpl(::sw::UndoRedoContext & rContext)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