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