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