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