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