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 <IShellCursorSupplier.hxx>
21 : #include <txtftn.hxx>
22 : #include <fmtanchr.hxx>
23 : #include <ftnidx.hxx>
24 : #include <frmfmt.hxx>
25 : #include <doc.hxx>
26 : #include <UndoManager.hxx>
27 : #include <docary.hxx>
28 : #include <swundo.hxx>
29 : #include <pam.hxx>
30 : #include <ndtxt.hxx>
31 : #include <UndoCore.hxx>
32 : #include <rolbck.hxx>
33 : #include <ndnotxt.hxx>
34 : #include <IMark.hxx>
35 : #include <mvsave.hxx>
36 : #include <redline.hxx>
37 : #include <crossrefbookmark.hxx>
38 : #include <undo.hrc>
39 : #include <comcore.hrc>
40 : #include <docsh.hxx>
41 :
42 : class SwRedlineSaveData: public SwUndRng, public SwRedlineData, private SwUndoSaveSection
43 : {
44 : public:
45 : SwRedlineSaveData(
46 : SwComparePosition eCmpPos,
47 : const SwPosition& rSttPos,
48 : const SwPosition& rEndPos,
49 : SwRangeRedline& rRedl,
50 : sal_Bool bCopyNext );
51 :
52 : ~SwRedlineSaveData();
53 :
54 : void RedlineToDoc( SwPaM& rPam );
55 :
56 0 : SwNodeIndex* GetMvSttIdx() const
57 : {
58 0 : return SwUndoSaveSection::GetMvSttIdx();
59 : }
60 :
61 : #if OSL_DEBUG_LEVEL > 0
62 : sal_uInt16 nRedlineCount;
63 : #endif
64 : };
65 :
66 : // This class saves the Pam as sal_uInt16s and can recompose those into a PaM
67 0 : SwUndRng::SwUndRng()
68 0 : : nSttNode( 0 ), nEndNode( 0 ), nSttCntnt( 0 ), nEndCntnt( 0 )
69 : {
70 0 : }
71 :
72 0 : SwUndRng::SwUndRng( const SwPaM& rPam )
73 : {
74 0 : SetValues( rPam );
75 0 : }
76 :
77 0 : void SwUndRng::SetValues( const SwPaM& rPam )
78 : {
79 0 : const SwPosition *pStt = rPam.Start();
80 0 : if( rPam.HasMark() )
81 : {
82 0 : const SwPosition *pEnd = rPam.GetPoint() == pStt
83 : ? rPam.GetMark()
84 0 : : rPam.GetPoint();
85 0 : nEndNode = pEnd->nNode.GetIndex();
86 0 : nEndCntnt = pEnd->nContent.GetIndex();
87 : }
88 : else
89 : // no selection !!
90 0 : nEndNode = 0, nEndCntnt = COMPLETE_STRING;
91 :
92 0 : nSttNode = pStt->nNode.GetIndex();
93 0 : nSttCntnt = pStt->nContent.GetIndex();
94 0 : }
95 :
96 0 : void SwUndRng::SetPaM( SwPaM & rPam, bool bCorrToCntnt ) const
97 : {
98 0 : rPam.DeleteMark();
99 0 : rPam.GetPoint()->nNode = nSttNode;
100 0 : SwNode* pNd = rPam.GetNode();
101 0 : if( pNd->IsCntntNode() )
102 0 : rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nSttCntnt );
103 0 : else if( bCorrToCntnt )
104 0 : rPam.Move( fnMoveForward, fnGoCntnt );
105 : else
106 0 : rPam.GetPoint()->nContent.Assign( 0, 0 );
107 :
108 0 : if( !nEndNode && COMPLETE_STRING == nEndCntnt ) // no selection
109 0 : return ;
110 :
111 0 : rPam.SetMark();
112 0 : if( nSttNode == nEndNode && nSttCntnt == nEndCntnt )
113 0 : return; // nothing left to do
114 :
115 0 : rPam.GetPoint()->nNode = nEndNode;
116 0 : if( (pNd = rPam.GetNode())->IsCntntNode() )
117 0 : rPam.GetPoint()->nContent.Assign( pNd->GetCntntNode(), nEndCntnt );
118 0 : else if( bCorrToCntnt )
119 0 : rPam.Move( fnMoveBackward, fnGoCntnt );
120 : else
121 0 : rPam.GetPoint()->nContent.Assign( 0, 0 );
122 : }
123 :
124 0 : SwPaM & SwUndRng::AddUndoRedoPaM(
125 : ::sw::UndoRedoContext & rContext, bool const bCorrToCntnt) const
126 : {
127 0 : SwPaM & rPaM( rContext.GetCursorSupplier().CreateNewShellCursor() );
128 0 : SetPaM( rPaM, bCorrToCntnt );
129 0 : return rPaM;
130 : }
131 :
132 0 : void SwUndo::RemoveIdxFromSection( SwDoc& rDoc, sal_uLong nSttIdx,
133 : sal_uLong* pEndIdx )
134 : {
135 0 : SwNodeIndex aIdx( rDoc.GetNodes(), nSttIdx );
136 0 : SwNodeIndex aEndIdx( rDoc.GetNodes(), pEndIdx ? *pEndIdx
137 0 : : aIdx.GetNode().EndOfSectionIndex() );
138 0 : SwPosition aPos( rDoc.GetNodes().GetEndOfPostIts() );
139 0 : rDoc.CorrAbs( aIdx, aEndIdx, aPos, sal_True );
140 0 : }
141 :
142 0 : void SwUndo::RemoveIdxFromRange( SwPaM& rPam, bool bMoveNext )
143 : {
144 0 : const SwPosition* pEnd = rPam.End();
145 0 : if( bMoveNext )
146 : {
147 0 : if( pEnd != rPam.GetPoint() )
148 0 : rPam.Exchange();
149 :
150 0 : SwNodeIndex aStt( rPam.GetMark()->nNode );
151 0 : SwNodeIndex aEnd( rPam.GetPoint()->nNode );
152 :
153 0 : if( !rPam.Move( fnMoveForward ) )
154 : {
155 0 : rPam.Exchange();
156 0 : if( !rPam.Move( fnMoveBackward ) )
157 : {
158 0 : rPam.GetPoint()->nNode = rPam.GetDoc()->GetNodes().GetEndOfPostIts();
159 0 : rPam.GetPoint()->nContent.Assign( 0, 0 );
160 : }
161 : }
162 :
163 0 : rPam.GetDoc()->CorrAbs( aStt, aEnd, *rPam.GetPoint(), sal_True );
164 : }
165 : else
166 0 : rPam.GetDoc()->CorrAbs( rPam, *pEnd, sal_True );
167 0 : }
168 :
169 0 : void SwUndo::RemoveIdxRel( sal_uLong nIdx, const SwPosition& rPos )
170 : {
171 : // Move only the Crsr. Bookmarks/TOXMarks/etc. are done by the corresponding
172 : // JoinNext/JoinPrev
173 0 : SwNodeIndex aIdx( rPos.nNode.GetNode().GetNodes(), nIdx );
174 0 : ::PaMCorrRel( aIdx, rPos );
175 0 : }
176 :
177 0 : SwUndo::SwUndo(SwUndoId const nId)
178 : : m_nId(nId), nOrigRedlineMode(nsRedlineMode_t::REDLINE_NONE),
179 0 : bCacheComment(true), pComment(NULL)
180 : {
181 0 : }
182 :
183 0 : bool SwUndo::IsDelBox() const
184 : {
185 0 : return GetId() == UNDO_COL_DELETE || GetId() == UNDO_ROW_DELETE ||
186 0 : GetId() == UNDO_TABLE_DELBOX;
187 : }
188 :
189 0 : SwUndo::~SwUndo()
190 : {
191 0 : delete pComment;
192 0 : }
193 :
194 : class UndoRedoRedlineGuard
195 : {
196 : public:
197 0 : UndoRedoRedlineGuard(::sw::UndoRedoContext & rContext, SwUndo & rUndo)
198 0 : : m_rRedlineAccess(rContext.GetDoc())
199 0 : , m_eMode(m_rRedlineAccess.GetRedlineMode())
200 : {
201 : RedlineMode_t const eTmpMode =
202 0 : static_cast<RedlineMode_t>(rUndo.GetRedlineMode());
203 0 : if ((nsRedlineMode_t::REDLINE_SHOW_MASK & eTmpMode) !=
204 : (nsRedlineMode_t::REDLINE_SHOW_MASK & m_eMode))
205 : {
206 0 : m_rRedlineAccess.SetRedlineMode( eTmpMode );
207 : }
208 : m_rRedlineAccess.SetRedlineMode_intern( static_cast<RedlineMode_t>(
209 0 : eTmpMode | nsRedlineMode_t::REDLINE_IGNORE) );
210 0 : }
211 0 : ~UndoRedoRedlineGuard()
212 : {
213 0 : m_rRedlineAccess.SetRedlineMode(m_eMode);
214 0 : }
215 : private:
216 : IDocumentRedlineAccess & m_rRedlineAccess;
217 : RedlineMode_t const m_eMode;
218 : };
219 :
220 0 : void SwUndo::Undo()
221 : {
222 : assert(false); // SwUndo::Undo(): ERROR: must call UndoWithContext instead
223 0 : }
224 :
225 0 : void SwUndo::Redo()
226 : {
227 : assert(false); // SwUndo::Redo(): ERROR: must call RedoWithContext instead
228 0 : }
229 :
230 0 : void SwUndo::UndoWithContext(SfxUndoContext & rContext)
231 : {
232 : ::sw::UndoRedoContext *const pContext(
233 0 : dynamic_cast< ::sw::UndoRedoContext * >(& rContext));
234 : assert(pContext);
235 0 : if (!pContext) { return; }
236 0 : const UndoRedoRedlineGuard aUndoRedoRedlineGuard(*pContext, *this);
237 0 : UndoImpl(*pContext);
238 : }
239 :
240 0 : void SwUndo::RedoWithContext(SfxUndoContext & rContext)
241 : {
242 : ::sw::UndoRedoContext *const pContext(
243 0 : dynamic_cast< ::sw::UndoRedoContext * >(& rContext));
244 : assert(pContext);
245 0 : if (!pContext) { return; }
246 0 : const UndoRedoRedlineGuard aUndoRedoRedlineGuard(*pContext, *this);
247 0 : RedoImpl(*pContext);
248 : }
249 :
250 0 : void SwUndo::Repeat(SfxRepeatTarget & rContext)
251 : {
252 : ::sw::RepeatContext *const pRepeatContext(
253 0 : dynamic_cast< ::sw::RepeatContext * >(& rContext));
254 : assert(pRepeatContext);
255 0 : if (!pRepeatContext) { return; }
256 0 : RepeatImpl(*pRepeatContext);
257 : }
258 :
259 0 : bool SwUndo::CanRepeat(SfxRepeatTarget & rContext) const
260 : {
261 : ::sw::RepeatContext *const pRepeatContext(
262 0 : dynamic_cast< ::sw::RepeatContext * >(& rContext));
263 : assert(pRepeatContext);
264 0 : if (!pRepeatContext) { return false; }
265 0 : return CanRepeatImpl(*pRepeatContext);
266 : }
267 :
268 0 : void SwUndo::RepeatImpl( ::sw::RepeatContext & )
269 : {
270 0 : }
271 :
272 0 : bool SwUndo::CanRepeatImpl( ::sw::RepeatContext & ) const
273 : {
274 0 : return ((REPEAT_START <= GetId()) && (GetId() < REPEAT_END));
275 : }
276 :
277 0 : OUString SwUndo::GetComment() const
278 : {
279 0 : OUString aResult;
280 :
281 0 : if (bCacheComment)
282 : {
283 0 : if (! pComment)
284 : {
285 0 : pComment = new OUString(SW_RES(UNDO_BASE + GetId()));
286 :
287 0 : SwRewriter aRewriter = GetRewriter();
288 :
289 0 : *pComment = aRewriter.Apply(*pComment);
290 : }
291 :
292 0 : aResult = *pComment;
293 : }
294 : else
295 : {
296 0 : aResult = SW_RES(UNDO_BASE + GetId());
297 :
298 0 : SwRewriter aRewriter = GetRewriter();
299 :
300 0 : aResult = aRewriter.Apply(aResult);
301 : }
302 :
303 0 : return aResult;
304 : }
305 :
306 0 : SwRewriter SwUndo::GetRewriter() const
307 : {
308 0 : SwRewriter aResult;
309 :
310 0 : return aResult;
311 : }
312 :
313 0 : SwUndoSaveCntnt::SwUndoSaveCntnt()
314 0 : : pHistory( 0 )
315 0 : {}
316 :
317 0 : SwUndoSaveCntnt::~SwUndoSaveCntnt()
318 : {
319 0 : delete pHistory;
320 0 : }
321 :
322 : // This is needed when deleting content. For REDO all contents will be moved
323 : // into the UndoNodesArray. These methods always create a new node to insert
324 : // content. As a result, the attributes will not be expanded.
325 : // - MoveTo moves from NodesArray into UndoNodesArray
326 : // - MoveFrom moves from UndoNodesArray into NodesArray
327 :
328 : // If pEndNdIdx is given, Undo/Redo calls -Ins/DelFly. In that case the whole
329 : // section should be moved.
330 0 : void SwUndoSaveCntnt::MoveToUndoNds( SwPaM& rPaM, SwNodeIndex* pNodeIdx,
331 : sal_uLong* pEndNdIdx, sal_Int32* pEndCntIdx )
332 : {
333 0 : SwDoc& rDoc = *rPaM.GetDoc();
334 0 : ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
335 :
336 0 : SwNoTxtNode* pCpyNd = rPaM.GetNode()->GetNoTxtNode();
337 :
338 : // here comes the actual delete (move)
339 0 : SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes();
340 : SwPosition aPos( pEndNdIdx ? rNds.GetEndOfPostIts()
341 0 : : rNds.GetEndOfExtras() );
342 :
343 0 : const SwPosition* pStt = rPaM.Start(), *pEnd = rPaM.End();
344 :
345 : // keep as sal_uInt16; the indices shift!
346 0 : sal_uLong nTmpMvNode = aPos.nNode.GetIndex();
347 :
348 0 : if( pCpyNd || pEndNdIdx )
349 : {
350 0 : SwNodeRange aRg( pStt->nNode, 0, pEnd->nNode, 1 );
351 0 : rDoc.GetNodes()._MoveNodes( aRg, rNds, aPos.nNode, sal_False );
352 0 : aPos.nContent = 0;
353 0 : aPos.nNode--;
354 : }
355 : else
356 : {
357 0 : rDoc.GetNodes().MoveRange( rPaM, aPos, rNds );
358 : }
359 0 : if( pEndNdIdx )
360 0 : *pEndNdIdx = aPos.nNode.GetIndex();
361 0 : if( pEndCntIdx )
362 0 : *pEndCntIdx = aPos.nContent.GetIndex();
363 :
364 : // old position
365 0 : aPos.nNode = nTmpMvNode;
366 0 : if( pNodeIdx )
367 0 : *pNodeIdx = aPos.nNode;
368 0 : }
369 :
370 0 : void SwUndoSaveCntnt::MoveFromUndoNds( SwDoc& rDoc, sal_uLong nNodeIdx,
371 : SwPosition& rInsPos,
372 : sal_uLong* pEndNdIdx, sal_Int32* pEndCntIdx )
373 : {
374 : // here comes the recovery
375 0 : SwNodes & rNds = rDoc.GetUndoManager().GetUndoNodes();
376 0 : if( nNodeIdx == rNds.GetEndOfPostIts().GetIndex() )
377 0 : return; // nothing saved
378 :
379 0 : ::sw::UndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
380 :
381 0 : SwPaM aPaM( rInsPos );
382 0 : if( pEndNdIdx ) // than get the section from it
383 0 : aPaM.GetPoint()->nNode.Assign( rNds, *pEndNdIdx );
384 : else
385 : {
386 0 : aPaM.GetPoint()->nNode = rNds.GetEndOfExtras();
387 0 : GoInCntnt( aPaM, fnMoveBackward );
388 : }
389 :
390 0 : SwTxtNode* pTxtNd = aPaM.GetNode()->GetTxtNode();
391 0 : if (!pEndNdIdx && pTxtNd)
392 : {
393 0 : if( pEndCntIdx )
394 0 : aPaM.GetPoint()->nContent.Assign( pTxtNd, *pEndCntIdx );
395 :
396 0 : aPaM.SetMark();
397 0 : aPaM.GetPoint()->nNode = nNodeIdx;
398 0 : aPaM.GetPoint()->nContent.Assign(aPaM.GetCntntNode(), 0);
399 :
400 0 : _SaveRedlEndPosForRestore aRedlRest( rInsPos.nNode, rInsPos.nContent.GetIndex() );
401 :
402 0 : rNds.MoveRange( aPaM, rInsPos, rDoc.GetNodes() );
403 :
404 : // delete the last Node as well
405 0 : if( !aPaM.GetPoint()->nContent.GetIndex() ||
406 0 : ( aPaM.GetPoint()->nNode++ && // still empty Nodes at the end?
407 0 : &rNds.GetEndOfExtras() != &aPaM.GetPoint()->nNode.GetNode() ))
408 : {
409 0 : aPaM.GetPoint()->nContent.Assign( 0, 0 );
410 0 : aPaM.SetMark();
411 0 : rNds.Delete( aPaM.GetPoint()->nNode,
412 0 : rNds.GetEndOfExtras().GetIndex() -
413 0 : aPaM.GetPoint()->nNode.GetIndex() );
414 : }
415 :
416 0 : aRedlRest.Restore();
417 : }
418 0 : else if( pEndNdIdx || !pTxtNd )
419 : {
420 : SwNodeRange aRg( rNds, nNodeIdx, rNds, (pEndNdIdx
421 0 : ? ((*pEndNdIdx) + 1)
422 0 : : rNds.GetEndOfExtras().GetIndex() ) );
423 0 : rNds._MoveNodes( aRg, rDoc.GetNodes(), rInsPos.nNode, 0 == pEndNdIdx );
424 :
425 : }
426 : else {
427 : assert(false); // wtf?
428 0 : }
429 : }
430 :
431 : // These two methods move the Point of Pam backwards/forwards. With that, one
432 : // can span an area for a Undo/Redo. (The Point is then positioned in front of
433 : // the area to manipulate!)
434 : // The flag indicates if there is still content in front of Point.
435 0 : bool SwUndoSaveCntnt::MovePtBackward( SwPaM& rPam )
436 : {
437 0 : rPam.SetMark();
438 0 : if( rPam.Move( fnMoveBackward ))
439 0 : return true;
440 :
441 : // If there is no content onwards, set Point simply to the previous position
442 : // (Node and Content, so that Content will be detached!)
443 0 : rPam.GetPoint()->nNode--;
444 0 : rPam.GetPoint()->nContent.Assign( 0, 0 );
445 0 : return false;
446 : }
447 :
448 0 : void SwUndoSaveCntnt::MovePtForward( SwPaM& rPam, bool bMvBkwrd )
449 : {
450 : // Was there content before this position?
451 0 : if( bMvBkwrd )
452 0 : rPam.Move( fnMoveForward );
453 : else
454 : {
455 0 : rPam.GetPoint()->nNode++;
456 0 : SwCntntNode* pCNd = rPam.GetCntntNode();
457 0 : if( pCNd )
458 0 : pCNd->MakeStartIndex( &rPam.GetPoint()->nContent );
459 : else
460 0 : rPam.Move( fnMoveForward );
461 : }
462 0 : }
463 :
464 : // Delete all objects that have ContentIndices to the given area.
465 : // Currently (1994) these exist:
466 : // - Footnotes
467 : // - Flys
468 : // - Bookmarks
469 : // - Directories
470 :
471 : // #i81002# - extending method
472 : // delete certain (not all) cross-reference bookmarks at text node of <rMark>
473 : // and at text node of <rPoint>, if these text nodes aren't the same.
474 0 : void SwUndoSaveCntnt::DelCntntIndex( const SwPosition& rMark,
475 : const SwPosition& rPoint,
476 : DelCntntType nDelCntntType )
477 : {
478 0 : const SwPosition *pStt = rMark < rPoint ? &rMark : &rPoint,
479 0 : *pEnd = &rMark == pStt ? &rPoint : &rMark;
480 :
481 0 : SwDoc* pDoc = rMark.nNode.GetNode().GetDoc();
482 :
483 0 : ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
484 :
485 : // 1. Footnotes
486 0 : if( nsDelCntntType::DELCNT_FTN & nDelCntntType )
487 : {
488 0 : SwFtnIdxs& rFtnArr = pDoc->GetFtnIdxs();
489 0 : if( !rFtnArr.empty() )
490 : {
491 : const SwNode* pFtnNd;
492 : sal_uInt16 nPos;
493 0 : rFtnArr.SeekEntry( pStt->nNode, &nPos );
494 : SwTxtFtn* pSrch;
495 :
496 : // for now delete all that come afterwards
497 0 : while( nPos < rFtnArr.size() && ( pFtnNd =
498 0 : &( pSrch = rFtnArr[ nPos ] )->GetTxtNode())->GetIndex()
499 0 : <= pEnd->nNode.GetIndex() )
500 : {
501 0 : const sal_Int32 nFtnSttIdx = *pSrch->GetStart();
502 0 : if( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType )
503 0 : ? (&pEnd->nNode.GetNode() == pFtnNd )
504 0 : : (( &pStt->nNode.GetNode() == pFtnNd &&
505 0 : pStt->nContent.GetIndex() > nFtnSttIdx) ||
506 0 : ( &pEnd->nNode.GetNode() == pFtnNd &&
507 0 : nFtnSttIdx >= pEnd->nContent.GetIndex() )) )
508 : {
509 0 : ++nPos; // continue searching
510 0 : continue;
511 : }
512 :
513 : // FIXME: duplicated code here and below -> refactor?
514 : // Unfortunately an index needs to be created. Otherwise there
515 : // will be problems with TextNode because the index will be
516 : // deleted in the DTOR of SwFtn!
517 0 : SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd;
518 0 : if( !pHistory )
519 0 : pHistory = new SwHistory;
520 : SwTxtAttr* const pFtnHnt =
521 0 : pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx );
522 : assert(pFtnHnt);
523 0 : SwIndex aIdx( pTxtNd, nFtnSttIdx );
524 0 : pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false );
525 0 : pTxtNd->EraseText( aIdx, 1 );
526 0 : }
527 :
528 0 : while( nPos-- && ( pFtnNd = &( pSrch = rFtnArr[ nPos ] )->
529 0 : GetTxtNode())->GetIndex() >= pStt->nNode.GetIndex() )
530 : {
531 0 : const sal_Int32 nFtnSttIdx = *pSrch->GetStart();
532 0 : if( !(nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType) && (
533 0 : ( &pStt->nNode.GetNode() == pFtnNd &&
534 0 : pStt->nContent.GetIndex() > nFtnSttIdx ) ||
535 0 : ( &pEnd->nNode.GetNode() == pFtnNd &&
536 0 : nFtnSttIdx >= pEnd->nContent.GetIndex() )))
537 0 : continue; // continue searching
538 :
539 : // Unfortunately an index needs to be created. Otherwise there
540 : // will be problems with TextNode because the index will be
541 : // deleted in the DTOR of SwFtn!
542 0 : SwTxtNode* pTxtNd = (SwTxtNode*)pFtnNd;
543 0 : if( !pHistory )
544 0 : pHistory = new SwHistory;
545 : SwTxtAttr* const pFtnHnt =
546 0 : pTxtNd->GetTxtAttrForCharAt( nFtnSttIdx );
547 : assert(pFtnHnt);
548 0 : SwIndex aIdx( pTxtNd, nFtnSttIdx );
549 0 : pHistory->Add( pFtnHnt, pTxtNd->GetIndex(), false );
550 0 : pTxtNd->EraseText( aIdx, 1 );
551 0 : }
552 : }
553 : }
554 :
555 : // 2. Flys
556 0 : if( nsDelCntntType::DELCNT_FLY & nDelCntntType )
557 : {
558 0 : sal_uInt16 nChainInsPos = pHistory ? pHistory->Count() : 0;
559 0 : const SwFrmFmts& rSpzArr = *pDoc->GetSpzFrmFmts();
560 0 : if( !rSpzArr.empty() )
561 : {
562 0 : const bool bDelFwrd = rMark.nNode.GetIndex() <= rPoint.nNode.GetIndex();
563 : SwFlyFrmFmt* pFmt;
564 : const SwFmtAnchor* pAnchor;
565 0 : size_t n = rSpzArr.size();
566 : const SwPosition* pAPos;
567 :
568 0 : while( n && !rSpzArr.empty() )
569 : {
570 0 : pFmt = (SwFlyFrmFmt*)rSpzArr[--n];
571 0 : pAnchor = &pFmt->GetAnchor();
572 0 : switch( pAnchor->GetAnchorId() )
573 : {
574 : case FLY_AS_CHAR:
575 0 : if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) &&
576 0 : (( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType )
577 0 : ? ( pStt->nNode <= pAPos->nNode &&
578 0 : pAPos->nNode < pEnd->nNode )
579 0 : : ( *pStt <= *pAPos && *pAPos < *pEnd )) )
580 : {
581 0 : if( !pHistory )
582 0 : pHistory = new SwHistory;
583 : SwTxtNode *const pTxtNd =
584 0 : pAPos->nNode.GetNode().GetTxtNode();
585 : SwTxtAttr* const pFlyHnt = pTxtNd->GetTxtAttrForCharAt(
586 0 : pAPos->nContent.GetIndex());
587 : assert(pFlyHnt);
588 0 : pHistory->Add( pFlyHnt, 0, false );
589 : // reset n so that no Format is skipped
590 0 : n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
591 : }
592 0 : break;
593 : case FLY_AT_PARA:
594 : {
595 0 : pAPos = pAnchor->GetCntntAnchor();
596 0 : if( pAPos )
597 : {
598 : bool bTmp;
599 0 : if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType )
600 0 : bTmp = pStt->nNode <= pAPos->nNode && pAPos->nNode < pEnd->nNode;
601 : else
602 : {
603 0 : if (bDelFwrd)
604 0 : bTmp = rMark.nNode < pAPos->nNode &&
605 0 : pAPos->nNode <= rPoint.nNode;
606 : else
607 0 : bTmp = rPoint.nNode <= pAPos->nNode &&
608 0 : pAPos->nNode < rMark.nNode;
609 : }
610 :
611 0 : if (bTmp)
612 : {
613 0 : if( !pHistory )
614 0 : pHistory = new SwHistory;
615 :
616 : // Moving the anchor?
617 0 : if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) &&
618 0 : ( rPoint.nNode.GetIndex() == pAPos->nNode.GetIndex() ) )
619 : {
620 : // Do not try to move the anchor to a table!
621 0 : if( rMark.nNode.GetNode().GetTxtNode() )
622 : {
623 0 : pHistory->Add( *pFmt );
624 0 : SwFmtAnchor aAnch( *pAnchor );
625 0 : SwPosition aPos( rMark.nNode );
626 0 : aAnch.SetAnchor( &aPos );
627 0 : pFmt->SetFmtAttr( aAnch );
628 : }
629 : }
630 : else
631 : {
632 0 : pHistory->Add( *pFmt, nChainInsPos );
633 : // reset n so that no Format is skipped
634 0 : n = n >= rSpzArr.size() ?
635 0 : rSpzArr.size() : n+1;
636 : }
637 : }
638 : }
639 : }
640 0 : break;
641 : case FLY_AT_CHAR:
642 0 : if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) &&
643 0 : ( pStt->nNode <= pAPos->nNode && pAPos->nNode <= pEnd->nNode ) )
644 : {
645 0 : if( !pHistory )
646 0 : pHistory = new SwHistory;
647 0 : if (IsDestroyFrameAnchoredAtChar(
648 0 : *pAPos, *pStt, *pEnd, nDelCntntType))
649 : {
650 0 : pHistory->Add( *pFmt, nChainInsPos );
651 0 : n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
652 : }
653 0 : else if( !( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType ) )
654 : {
655 0 : if( *pStt <= *pAPos && *pAPos < *pEnd )
656 : {
657 : // These are the objects anchored
658 : // between section start and end position
659 : // Do not try to move the anchor to a table!
660 0 : if( rMark.nNode.GetNode().GetTxtNode() )
661 : {
662 0 : pHistory->Add( *pFmt );
663 0 : SwFmtAnchor aAnch( *pAnchor );
664 0 : aAnch.SetAnchor( &rMark );
665 0 : pFmt->SetFmtAttr( aAnch );
666 : }
667 : }
668 : }
669 : }
670 0 : break;
671 : case FLY_AT_FLY:
672 :
673 0 : if( 0 != (pAPos = pAnchor->GetCntntAnchor() ) &&
674 0 : pStt->nNode == pAPos->nNode )
675 : {
676 0 : if( !pHistory )
677 0 : pHistory = new SwHistory;
678 :
679 0 : pHistory->Add( *pFmt, nChainInsPos );
680 :
681 : // reset n so that no Format is skipped
682 0 : n = n >= rSpzArr.size() ? rSpzArr.size() : n+1;
683 : }
684 0 : break;
685 0 : default: break;
686 : }
687 : }
688 : }
689 : }
690 :
691 : // 3. Bookmarks
692 0 : if( nsDelCntntType::DELCNT_BKM & nDelCntntType )
693 : {
694 0 : IDocumentMarkAccess* const pMarkAccess = pDoc->getIDocumentMarkAccess();
695 0 : if( pMarkAccess->getAllMarksCount() )
696 : {
697 :
698 0 : for( sal_uInt16 n = 0; n < pMarkAccess->getAllMarksCount(); ++n )
699 : {
700 : // #i81002#
701 0 : bool bSavePos = false;
702 0 : bool bSaveOtherPos = false;
703 0 : const ::sw::mark::IMark* pBkmk = (pMarkAccess->getAllMarksBegin() + n)->get();
704 :
705 0 : if( nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType )
706 : {
707 0 : if ( pStt->nNode <= pBkmk->GetMarkPos().nNode
708 0 : && pBkmk->GetMarkPos().nNode < pEnd->nNode )
709 : {
710 0 : bSavePos = true;
711 : }
712 0 : if ( pBkmk->IsExpanded()
713 0 : && pStt->nNode <= pBkmk->GetOtherMarkPos().nNode
714 0 : && pBkmk->GetOtherMarkPos().nNode < pEnd->nNode )
715 : {
716 0 : bSaveOtherPos = true;
717 : }
718 : }
719 : else
720 : {
721 : // #i92125#
722 : // keep cross-reference bookmarks, if content inside one paragraph is deleted.
723 0 : if ( rMark.nNode == rPoint.nNode
724 0 : && ( IDocumentMarkAccess::GetType(*pBkmk) == IDocumentMarkAccess::CROSSREF_HEADING_BOOKMARK
725 0 : || IDocumentMarkAccess::GetType(*pBkmk) == IDocumentMarkAccess::CROSSREF_NUMITEM_BOOKMARK ) )
726 : {
727 0 : continue;
728 : }
729 :
730 0 : bool bMaybe = false;
731 0 : if ( *pStt <= pBkmk->GetMarkPos() && pBkmk->GetMarkPos() <= *pEnd )
732 : {
733 0 : if ( pBkmk->GetMarkPos() == *pEnd
734 0 : || ( *pStt == pBkmk->GetMarkPos() && pBkmk->IsExpanded() ) )
735 0 : bMaybe = true;
736 : else
737 0 : bSavePos = true;
738 : }
739 0 : if( pBkmk->IsExpanded() &&
740 0 : *pStt <= pBkmk->GetOtherMarkPos() && pBkmk->GetOtherMarkPos() <= *pEnd )
741 : {
742 0 : if ( bSavePos || bSaveOtherPos
743 0 : || ( pBkmk->GetOtherMarkPos() < *pEnd && pBkmk->GetOtherMarkPos() > *pStt ) )
744 : {
745 0 : if( bMaybe )
746 0 : bSavePos = true;
747 0 : bSaveOtherPos = true;
748 : }
749 : }
750 :
751 0 : if ( !bSavePos && !bSaveOtherPos
752 0 : && dynamic_cast< const ::sw::mark::CrossRefBookmark* >(pBkmk) )
753 : {
754 : // certain special handling for cross-reference bookmarks
755 : const bool bDifferentTxtNodesAtMarkAndPoint =
756 0 : rMark.nNode != rPoint.nNode
757 0 : && rMark.nNode.GetNode().GetTxtNode()
758 0 : && rPoint.nNode.GetNode().GetTxtNode();
759 0 : if ( bDifferentTxtNodesAtMarkAndPoint )
760 : {
761 : // delete cross-reference bookmark at <pStt>, if only part of
762 : // <pEnd> text node content is deleted.
763 0 : if( pStt->nNode == pBkmk->GetMarkPos().nNode
764 0 : && pEnd->nContent.GetIndex() != pEnd->nNode.GetNode().GetTxtNode()->Len() )
765 : {
766 0 : bSavePos = true;
767 0 : bSaveOtherPos = false; // cross-reference bookmarks are not expanded
768 : }
769 : // delete cross-reference bookmark at <pEnd>, if only part of
770 : // <pStt> text node content is deleted.
771 0 : else if( pEnd->nNode == pBkmk->GetMarkPos().nNode &&
772 0 : pStt->nContent.GetIndex() != 0 )
773 : {
774 0 : bSavePos = true;
775 0 : bSaveOtherPos = false; // cross-reference bookmarks are not expanded
776 : }
777 : }
778 : }
779 0 : else if ( IDocumentMarkAccess::GetType(*pBkmk) == IDocumentMarkAccess::ANNOTATIONMARK )
780 : {
781 : // delete annotation marks, if its end position is covered by the deletion
782 0 : const SwPosition& rAnnotationEndPos = pBkmk->GetMarkEnd();
783 0 : if ( *pStt < rAnnotationEndPos && rAnnotationEndPos <= *pEnd )
784 : {
785 0 : bSavePos = true;
786 0 : bSaveOtherPos = true;
787 : }
788 : }
789 : }
790 :
791 0 : if ( bSavePos || bSaveOtherPos )
792 : {
793 0 : if( !pHistory )
794 0 : pHistory = new SwHistory;
795 :
796 0 : pHistory->Add( *pBkmk, bSavePos, bSaveOtherPos );
797 0 : if ( bSavePos
798 0 : && ( bSaveOtherPos
799 0 : || !pBkmk->IsExpanded() ) )
800 : {
801 0 : pMarkAccess->deleteMark(pMarkAccess->getAllMarksBegin()+n);
802 0 : n--;
803 : }
804 : }
805 : }
806 : }
807 0 : }
808 0 : }
809 :
810 : // save a complete section into UndoNodes array
811 0 : SwUndoSaveSection::SwUndoSaveSection()
812 0 : : pMvStt( 0 ), pRedlSaveData( 0 ), nMvLen( 0 ), nStartPos( ULONG_MAX )
813 : {
814 0 : }
815 :
816 0 : SwUndoSaveSection::~SwUndoSaveSection()
817 : {
818 0 : if( pMvStt ) // delete also the section from UndoNodes array
819 : {
820 : // SaveSection saves the content in the PostIt section.
821 0 : SwNodes& rUNds = pMvStt->GetNode().GetNodes();
822 0 : rUNds.Delete( *pMvStt, nMvLen );
823 :
824 0 : delete pMvStt;
825 : }
826 0 : delete pRedlSaveData;
827 0 : }
828 :
829 0 : void SwUndoSaveSection::SaveSection( SwDoc* pDoc, const SwNodeIndex& rSttIdx )
830 : {
831 0 : SwNodeRange aRg( rSttIdx.GetNode(), *rSttIdx.GetNode().EndOfSectionNode() );
832 0 : SaveSection( pDoc, aRg );
833 0 : }
834 :
835 0 : void SwUndoSaveSection::SaveSection(
836 : SwDoc* pDoc,
837 : const SwNodeRange& rRange )
838 : {
839 0 : SwPaM aPam( rRange.aStart, rRange.aEnd );
840 :
841 : // delete all footnotes, fly frames, bookmarks and indexes
842 0 : DelCntntIndex( *aPam.GetMark(), *aPam.GetPoint() );
843 : {
844 : // move certain indexes out of deleted range
845 0 : SwNodeIndex aSttIdx( aPam.Start()->nNode.GetNode() );
846 0 : SwNodeIndex aEndIdx( aPam.End()->nNode.GetNode() );
847 0 : SwNodeIndex aMvStt( aEndIdx, 1 );
848 0 : pDoc->CorrAbs( aSttIdx, aEndIdx, SwPosition( aMvStt ), sal_True );
849 : }
850 :
851 0 : pRedlSaveData = new SwRedlineSaveDatas;
852 0 : if( !SwUndo::FillSaveData( aPam, *pRedlSaveData, true, true ))
853 0 : delete pRedlSaveData, pRedlSaveData = 0;
854 :
855 0 : nStartPos = rRange.aStart.GetIndex();
856 :
857 0 : aPam.GetPoint()->nNode--;
858 0 : aPam.GetMark()->nNode++;
859 :
860 0 : SwCntntNode* pCNd = aPam.GetCntntNode( false );
861 0 : if( pCNd )
862 0 : aPam.GetMark()->nContent.Assign( pCNd, 0 );
863 0 : if( 0 != ( pCNd = aPam.GetCntntNode( true )) )
864 0 : aPam.GetPoint()->nContent.Assign( pCNd, pCNd->Len() );
865 :
866 : // Keep positions as SwIndex so that this section can be deleted in DTOR
867 : sal_uLong nEnd;
868 0 : pMvStt = new SwNodeIndex( rRange.aStart );
869 0 : MoveToUndoNds(aPam, pMvStt, &nEnd, 0);
870 0 : nMvLen = nEnd - pMvStt->GetIndex() + 1;
871 0 : }
872 :
873 0 : void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, SwNodeIndex* pIdx,
874 : sal_uInt16 nSectType )
875 : {
876 0 : if( ULONG_MAX != nStartPos ) // was there any content?
877 : {
878 : // check if the content is at the old position
879 0 : SwNodeIndex aSttIdx( pDoc->GetNodes(), nStartPos );
880 :
881 : // move the content from UndoNodes array into Fly
882 0 : SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection( aSttIdx,
883 0 : (SwStartNodeType)nSectType );
884 :
885 0 : RestoreSection( pDoc, SwNodeIndex( *pSttNd->EndOfSectionNode() ));
886 :
887 0 : if( pIdx )
888 0 : *pIdx = *pSttNd;
889 : }
890 0 : }
891 :
892 0 : void SwUndoSaveSection::RestoreSection( SwDoc* pDoc, const SwNodeIndex& rInsPos )
893 : {
894 0 : if( ULONG_MAX != nStartPos ) // was there any content?
895 : {
896 0 : SwPosition aInsPos( rInsPos );
897 0 : sal_uLong nEnd = pMvStt->GetIndex() + nMvLen - 1;
898 0 : MoveFromUndoNds(*pDoc, pMvStt->GetIndex(), aInsPos, &nEnd, 0);
899 :
900 : // destroy indices again, content was deleted from UndoNodes array
901 0 : DELETEZ( pMvStt );
902 0 : nMvLen = 0;
903 :
904 0 : if( pRedlSaveData )
905 : {
906 0 : SwUndo::SetSaveData( *pDoc, *pRedlSaveData );
907 0 : delete pRedlSaveData, pRedlSaveData = 0;
908 0 : }
909 : }
910 0 : }
911 :
912 : // save and set the RedlineData
913 0 : SwRedlineSaveData::SwRedlineSaveData(
914 : SwComparePosition eCmpPos,
915 : const SwPosition& rSttPos,
916 : const SwPosition& rEndPos,
917 : SwRangeRedline& rRedl,
918 : sal_Bool bCopyNext )
919 : : SwUndRng( rRedl )
920 0 : , SwRedlineData( rRedl.GetRedlineData(), bCopyNext )
921 : {
922 : assert( POS_OUTSIDE == eCmpPos ||
923 : !rRedl.GetContentIdx() ); // "Redline with Content"
924 :
925 0 : switch (eCmpPos)
926 : {
927 : case POS_OVERLAP_BEFORE: // Pos1 overlaps Pos2 at the beginning
928 0 : nEndNode = rEndPos.nNode.GetIndex();
929 0 : nEndCntnt = rEndPos.nContent.GetIndex();
930 0 : break;
931 :
932 : case POS_OVERLAP_BEHIND: // Pos1 overlaps Pos2 at the end
933 0 : nSttNode = rSttPos.nNode.GetIndex();
934 0 : nSttCntnt = rSttPos.nContent.GetIndex();
935 0 : break;
936 :
937 : case POS_INSIDE: // Pos1 lays completely in Pos2
938 0 : nSttNode = rSttPos.nNode.GetIndex();
939 0 : nSttCntnt = rSttPos.nContent.GetIndex();
940 0 : nEndNode = rEndPos.nNode.GetIndex();
941 0 : nEndCntnt = rEndPos.nContent.GetIndex();
942 0 : break;
943 :
944 : case POS_OUTSIDE: // Pos2 lays completely in Pos1
945 0 : if ( rRedl.GetContentIdx() )
946 : {
947 : // than move section into UndoArray and memorize it
948 0 : SaveSection( rRedl.GetDoc(), *rRedl.GetContentIdx() );
949 0 : rRedl.SetContentIdx( 0 );
950 : }
951 0 : break;
952 :
953 : case POS_EQUAL: // Pos1 ist exactly as big as Pos2
954 0 : break;
955 :
956 : default:
957 : assert(false);
958 : }
959 :
960 : #if OSL_DEBUG_LEVEL > 0
961 : nRedlineCount = rSttPos.nNode.GetNode().GetDoc()->GetRedlineTbl().size();
962 : #endif
963 0 : }
964 :
965 0 : SwRedlineSaveData::~SwRedlineSaveData()
966 : {
967 0 : }
968 :
969 0 : void SwRedlineSaveData::RedlineToDoc( SwPaM& rPam )
970 : {
971 0 : SwDoc& rDoc = *rPam.GetDoc();
972 0 : SwRangeRedline* pRedl = new SwRangeRedline( *this, rPam );
973 :
974 0 : if( GetMvSttIdx() )
975 : {
976 0 : SwNodeIndex aIdx( rDoc.GetNodes() );
977 0 : RestoreSection( &rDoc, &aIdx, SwNormalStartNode );
978 0 : if( GetHistory() )
979 0 : GetHistory()->Rollback( &rDoc );
980 0 : pRedl->SetContentIdx( &aIdx );
981 : }
982 0 : SetPaM( *pRedl );
983 : // First, delete the "old" so that in an Append no unexpected things will
984 : // happen, e.g. a delete in an insert. In the latter case the just restored
985 : // content will be deleted and not the one you originally wanted.
986 0 : rDoc.DeleteRedline( *pRedl, false, USHRT_MAX );
987 :
988 0 : RedlineMode_t eOld = rDoc.GetRedlineMode();
989 0 : rDoc.SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_DONTCOMBINE_REDLINES));
990 : //#i92154# let UI know about a new redline with comment
991 0 : if (rDoc.GetDocShell() && (!pRedl->GetComment().isEmpty()) )
992 0 : rDoc.GetDocShell()->Broadcast(SwRedlineHint(pRedl,SWREDLINE_INSERTED));
993 :
994 0 : bool const bSuccess = rDoc.AppendRedline( pRedl, true );
995 : assert(bSuccess); // SwRedlineSaveData::RedlineToDoc: insert redline failed
996 : (void) bSuccess; // unused in non-debug
997 0 : rDoc.SetRedlineMode_intern( eOld );
998 0 : }
999 :
1000 0 : bool SwUndo::FillSaveData(
1001 : const SwPaM& rRange,
1002 : SwRedlineSaveDatas& rSData,
1003 : bool bDelRange,
1004 : bool bCopyNext )
1005 : {
1006 0 : rSData.DeleteAndDestroyAll();
1007 :
1008 : SwRedlineSaveData* pNewData;
1009 0 : const SwPosition* pStt = rRange.Start();
1010 0 : const SwPosition* pEnd = rRange.End();
1011 0 : const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl();
1012 0 : sal_uInt16 n = 0;
1013 0 : rRange.GetDoc()->GetRedline( *pStt, &n );
1014 0 : for ( ; n < rTbl.size(); ++n )
1015 : {
1016 0 : SwRangeRedline* pRedl = rTbl[n];
1017 :
1018 : const SwComparePosition eCmpPos =
1019 0 : ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() );
1020 0 : if ( eCmpPos != POS_BEFORE
1021 0 : && eCmpPos != POS_BEHIND
1022 0 : && eCmpPos != POS_COLLIDE_END
1023 0 : && eCmpPos != POS_COLLIDE_START )
1024 : {
1025 0 : pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, *pRedl, bCopyNext );
1026 0 : rSData.push_back( pNewData );
1027 : }
1028 : }
1029 0 : if( !rSData.empty() && bDelRange )
1030 : {
1031 0 : rRange.GetDoc()->DeleteRedline( rRange, false, USHRT_MAX );
1032 : }
1033 0 : return !rSData.empty();
1034 : }
1035 :
1036 0 : bool SwUndo::FillSaveDataForFmt(
1037 : const SwPaM& rRange,
1038 : SwRedlineSaveDatas& rSData )
1039 : {
1040 0 : rSData.DeleteAndDestroyAll();
1041 :
1042 : SwRedlineSaveData* pNewData;
1043 0 : const SwPosition *pStt = rRange.Start(), *pEnd = rRange.End();
1044 0 : const SwRedlineTbl& rTbl = rRange.GetDoc()->GetRedlineTbl();
1045 0 : sal_uInt16 n = 0;
1046 0 : rRange.GetDoc()->GetRedline( *pStt, &n );
1047 0 : for ( ; n < rTbl.size(); ++n )
1048 : {
1049 0 : SwRangeRedline* pRedl = rTbl[n];
1050 0 : if ( nsRedlineType_t::REDLINE_FORMAT == pRedl->GetType() )
1051 : {
1052 0 : const SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRedl->Start(), *pRedl->End() );
1053 0 : if ( eCmpPos != POS_BEFORE
1054 0 : && eCmpPos != POS_BEHIND
1055 0 : && eCmpPos != POS_COLLIDE_END
1056 0 : && eCmpPos != POS_COLLIDE_START )
1057 : {
1058 0 : pNewData = new SwRedlineSaveData( eCmpPos, *pStt, *pEnd, *pRedl, true );
1059 0 : rSData.push_back( pNewData );
1060 : }
1061 :
1062 : }
1063 : }
1064 0 : return !rSData.empty();
1065 : }
1066 :
1067 :
1068 0 : void SwUndo::SetSaveData( SwDoc& rDoc, const SwRedlineSaveDatas& rSData )
1069 : {
1070 0 : RedlineMode_t eOld = rDoc.GetRedlineMode();
1071 0 : rDoc.SetRedlineMode_intern( (RedlineMode_t)(( eOld & ~nsRedlineMode_t::REDLINE_IGNORE) | nsRedlineMode_t::REDLINE_ON ));
1072 0 : SwPaM aPam( rDoc.GetNodes().GetEndOfContent() );
1073 :
1074 0 : for( size_t n = rSData.size(); n; )
1075 0 : rSData[ --n ]->RedlineToDoc( aPam );
1076 :
1077 : #if OSL_DEBUG_LEVEL > 0
1078 : // check redline count against count saved in RedlineSaveData object
1079 : assert(rSData.empty() ||
1080 : (rSData[0]->nRedlineCount == rDoc.GetRedlineTbl().size()));
1081 : // "redline count not restored properly"
1082 : #endif
1083 :
1084 0 : rDoc.SetRedlineMode_intern( eOld );
1085 0 : }
1086 :
1087 0 : bool SwUndo::HasHiddenRedlines( const SwRedlineSaveDatas& rSData )
1088 : {
1089 0 : for( size_t n = rSData.size(); n; )
1090 0 : if( rSData[ --n ]->GetMvSttIdx() )
1091 0 : return true;
1092 0 : return false;
1093 : }
1094 :
1095 0 : bool SwUndo::CanRedlineGroup( SwRedlineSaveDatas& rCurr,
1096 : const SwRedlineSaveDatas& rCheck, bool bCurrIsEnd )
1097 : {
1098 0 : if( rCurr.size() != rCheck.size() )
1099 0 : return false;
1100 :
1101 0 : for( size_t n = 0; n < rCurr.size(); ++n )
1102 : {
1103 0 : const SwRedlineSaveData& rSet = *rCurr[ n ];
1104 0 : const SwRedlineSaveData& rGet = *rCheck[ n ];
1105 0 : if( rSet.nSttNode != rGet.nSttNode ||
1106 0 : rSet.GetMvSttIdx() || rGet.GetMvSttIdx() ||
1107 0 : ( bCurrIsEnd ? rSet.nSttCntnt != rGet.nEndCntnt
1108 0 : : rSet.nEndCntnt != rGet.nSttCntnt ) ||
1109 0 : !rGet.CanCombine( rSet ) )
1110 : {
1111 0 : return false;
1112 : }
1113 : }
1114 :
1115 0 : for( size_t n = 0; n < rCurr.size(); ++n )
1116 : {
1117 0 : SwRedlineSaveData& rSet = *rCurr[ n ];
1118 0 : const SwRedlineSaveData& rGet = *rCheck[ n ];
1119 0 : if( bCurrIsEnd )
1120 0 : rSet.nSttCntnt = rGet.nSttCntnt;
1121 : else
1122 0 : rSet.nEndCntnt = rGet.nEndCntnt;
1123 : }
1124 0 : return true;
1125 : }
1126 :
1127 : // #111827#
1128 0 : OUString ShortenString(const OUString & rStr, sal_Int32 nLength, const OUString & rFillStr)
1129 : {
1130 : assert(nLength - rFillStr.getLength() >= 2);
1131 :
1132 0 : if (rStr.getLength() <= nLength)
1133 0 : return rStr;
1134 :
1135 0 : nLength -= rFillStr.getLength();
1136 0 : if ( nLength < 2 )
1137 0 : nLength = 2;
1138 :
1139 0 : const sal_Int32 nFrontLen = nLength - nLength / 2;
1140 0 : const sal_Int32 nBackLen = nLength - nFrontLen;
1141 :
1142 : return rStr.copy(0, nFrontLen)
1143 0 : + rFillStr
1144 0 : + rStr.copy(rStr.getLength() - nBackLen);
1145 : }
1146 :
1147 0 : bool IsDestroyFrameAnchoredAtChar(SwPosition const & rAnchorPos,
1148 : SwPosition const & rStart, SwPosition const & rEnd,
1149 : DelCntntType const nDelCntntType)
1150 : {
1151 :
1152 : // Here we identified the objects to destroy:
1153 : // - anchored between start and end of the selection
1154 : // - anchored in start of the selection with "CheckNoContent"
1155 : // - anchored in start of sel. and the selection start at pos 0
1156 0 : return (rAnchorPos.nNode < rEnd.nNode)
1157 0 : && ( (nsDelCntntType::DELCNT_CHKNOCNTNT & nDelCntntType)
1158 0 : || (rStart.nNode < rAnchorPos.nNode)
1159 0 : || !rStart.nContent.GetIndex()
1160 0 : );
1161 : }
1162 :
1163 0 : void SwRedlineSaveDatas::DeleteAndDestroyAll()
1164 : {
1165 0 : for( const_iterator it = begin(); it != end(); ++it )
1166 0 : delete *it;
1167 0 : clear();
1168 0 : }
1169 :
1170 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|