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