Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <UndoRedline.hxx>
21 : #include <hintids.hxx>
22 : #include <unotools/charclass.hxx>
23 : #include <doc.hxx>
24 : #include <swundo.hxx>
25 : #include <pam.hxx>
26 : #include <ndtxt.hxx>
27 : #include <UndoCore.hxx>
28 : #include <UndoDelete.hxx>
29 : #include <rolbck.hxx>
30 : #include <redline.hxx>
31 : #include <docary.hxx>
32 : #include <sortopt.hxx>
33 :
34 : extern void sw_JoinText( SwPaM& rPam, sal_Bool bJoinPrev );
35 : extern void sw_GetJoinFlags( SwPaM& rPam, sal_Bool& rJoinTxt, sal_Bool& rJoinPrev );
36 :
37 0 : SwUndoRedline::SwUndoRedline( SwUndoId nUsrId, const SwPaM& rRange )
38 : : SwUndo( UNDO_REDLINE ), SwUndRng( rRange ),
39 : pRedlData( 0 ), pRedlSaveData( 0 ), nUserId( nUsrId ),
40 0 : bHiddenRedlines( sal_False )
41 : {
42 : // consider Redline
43 0 : SwDoc& rDoc = *rRange.GetDoc();
44 0 : if( rDoc.IsRedlineOn() )
45 : {
46 0 : switch( nUserId )
47 : {
48 : case UNDO_DELETE:
49 : case UNDO_REPLACE:
50 0 : pRedlData = new SwRedlineData( nsRedlineType_t::REDLINE_DELETE, rDoc.GetRedlineAuthor() );
51 0 : break;
52 : default:
53 : ;
54 : }
55 0 : SetRedlineMode( rDoc.GetRedlineMode() );
56 : }
57 :
58 0 : sal_uLong nEndExtra = rDoc.GetNodes().GetEndOfExtras().GetIndex();
59 :
60 0 : pRedlSaveData = new SwRedlineSaveDatas;
61 0 : if( !FillSaveData( rRange, *pRedlSaveData, sal_False,
62 0 : UNDO_REJECT_REDLINE != nUserId ))
63 0 : delete pRedlSaveData, pRedlSaveData = 0;
64 : else
65 : {
66 0 : bHiddenRedlines = HasHiddenRedlines( *pRedlSaveData );
67 0 : if( bHiddenRedlines ) // then the NodeIndices of SwUndRng need to be corrected
68 : {
69 0 : nEndExtra -= rDoc.GetNodes().GetEndOfExtras().GetIndex();
70 0 : nSttNode -= nEndExtra;
71 0 : nEndNode -= nEndExtra;
72 : }
73 : }
74 0 : }
75 :
76 0 : SwUndoRedline::~SwUndoRedline()
77 : {
78 0 : delete pRedlData;
79 0 : delete pRedlSaveData;
80 0 : }
81 :
82 0 : sal_uInt16 SwUndoRedline::GetRedlSaveCount() const
83 : {
84 0 : return pRedlSaveData ? pRedlSaveData->size() : 0;
85 : }
86 :
87 0 : void SwUndoRedline::UndoImpl(::sw::UndoRedoContext & rContext)
88 : {
89 0 : SwDoc *const pDoc = & rContext.GetDoc();
90 0 : SwPaM & rPam( AddUndoRedoPaM(rContext) );
91 :
92 0 : UndoRedlineImpl(*pDoc, rPam);
93 :
94 0 : if( pRedlSaveData )
95 : {
96 0 : sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex();
97 0 : SetSaveData( *pDoc, *pRedlSaveData );
98 0 : if( bHiddenRedlines )
99 : {
100 0 : pRedlSaveData->DeleteAndDestroyAll();
101 :
102 0 : nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex() - nEndExtra;
103 0 : nSttNode += nEndExtra;
104 0 : nEndNode += nEndExtra;
105 : }
106 0 : SetPaM(rPam, true);
107 : }
108 0 : }
109 :
110 0 : void SwUndoRedline::RedoImpl(::sw::UndoRedoContext & rContext)
111 : {
112 0 : SwDoc *const pDoc = & rContext.GetDoc();
113 0 : RedlineMode_t eOld = pDoc->GetRedlineMode();
114 0 : pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
115 :
116 0 : SwPaM & rPam( AddUndoRedoPaM(rContext) );
117 0 : if( pRedlSaveData && bHiddenRedlines )
118 : {
119 0 : sal_uLong nEndExtra = pDoc->GetNodes().GetEndOfExtras().GetIndex();
120 : FillSaveData(rPam, *pRedlSaveData, sal_False,
121 0 : UNDO_REJECT_REDLINE != nUserId );
122 :
123 0 : nEndExtra -= pDoc->GetNodes().GetEndOfExtras().GetIndex();
124 0 : nSttNode -= nEndExtra;
125 0 : nEndNode -= nEndExtra;
126 : }
127 :
128 0 : RedoRedlineImpl(*pDoc, rPam);
129 :
130 0 : SetPaM(rPam, true);
131 0 : pDoc->SetRedlineMode_intern( eOld );
132 0 : }
133 :
134 0 : void SwUndoRedline::UndoRedlineImpl(SwDoc &, SwPaM &)
135 : {
136 0 : }
137 :
138 : // default: remove redlines
139 0 : void SwUndoRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
140 : {
141 0 : rDoc.DeleteRedline(rPam, true, USHRT_MAX);
142 0 : }
143 :
144 0 : SwUndoRedlineDelete::SwUndoRedlineDelete( const SwPaM& rRange, SwUndoId nUsrId )
145 : : SwUndoRedline( nUsrId ? nUsrId : UNDO_DELETE, rRange ),
146 0 : bCanGroup( sal_False ), bIsDelim( sal_False ), bIsBackspace( sal_False )
147 : {
148 : const SwTxtNode* pTNd;
149 0 : if( UNDO_DELETE == nUserId &&
150 : nSttNode == nEndNode && nSttCntnt + 1 == nEndCntnt &&
151 0 : 0 != (pTNd = rRange.GetNode()->GetTxtNode()) )
152 : {
153 0 : sal_Unicode cCh = pTNd->GetTxt().GetChar( nSttCntnt );
154 0 : if( CH_TXTATR_BREAKWORD != cCh && CH_TXTATR_INWORD != cCh )
155 : {
156 0 : bCanGroup = sal_True;
157 0 : bIsDelim = !GetAppCharClass().isLetterNumeric( pTNd->GetTxt(),
158 0 : nSttCntnt );
159 0 : bIsBackspace = nSttCntnt == rRange.GetPoint()->nContent.GetIndex();
160 : }
161 : }
162 :
163 0 : bCacheComment = false;
164 0 : }
165 :
166 0 : void SwUndoRedlineDelete::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
167 : {
168 0 : rDoc.DeleteRedline(rPam, true, USHRT_MAX);
169 0 : }
170 :
171 0 : void SwUndoRedlineDelete::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
172 : {
173 0 : if (rPam.GetPoint() != rPam.GetMark())
174 : {
175 0 : rDoc.AppendRedline( new SwRedline(*pRedlData, rPam), sal_False );
176 : }
177 0 : }
178 :
179 0 : sal_Bool SwUndoRedlineDelete::CanGrouping( const SwUndoRedlineDelete& rNext )
180 : {
181 0 : sal_Bool bRet = sal_False;
182 0 : if( UNDO_DELETE == nUserId && nUserId == rNext.nUserId &&
183 : bCanGroup == rNext.bCanGroup &&
184 : bIsDelim == rNext.bIsDelim &&
185 : bIsBackspace == rNext.bIsBackspace &&
186 : nSttNode == nEndNode &&
187 : rNext.nSttNode == nSttNode &&
188 : rNext.nEndNode == nEndNode )
189 : {
190 0 : int bIsEnd = 0;
191 0 : if( rNext.nSttCntnt == nEndCntnt )
192 0 : bIsEnd = 1;
193 0 : else if( rNext.nEndCntnt == nSttCntnt )
194 0 : bIsEnd = -1;
195 :
196 0 : if( bIsEnd &&
197 0 : (( !pRedlSaveData && !rNext.pRedlSaveData ) ||
198 : ( pRedlSaveData && rNext.pRedlSaveData &&
199 : SwUndo::CanRedlineGroup( *pRedlSaveData,
200 0 : *rNext.pRedlSaveData, 1 != bIsEnd )
201 : )))
202 : {
203 0 : if( 1 == bIsEnd )
204 0 : nEndCntnt = rNext.nEndCntnt;
205 : else
206 0 : nSttCntnt = rNext.nSttCntnt;
207 0 : bRet = sal_True;
208 : }
209 : }
210 0 : return bRet;
211 : }
212 :
213 0 : SwUndoRedlineSort::SwUndoRedlineSort( const SwPaM& rRange,
214 : const SwSortOptions& rOpt )
215 : : SwUndoRedline( UNDO_SORT_TXT, rRange ),
216 0 : pOpt( new SwSortOptions( rOpt ) ),
217 0 : nSaveEndNode( nEndNode ), nOffset( 0 ), nSaveEndCntnt( nEndCntnt )
218 : {
219 0 : }
220 :
221 0 : SwUndoRedlineSort::~SwUndoRedlineSort()
222 : {
223 0 : delete pOpt;
224 0 : }
225 :
226 0 : void SwUndoRedlineSort::UndoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
227 : {
228 : // rPam contains the sorted range
229 : // aSaveRange contains copied (i.e. original) range
230 :
231 0 : SwPosition *const pStart = rPam.Start();
232 0 : SwPosition *const pEnd = rPam.End();
233 :
234 0 : SwNodeIndex aPrevIdx( pStart->nNode, -1 );
235 0 : sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex();
236 :
237 0 : if( 0 == ( nsRedlineMode_t::REDLINE_SHOW_DELETE & rDoc.GetRedlineMode()) )
238 : {
239 : // Search both Redline objects and make them visible to make the nodes
240 : // consistent again. The 'delete' one is hidden, thus search for the
241 : // 'insert' Redline object. The former is located directly after the latter.
242 : sal_uInt16 nFnd = rDoc.GetRedlinePos(
243 0 : *rDoc.GetNodes()[ nSttNode + 1 ],
244 0 : nsRedlineType_t::REDLINE_INSERT );
245 : OSL_ENSURE( USHRT_MAX != nFnd && nFnd+1 < (sal_uInt16)rDoc.GetRedlineTbl().size(),
246 : "could not find an Insert object" );
247 0 : ++nFnd;
248 0 : rDoc.GetRedlineTbl()[nFnd]->Show( 1 );
249 : }
250 :
251 : {
252 0 : SwPaM aTmp( *rPam.GetMark() );
253 0 : aTmp.GetMark()->nContent = 0;
254 0 : aTmp.SetMark();
255 0 : aTmp.GetPoint()->nNode = nSaveEndNode;
256 0 : aTmp.GetPoint()->nContent.Assign( aTmp.GetCntntNode(), nSaveEndCntnt );
257 0 : rDoc.DeleteRedline( aTmp, true, USHRT_MAX );
258 : }
259 :
260 0 : rDoc.DelFullPara(rPam);
261 :
262 0 : SwPaM *const pPam = & rPam;
263 0 : pPam->DeleteMark();
264 0 : pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 );
265 0 : SwCntntNode* pCNd = pPam->GetCntntNode();
266 0 : pPam->GetPoint()->nContent.Assign(pCNd, 0 );
267 0 : pPam->SetMark();
268 :
269 0 : pPam->GetPoint()->nNode += nOffsetTemp;
270 0 : pCNd = pPam->GetCntntNode();
271 0 : pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
272 :
273 0 : SetValues( *pPam );
274 :
275 0 : SetPaM(rPam);
276 0 : }
277 :
278 0 : void SwUndoRedlineSort::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
279 : {
280 0 : SwPaM* pPam = &rPam;
281 0 : SwPosition* pStart = pPam->Start();
282 0 : SwPosition* pEnd = pPam->End();
283 :
284 0 : SwNodeIndex aPrevIdx( pStart->nNode, -1 );
285 0 : sal_uLong nOffsetTemp = pEnd->nNode.GetIndex() - pStart->nNode.GetIndex();
286 0 : xub_StrLen nCntStt = pStart->nContent.GetIndex();
287 :
288 0 : rDoc.SortText(rPam, *pOpt);
289 :
290 0 : pPam->DeleteMark();
291 0 : pPam->GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 );
292 0 : SwCntntNode* pCNd = pPam->GetCntntNode();
293 0 : xub_StrLen nLen = pCNd->Len();
294 0 : if( nLen > nCntStt )
295 0 : nLen = nCntStt;
296 0 : pPam->GetPoint()->nContent.Assign(pCNd, nLen );
297 0 : pPam->SetMark();
298 :
299 0 : pPam->GetPoint()->nNode += nOffsetTemp;
300 0 : pCNd = pPam->GetCntntNode();
301 0 : pPam->GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
302 :
303 0 : SetValues( rPam );
304 :
305 0 : SetPaM( rPam );
306 0 : rPam.GetPoint()->nNode = nSaveEndNode;
307 0 : rPam.GetPoint()->nContent.Assign( rPam.GetCntntNode(), nSaveEndCntnt );
308 0 : }
309 :
310 0 : void SwUndoRedlineSort::RepeatImpl(::sw::RepeatContext & rContext)
311 : {
312 0 : rContext.GetDoc().SortText( rContext.GetRepeatPaM(), *pOpt );
313 0 : }
314 :
315 0 : void SwUndoRedlineSort::SetSaveRange( const SwPaM& rRange )
316 : {
317 0 : const SwPosition& rPos = *rRange.End();
318 0 : nSaveEndNode = rPos.nNode.GetIndex();
319 0 : nSaveEndCntnt = rPos.nContent.GetIndex();
320 0 : }
321 :
322 0 : void SwUndoRedlineSort::SetOffset( const SwNodeIndex& rIdx )
323 : {
324 0 : nOffset = rIdx.GetIndex() - nSttNode;
325 0 : }
326 :
327 0 : SwUndoAcceptRedline::SwUndoAcceptRedline( const SwPaM& rRange )
328 0 : : SwUndoRedline( UNDO_ACCEPT_REDLINE, rRange )
329 : {
330 0 : }
331 :
332 0 : void SwUndoAcceptRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
333 : {
334 0 : rDoc.AcceptRedline(rPam, false);
335 0 : }
336 :
337 0 : void SwUndoAcceptRedline::RepeatImpl(::sw::RepeatContext & rContext)
338 : {
339 0 : rContext.GetDoc().AcceptRedline(rContext.GetRepeatPaM(), true);
340 0 : }
341 :
342 0 : SwUndoRejectRedline::SwUndoRejectRedline( const SwPaM& rRange )
343 0 : : SwUndoRedline( UNDO_REJECT_REDLINE, rRange )
344 : {
345 0 : }
346 :
347 0 : void SwUndoRejectRedline::RedoRedlineImpl(SwDoc & rDoc, SwPaM & rPam)
348 : {
349 0 : rDoc.RejectRedline(rPam, false);
350 0 : }
351 :
352 0 : void SwUndoRejectRedline::RepeatImpl(::sw::RepeatContext & rContext)
353 : {
354 0 : rContext.GetDoc().RejectRedline(rContext.GetRepeatPaM(), true);
355 0 : }
356 :
357 0 : SwUndoCompDoc::SwUndoCompDoc( const SwPaM& rRg, sal_Bool bIns )
358 : : SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRg ), pRedlData( 0 ),
359 0 : pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ), bInsert( bIns )
360 : {
361 0 : SwDoc* pDoc = (SwDoc*)rRg.GetDoc();
362 0 : if( pDoc->IsRedlineOn() )
363 : {
364 0 : RedlineType_t eTyp = bInsert ? nsRedlineType_t::REDLINE_INSERT : nsRedlineType_t::REDLINE_DELETE;
365 0 : pRedlData = new SwRedlineData( eTyp, pDoc->GetRedlineAuthor() );
366 0 : SetRedlineMode( pDoc->GetRedlineMode() );
367 : }
368 0 : }
369 :
370 0 : SwUndoCompDoc::SwUndoCompDoc( const SwRedline& rRedl )
371 : : SwUndo( UNDO_COMPAREDOC ), SwUndRng( rRedl ), pRedlData( 0 ),
372 : pUnDel( 0 ), pUnDel2( 0 ), pRedlSaveData( 0 ),
373 : // for MergeDoc the corresponding inverse is needed
374 0 : bInsert( nsRedlineType_t::REDLINE_DELETE == rRedl.GetType() )
375 : {
376 0 : SwDoc* pDoc = (SwDoc*)rRedl.GetDoc();
377 0 : if( pDoc->IsRedlineOn() )
378 : {
379 0 : pRedlData = new SwRedlineData( rRedl.GetRedlineData() );
380 0 : SetRedlineMode( pDoc->GetRedlineMode() );
381 : }
382 :
383 0 : pRedlSaveData = new SwRedlineSaveDatas;
384 0 : if( !FillSaveData( rRedl, *pRedlSaveData, sal_False, sal_True ))
385 0 : delete pRedlSaveData, pRedlSaveData = 0;
386 0 : }
387 :
388 0 : SwUndoCompDoc::~SwUndoCompDoc()
389 : {
390 0 : delete pRedlData;
391 0 : delete pUnDel;
392 0 : delete pUnDel2;
393 0 : delete pRedlSaveData;
394 0 : }
395 :
396 0 : void SwUndoCompDoc::UndoImpl(::sw::UndoRedoContext & rContext)
397 : {
398 0 : SwDoc *const pDoc = & rContext.GetDoc();
399 0 : SwPaM *const pPam( & AddUndoRedoPaM(rContext) );
400 :
401 0 : if( !bInsert )
402 : {
403 : // delete Redlines
404 0 : RedlineMode_t eOld = pDoc->GetRedlineMode();
405 0 : pDoc->SetRedlineMode_intern((RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON));
406 :
407 0 : pDoc->DeleteRedline( *pPam, true, USHRT_MAX );
408 :
409 0 : pDoc->SetRedlineMode_intern( eOld );
410 :
411 : // per definition Point is end (in SwUndRng!)
412 0 : SwCntntNode* pCSttNd = pPam->GetCntntNode( sal_False );
413 0 : SwCntntNode* pCEndNd = pPam->GetCntntNode( sal_True );
414 :
415 : // if start- and end-content is zero, then the doc-compare moves
416 : // complete nodes into the current doc. And then the selection
417 : // must be from end to start, so the delete join into the right
418 : // direction.
419 0 : if( !nSttCntnt && !nEndCntnt )
420 0 : pPam->Exchange();
421 :
422 : sal_Bool bJoinTxt, bJoinPrev;
423 0 : sw_GetJoinFlags( *pPam, bJoinTxt, bJoinPrev );
424 :
425 0 : pUnDel = new SwUndoDelete( *pPam, sal_False );
426 :
427 0 : if( bJoinTxt )
428 0 : sw_JoinText( *pPam, bJoinPrev );
429 :
430 0 : if( pCSttNd && !pCEndNd)
431 : {
432 : // #112139# Do not step behind the end of content.
433 0 : SwNode * pTmp = pPam->GetNode(sal_True);
434 0 : if (pTmp)
435 : {
436 0 : SwNode * pEnd = pDoc->GetNodes().DocumentSectionEndNode(pTmp);
437 :
438 0 : if (pTmp != pEnd)
439 : {
440 0 : pPam->SetMark();
441 0 : pPam->GetPoint()->nNode++;
442 0 : pPam->GetBound( sal_True ).nContent.Assign( 0, 0 );
443 0 : pPam->GetBound( sal_False ).nContent.Assign( 0, 0 );
444 0 : pUnDel2 = new SwUndoDelete( *pPam, sal_True );
445 : }
446 : }
447 : }
448 0 : pPam->DeleteMark();
449 : }
450 : else
451 : {
452 0 : if( IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
453 : {
454 0 : pDoc->DeleteRedline( *pPam, true, USHRT_MAX );
455 :
456 0 : if( pRedlSaveData )
457 0 : SetSaveData( *pDoc, *pRedlSaveData );
458 : }
459 0 : SetPaM(*pPam, true);
460 : }
461 0 : }
462 :
463 0 : void SwUndoCompDoc::RedoImpl(::sw::UndoRedoContext & rContext)
464 : {
465 0 : SwDoc *const pDoc = & rContext.GetDoc();
466 0 : SwPaM *const pPam( & AddUndoRedoPaM(rContext) );
467 :
468 0 : if( bInsert )
469 : {
470 0 : if( pRedlData && IDocumentRedlineAccess::IsRedlineOn( GetRedlineMode() ))
471 : {
472 0 : SwRedline* pTmp = new SwRedline( *pRedlData, *pPam );
473 0 : ((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp );
474 0 : pTmp->InvalidateRange();
475 : }
476 0 : else if( !( nsRedlineMode_t::REDLINE_IGNORE & GetRedlineMode() ) &&
477 0 : !pDoc->GetRedlineTbl().empty() )
478 0 : pDoc->SplitRedline( *pPam );
479 : }
480 : else
481 : {
482 0 : if( pUnDel2 )
483 : {
484 0 : pUnDel2->UndoImpl(rContext);
485 0 : delete pUnDel2, pUnDel2 = 0;
486 : }
487 0 : pUnDel->UndoImpl(rContext);
488 0 : delete pUnDel, pUnDel = 0;
489 :
490 0 : SetPaM( *pPam );
491 :
492 0 : SwRedline* pTmp = new SwRedline( *pRedlData, *pPam );
493 0 : ((SwRedlineTbl&)pDoc->GetRedlineTbl()).Insert( pTmp );
494 0 : if (pTmp) // #i19649#
495 0 : pTmp->InvalidateRange();
496 : }
497 :
498 0 : SetPaM(*pPam, true);
499 0 : }
500 :
501 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|